Is there a way to update array value in algolia Partial Update Method? - algolia

My records are something like this,
{
objectID: "123123",
product_id: "456456",
categories: ['pie', 'desert']
}
I want to just replace desert with sweet in categories.
Is this possible by using partial_update_objects method?

You can't update a value but ultimately you can Remove & Add with the built-in operations. It would allow an "update" of the value (it only works if the values in the array are unique). An alternative is to get the object and compute the new value for the array to later replace it.

Related

Ag-grid setFilter in server side filtering

I just want to check if it's possible to give setFilter values in callback, in form of complex objects instead of array of strings. Reason why we need setFilter to have complex objects is because we are using server side filtering and we would like to show labels in filter, but send back keys to server to perform filtering.
If we have for example objects like {name: 'some name', id: 1} we would like to show 'some name' in filter UI but when that filter is selected we need associated id (in this case 1).
By looking into source code of setFilter and corresponding model, it seems like this is not possible.
Is there a way maybe I am missing that this could work?
ag-Grid version 23.2.0
I have exactly the same problem, from the interface it seems impossible indeed because of expected string[] values
interface SetFilterValuesFuncParams {
// The function to call with the values to load into the filter once they are ready
success: (values: string[]) => void;
// The column definition object from which the set filter is invoked
colDef: ColDef;
}

Update last object inside array [duplicate]

I have an object structure like this:
{
name: "...",
pockets: [
{
cdate: "....",
items: [...]
}
...
]
}
In an update operation, I want to add some records into the items field of the last pocket item. Using dot notation is the only way that I know to access a sub document, but I can't get what I want. So, I'm looking for something like these:
pockets.-1.items
pockets.$last.items
Is it possible to modify the last element? If yes, how?
I don't know of a way to do this using a single-line query. But you could select the record, update and then save it.
var query = <insert query here>;
var mydocs = db.mycollection.find(query);
for (var i=0 ; i<mydocs.length ; i++) {
mydocs[i].pockets[pockets.length-1].items.push('new item');
db.mycollection.save(mydoc);
}
I don't believe it is possible to do it atomically. There is a request for this functionality to be added to MongoDB.
If you can assure thread-safety in your application code, you could probably use a sequence of $pop from pockets array (that removes the last element from pockets) to variable p and then $addToSet to p.items, now you can $push p back into pockets. But if your application doesn't have a way to assure only one process may be doing this at one time, then another process could modify the array in the middle of those steps and you may end up losing that update.
You might also look into "Update if current" semantics here to see another way you can work around possible race by multiple threads issue.

Mongoose - Querying a collection for a new property with a default value without having to resave every element

We recently added a new property to one of our Mongoose schemas that defines takes a String with an enum validator and a default value. We now need to query for documents using that property but it isn't set for pre-existing documents until after the query happens. Is there any way to get around this without having to re-save every document in that collection that existed before this change, or if not is there a best practice for how to do that cleanly?
The new property:
sales_category: {
type: String,
required: true,
enum: ["Prospect", "Subscriber", "Activated Trial", "Expired Subscriber", "Expired Free Trial"],
default: "Prospect"
}
The query:
Account.find({sales_category: "Prospect"}).populate("account_holder").exec(function(err, accounts) {
Edit: I just found https://stackoverflow.com/a/14288276/8324 which seems to imply that there is no clean way to do this, the suggestion to leave it as it is and just invert any query for {sales_category: "Prospect"} to a query for not any of the other categories seems like the best solution provided the enum never changes. I'm not sure if we can guarantee that it in this use case though so I think I might end up falling back to the "re-save everything" solution, even if it doesn't feel great.
I'll leave this open for now in case someone has a better solution.
What about using an OR conditional with an $exists operator?
Account.find().or([{sales_category: "Prospect"}, { sales_category: { $exists: false }}]).populate("account_holder").exec(function(err, accounts) {...});
One note: this doesn't use an index which would only be a concern if this is used on a large collection.

Updating multiple complex array elements in MongoDB

I know this has been asked before, but I have yet to find a solution that works efficiently. I am working with the MongoDB C# driver, though this is more of a general question about MongoDB operations.
I have a document structure that looks something like this:
field1: value1
field2: value2
...
users: [ {...user 1 subdocument...}, {...user 2 subdocument...}, ... ]
Some facts:
Each user subdocument includes further sub-arrays & subdocuments (so they're fairly complex).
The average users array only contains about 5 elements, but in the worst case can surpass 100.
Several thousand update operations on multiple users may be conducted per day in this system, each on one document at a time. Larger arrays will receive more frequent updates due to their data size.
I am trying to figure out how to do this efficiently. From what I've heard, you cannot directly set several array elements to new values all at once, so I had to try something else.
I tried using the $pullAll / $AddToSet + $each operations to remove the old array and replace it with a modified one. I am aware that $pullall can remove only the elements that I need as well, but I would like to preserve the order of elements.
The C# code:
try
{
WriteConcernResult wcr = collection.Update(query,
Update.Combine(Update.PullAll("users"),
Update.AddToSetEach("users", newUsers.ToArray())));
}
catch (WriteConcernException wce)
{
return wce.Message;
}
In this case newUsers is aList<BsonValue>converted to an array. However I am getting the following exception message:
Cannot update 'users' and 'users' at the same time
By the looks of it, I can't have two update statements in use on the same field in the same write operation.
I also tried Update.Set("users", newUsers.ToArray()), but apparently the Set statement doesn't work with arrays, just basic values:
Argument 2: cannot convert from 'MongoDB.Bson.BsonValue[]' to 'MongoDB.Bson.BsonValue'
So then I tried converting that array to a BsonDocument:
Update.Set("users", newUsers.ToArray().ToBsonDocument());
And got this:
An Array value cannot be written to the root level of a BSON document.
I could try replacing the whole document, but that seems like overkill and definitely not very efficient.
So the only thing I can think of now is to run two separate write operations: one to remove the unwanted old users and another to replace them with their newer versions:
WriteConcernResult wcr = collection.Update(query, Update.PullAll("users"));
WriteConcernResult wcr = collection.Update(query, Update.AddToSetEach("users", newUsers.ToArray()));
Is this my best option? Or is there another, better way of doing this?
Your code should work with a minor change:
Update.Set("users", new BsonArray(newUsers));
BsonArray is a BsonValue, where as an array of documents is not and we don't implicitly convert arrays like we do other primitive values.
this extension method solve my problem:
public static class MongoExtension
{
public static BsonArray ToBsonArray(this IEnumerable list)
{
var array = new BsonArray();
foreach (var item in list)
array.Add((BsonValue) item);
return array;
}
}

Mongodb "getting" keys to update values within them

I have a document for a user
bob = collection.find_one({'username':'bob'})
This returns to me a python dictionary,
print bob
>>{u'_id': ObjectId('542130bd43941e7878a8fa378'),
u'likes': {},
}
type(bob)
>> dict
So how can I do something like bob.update({'likes': {'sports':'football','movie':'terminator'}})
You are using update() incorrectly. update() updates a document within a collection. So you must call it on your collection, and pass it a dictionary that specifies the document you wish to update, and use the $set modifier to modify certain fields in the document you specified earlier.
Like this:
collection.update({'username': 'bob'}, {'$set': {'likes': {'sports': 'football', 'movie': 'terminator'}}})
Check out the documents here for more useful information regarding update(), as Salvador Dali already mentioned:
http://api.mongodb.org/python/current/api/pymongo/collection.html#pymongo.collection.Collection.update