MongoDB updates multiple array entries

I recently started using MongoDB, and I have a question regarding updating arrays in a document. I got a structure like this:

{ "_id" : ObjectId(), "post" : "", "comments" : [ { "user" : "test", "avatar" : "/static/avatars/asd.jpg", "text" : "....." } { "user" : "test", "avatar" : "/static/avatars/asd.jpg", "text" : "....." } { "user" : "test", "avatar" : "/static/avatars/asd.jpg", "text" : "....." } ... ] } 

I am trying to execute the following query:

 update({"comments.user":"test"},{$set:{"comments.$.avatar": "new_avatar.jpg"}},false,true) 

The problem is that it updates all documents, but only the first element of the array in each document updates. Is there a way to update all elements of an array, or should I try to do this manually? Thanks.

+8
arrays mongodb
source share
4 answers

You cannot change multiple elements of an array in a single update operation. Thus, you will have to repeat the update to transfer documents for which you need to change several elements of the array. You can do this by repeating each document in the collection, reapplying the update with $elemMatch until all its relevant comments are replaced in the document, for example:

 db.collection.find (). forEach (function (doc) {
   do {
     db.collection.update ({_ id: doc._id,
                           comments: {$ elemMatch: {user: "test",
                                                 avatar: {$ ne: "new_avatar.jpg"}}}},
                          {$ set: {"comments. $. avatar": "new_avatar.jpg"}});
   } while (db.getPrevError (). n! = 0);
 })

Please note that if the effectiveness of this operation is a requirement for your application, you should normalize your scheme so that the location of the user's avatar is stored in one document, and not in each comment.

+19
source share

One solution could be to create a function that will be used with forEach and its evasion (therefore, it runs quickly). Assuming your collection is an "article", you can run the following:

 var runUpdate = function(){ db.article.find({"comments.user":"test").forEach( function(article) { for(var i in article.comments){ article.comments[i].avatar = 'new_avatar.jpg'; } db.article.save(article); }); }; db.eval(runUpdate); 
+5
source share

If you know the indexes you want to update, you can do it without any problems:

 var update = { $set: {} }; for (var i = 0; i < indexesToUpdate.length; ++i) { update.$set[`comments.${indexesToUpdate[i]}. avatar`] = "new_avatar.jpg"; } Comments.update({ "comments.user":"test" }, update, function(error) { // ... }); 
  • remember that the IDE command will not accept the syntax, but you can ignore it.
+1
source share

It looks like you can do this:

 db.yourCollection.update({"comments.user":"test"},{$set:{"comments.0.avatar": "new_avatar.jpg", "comments.1.avatar": "new_avatar.jpg", etc...}) 

So, if you have a small number of array elements, this might be a little easier to do. If you want something like "comments. *. Avatar", you don’t know how to do it. This is probably not so good that you have so much data duplication.

-one
source share

All Articles