2

Lets say we have this document:

{
    "_id" : ObjectId("4faaba123412d654fe83hg876"),
    "items" : [
            {
                    "name" : "item_one",
                    "bought" : true
            },
            {
                    "name" : "my_item",
                    "bought" : true
            },
            {
                    "name" : "my_item_three",
                    "bought" : true
            }
    ]
}

For example how can I modify the first 2 objects of the array and set their "bought" to false. Or in other words how could I change properties of the first n objects.

I thought I could first do a db.findOne() with this ID than take the items and use a function that will change the values and then set the whole item to this new array that this function returns.

That would probably do the work but is there a faster and nicer method? Is there a way to do it if I know the number of objects I want to change, so it will not be n but 5 for example.

1
  • 1
    Yes you can use .findOne() or similar logic and then alter the content of the document and .save() it back or similar. This is not a "great" pattern though as other writes could have occurred on the document in the time between when you read it and when you save it. If you need to do this kind of updating to "multiple" array elements at once then you are best to consider a different model, ie collection instead of embedded. Commented Jun 12, 2015 at 11:12

2 Answers 2

3

You can loop over the nth objects you need and set the bought to false by using the '=':

for(var i=0; i < n_times; i++){  
    my_object.items[i].bought = false;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yes but I have to use findOne() and then update() right? I was looking for a solution with one quary.
1

If you know the number of objects you want to update beforehand then you could take advantage of the dot notation in your update to access the elements of an array with a loop:

var id = ObjectId("4faaba123412d654fe83hg876");

// Iterate and update using the update query object 
for(var i=0; i<n; i++){ 
    var update = { "$set": {} };
    // set the update query object
    update["$set"]["items."+i.toString()+".bought"] = false;
    db.collection.update({"_id": id}, update, {"upsert": false, "multi": true});
}

-- EDIT --

This can also be done in one atomic update, given that you create the update object prior to the update, something like this

var update = { "$set": {} };
for(var i=0; i<n; i++){ 
    // set the update query object
    update["$set"]["items."+i.toString()+".bought"] = false;    
}

db.collection.update({"_id": id}, update, {"upsert": false, "multi": true});

Check the demo below

var update = { "$set": {} };
for(var i=0; i<5; i++){ 
    // set the update query object
    update["$set"]["items."+i.toString()+".bought"] = false;    
}

pre.innerHTML = JSON.stringify(update);
<pre id="pre"></pre>

5 Comments

Yes I was thinking exactly to use the dot notation and that's why I included the part with exact nuber of items in my question. Thank you.
But don't I do n updates like that? Wouldn't be easier if I construct an update object before that and just make 1 update?
@chnging Yes that's quite possible, actually would recommend that approach. Let me update my answer with that approach.
I implemented it like that var setObject = {}; for (var i = 0; i < n; i++) setObject["items." + i.toString() + ".bought"] = false; And then in the update() I use { $set: setObject }
@chnging Exactly what I had in mind which I updated in the answer. Cheers!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.