RethinkDB: Javascript - How to deleted nested objects - javascript

I'm having a rather large amount of difficulty with trying to remove nested objects from my table, without accidentally deleting all my data in the process (happened three times now, thank god I made copies).
My Object:
{
"value1": thing,
"value2": thing,
"value3": thing,
"roles": {
"1": {
"name": "Dave",
"id": "1"
},
"2": {
"name": "Jeff",
"id": "2"
},
"3": {
"name": "Rick",
"id": "3"
},
"4": {
"name": "Red",
"id": "4"
}
}
}`
I've tried a number of rethink queries, but none have worked thus far. It should be noted that 1, 2, 3, & 4 are variables that can have any amount of numbers, and thus my query must reflect that.
Some attempted queries:
function removeRole(id, roleName) {
let role = `${roleName}`
return this.r.table('guilds').get(id).replace(function(s){
return s.without({roles : {[role] : { "name": role }}})
})
}
function removeRole(id, roleName) {
return this.r.table('guilds').getAll(id).filter(this.r.replace(this.r.row.without(roleName))).run()
}
function removeRole(id, roleName) {
return this.r.table('guilds').get(id)('roles')(roleName).delete()
}
Any assistance is greatly appreciated, and if the question has issues, please let me know. Still rather new to this so feedback is appreciated.

I'm not sure if I understood your intention, but the following query seems to do what you're trying to accomplish:
r.db('test')
.table('test')
.get(id)
.replace((doc) => {
// This expression makes sure that we delete the specified keys only
const roleKeys = doc
.getField('roles')
.values()
// Make sure we have a role name is in the names array
.filter(role => r.expr(names).contains(role.getField('name')))
// This is a bit tricky, and I believe I implemented this in a not efficient
// way probably missing a first-class RethinkDB expression that supports
// such a case out of box. Since we are going to delete by nested dynamic
// ids, RethinkDB requires special syntax to denote nested ids:
// {roles: {ID_1: true, ID_2: true}}
// Well, this is just a JavaScript syntax workaround, so we're building
// such an object dynamically using fold.
.fold({}, (acc, role) => acc.merge(r.object(role.getField('id'), true)));
return doc.without({roles: roleKeys});
})
For example, if names is an array, say ['Jeff', 'Rick'], the nested roleKeys expession will be dynamically evaluated into:
{2: true, 3: true}
that is merged into the roles selector, and the above query will transform the document as follows:
{
"value1": ...,
"value2": ...,
"value3": ...,
"roles": {
"1": {"name": "Dave", "id": "1"},
"4": {"name": "Red", "id": "4"}
}
}

Related

How do I create an unique dataset of json object literal in Javascript?

I want to get an output as an unique set of Categories array with the following output [Men,Woman].
Is there any way to do it in Javascript?
For example this my data
{
"products:"[
{
"id": 1,
"categories": {
"1": "Men",
},
},
{
"id": 2,
"categories": {
"1": "Men",
},
}, {
"id": 3,
"categories": {
"1": "Woman",
},
}
];
}
A simple 1 line answer would be
new Set(input.products.map(p => p.categories["1"]))
This is if you're expecting only key "1" in the categories object.
If it can have multiple categories then you can always do
const uniqueCategories = new Set();
input.products.forEach(p => uniqueCategories.add(...Object.values(p.categories)))
Now you can convert a Set into an array
PS: This is not a ReactJs problem but a pure JS question. You might want to remove the ReactJs tag from this question altogether.

Reading values from dictionary in Javascript

I am trying to read tags from a selected collection of bibliographic data in ZOTERO with Javascript.
For those who aren't familiar with ZOTERO: it has an in-built "run JS" panel to work directly with items selected / marked in the standalone version.
This is the script I am using to read data from a selected folder and access the tags:
var s = new Zotero.Search();
s.libraryID = ZoteroPane.getSelectedLibraryID();
var itemIDs = await s.search();
for (itemID of itemIDs) {
item = Zotero.Items.get(itemID);
return item;
itemTAG = item.getTags();
return itemTAG;
}
When I call return itemIDs; before the for loop, I get 4943 key:value pairs, which correctly mirrors the number of items in my collection.
The structure looks like this:
[
"0": 21848
"1": 21849
"2": 21850
"3": 21851
"4": 21852
"5": 21853
"6": 21854
"7": 21855
"8": 21856
"9": 21857
"10": 21858
]
What I would actually like to do is iterate through all IDs to get the bibliographic data for each item and return the tags.
This is why I first tried a for/in loop, but this didn't work, supposedly because I wasn't calling the key:value pairs (corresponding to a dictionary in Python?) correctly.
However, the above for/of loop works at least for the first item (item "0") and returns the following data:
{
"key": "BDSIJ5P4",
"version": 1085,
"itemType": "book",
"place": "[Augsburg]",
"publisher": "[Gabriel Bodenehr]",
"date": "[circa 1730]",
"title": "Constantinopel",
"numPages": "1 Karte",
"creators": [
{
"firstName": "Gabriel",
"lastName": "Bodenehr",
"creatorType": "author"
}
],
"tags": [
{
"tag": "Europa"
}
],
"collections": [
"DUW2PJDP"
],
"relations": {
"dc:replaces": [
"http://zotero.org/groups/2289797/items/ZB5J5VZK"
]
},
"dateAdded": "2019-02-13T17:27:29Z",
"dateModified": "2020-03-23T13:13:13Z"
}
So my two questions are:
How can I create a proper for/in loop that retrieves these same data for each item?
How can I return tags only? It seems that item.getTags() [which I used in analogy to the getNotes() examples in the documentation] may not be a valid function. Would that be specific to Zotero or Javascript in general?
Use map() to call a function on every array element and return an array of all the results.
return itemIDs.map(itemID => Zotero.Items.get(itemID).getTags())

JSON list optimization

I want to create a JSON API that returns a list of objects. Each object has an id, a name and some other information. API is consumed using JavaScript.
The natural options for my JSON output seems to be:
"myList": [
{
"id": 1,
"name": "object1",
"details": {}
},
{
"id": 2,
"name": "object2",
"details": {}
},
{
"id": 3,
"name": "object3",
"details": {}
},
]
Now let's imagine that I use my API to get all the objects but want to first do something with id2 then something else with id1 and id3.
Then I may be interested to be able to directly get the object for a specific id:
"myList": {
"1": {
"name": "object1",
"details": {}
},
"2": {
"name": "object2",
"details": {}
},
"3": {
"name": "object3",
"details": {}
},
}
This second option may be less natural when somewhere else in the code I want to simply loop through all the elements.
Is there a good practice for these use cases when the API is used for both looping through all elements and sometime using specific elements only (without doing a dedicated call for each element)?
In your example you've changed the ID value from 1 to id1. This would make operating on the data a bit annoying, because you have to add and remove id all the time.
If you didn't do that, and you were relying on the sorted order of the object, you may be in for a surprise, depending on JS engine:
var source = JSON.stringify({z: "first", a: "second", 0: "third"});
var parsed = JSON.parse(source);
console.log(Object.keys(parsed));
// ["0", "z", "a"]
My experience is to work with arrays on the transport layer and index the data (i.e. convert array to map) when required.

Indexing array values in an object in an IndexedDB

For a Chrome app, wich stores data in IndexedDB, i have a object like this:
var simplifiedOrderObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"address": "Foostreet 12, 12345 Bar York",
"orderitems": [
{
"item": "brush",
"price": "2.00"
},
{
"item": "phone",
"price": "30.90"
}
],
"parcels": [
{
"service": "DHL",
"track": "12345"
},
{
"service": "UPS",
"track": "3254231514"
}
]
}
If i store the hole object in an objectStore, can i use an index for "track", which can be contained multiple times in each order object?
Or is it needed or possibly better/faster to split each object into multiple objectStores like know from relational DBs:
order
orderitem
parcel
The solution should also work in a fast way with 100.000 or more objects stored.
Answering my own question: I have made some tests now. It looks like it is not possible to do this with that object in only 1 objectStore.
An other example object which would work:
var myObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"shipping": {"method": "letter",
"company": "Deutsche Post AG" }
}
Creating an index will be done by:
objectStore.createIndex(objectIndexName, objectKeypath, optionalObjectParameters);
With setting objectKeypath it is possible to address a value in the main object like "name":
objectStore.createIndex("name", "name", {unique: false});
It would also be possible to address a value form a subobject of an object like "shipping.method":
objectStore.createIndex("shipping", "shipping.method", {unique: false});
BUT it is not possible to address values like the ones of "track", which are contained in objects, stored in an array. Even something like "parcels[0].track" to get the first value as index does not work.
Anyhow, it would be possible to index all simple elements of an array (but not objects).
So the following more simple structure would allow to create an index entry for each parcelnumber in the array "trackingNumbers":
var simplifiedOrderObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"address": "Foostreet 12, 12345 Bar York",
"orderitems": [
{
"item": "brush",
"price": "2.00"
},
{
"item": "phone",
"price": "30.90"
}
],
"trackingNumbers": ["12345", "3254231514"]
}
when creating the index with multiEntry set to true:
objectStore.createIndex("tracking", "trackingNumbers", {unique: false, multiEntry: true});
Anyhow, the missing of the possibility to index object values in arrays, makes using indexedDB really unneeded complicated. It's a failure in design. This forces the developer to do things like in relational DBs, while lacking all the possibilities of SQL. Really bad :(

Mongodb find in hash by value

i have this mongodb documents format:
{
"_id": ObjectId("5406e4c49b324869198b456a"),
"phones": {
"12035508684": 1,
"13399874497": 0,
"15148399728": 1,
"18721839971": 1,
"98311321109": -1,
}
}
phones field - its a hash of phone numbers and frequency of its using.
And i need to select all documents, which have at least one zero or less frequency.
Trying this:
db.my_collection.find({"phones": { $lte: 0} })
but no luck.
Thanks in advance for your advices
You can't do that sort of query in MongoDB, well not in a simple way anyhow, as what you are doing here is generally an "anti-pattern", where part of your data is actually being specified as "keys". So a better way to model this is you use something where that "data" is actually a value to a key, and not the other way around:
{
"_id": ObjectId("5406e4c49b324869198b456a"),
"phones": [
{ "number": "12035508684", "value": 1 },
{ "number": "13399874497", "value": 0 },
{ "number": "15148399728", "value": 1 },
{ "number": "18721839971", "value": 1 },
{ "number": "98311321109", "value": -1 },
}
}
Then your query is quite simple:
db.collection.find({ "phones.value": { "$lte": 0 } })
But otherwise MongoDB cannot "natively" traverse the "keys" of an object/hash, and to do that you need do JavaScript evaluation to do this. Which is not a great idea for performance. Basically a $where query in short form:
db.collection.find(function() {
var phones = this.phones;
return Object.keys(phones).some(function(phone) {
return phones[phone] <= 0;
})
})
So the better option is to change the way you are modelling this and take advantage of the native operators. Otherwise most queries require and "explicit" path to any "key" inside the object/hash.

Categories

Resources