Add a new field to all documents in a nested array

I have a database of human documents. Each has a field called photos, which is an array of photo documents. I would like to add a new β€œchecked” flag to each of the photo documents and initialize it to false.

This is the query I'm trying to use:

db.person.update({ "_id" : { $exists : true } }, {$set : {photos.reviewed : false} }, false, true) 

However, I get the following error:

 SyntaxError: missing : after property id (shell):1 

Is this possible, and if so, what am I doing wrong in my update?

Here is a complete example of a person document:

 { "_class" : "com.foo.Person", "_id" : "2894", "name" : "Pixel Spacebag", "photos" : [ { "_id" : null, "thumbUrl" : "http://site.com/a_s.jpg", "fullUrl" : "http://site.com/a.jpg" }, { "_id" : null, "thumbUrl" : "http://site.com/b_s.jpg", "fullUrl" : "http://site.com/b.jpg" }] } 

Bonus karma for anyone who can tell me what is cleaner, why update "all documents" without using the request { "_id" : { $exists : true } }

+7
source share
4 answers

Is this possible, and if so, what am I doing wrong in my update?

Not. In general, MongoDB can only do updates on top-level objects.

An exception is the $ positional operator . From the docs: Use this to find an array member and then manipulate it .

However, in your case, you want to change all the elements in the array. So this is not what you need.

Bonus karma for anyone who can tell me what is cleaner, why update "all documents"

Try db.coll.update(query, update, false, true) , this will update "multi". This last true is what makes it multi.

Is it possible,

You have two options:

  • Write a for loop to complete the update. It will basically be a nested for loop, one for looping through data, the other for looping through a submatrix. If you have a lot of data, you will need to write that this is your choice (and possibly multi-threaded).
  • Write your code to handle reviewed as nullable. Write the data in such a way that when you get a photo with reviewed undefined, it should be false . Then you can set the field accordingly and pass it back to the database.

Method # 2 is something you should get used to. As your data grows and you add fields, it becomes difficult to β€œrevert” all old data. This is similar to the problem of issuing a schema change in SQL when there are 1B elements in the database.

Instead, make your code null resistant and learn to treat it as the default.

Again, this is not the solution you are looking for.

+9
source

You can do it

 (null, {$set : {"photos.reviewed" : false} }, false, true) 

The first parameter is null: no specification = any item in the collection.

"photos.reviewed" must be declared as a string to update the subfield.

-one
source

You can do the following:

 db.person.update({}, $set:{name.surname:null}, false, true); 
-one
source

The old theme is now, but it just worked perfectly with Mongo 3.0.6:

db.users.update({ _id: ObjectId("55e8969119cee85d216211fb") }, { $set: {"settings.pieces": "merida"} })

In my case, the custom object looks like

 { _id: 32, name: "foo", ..., settings: { ..., pieces: "merida", ...} } 
-one
source

All Articles