Updating one element in an array
Mongo updates are usually easy and pretty clear (if you are familiar with JSON format), but it has its own limitations, especially when it comes to updating fields within an array.
Let's assume we have a collection 'foo' like so:
"_id" : ObjectId("4f9808648859c65d"),
{"text" : "foo", "value" : 11},
{"text" : "foo", "value" : 22},
{"text" : "foobar", "value" : 33}
And now we would like to update the text of the element in the array 'array' to "blah" where the value is 22:
> db.foo.update({"array.value" : 22}, {"$set" : {"array.$.text" : "blah"}})
"_id" : ObjectId("4f9808648859c65d"),
{"text" : "foo", "value" : 11},
{"text" : "foobar", "value" : 33},
{"text" : "blah", "value" : 22}
So, as you just saw, the trick is the dollar sign '$' (called the $ positional operator) which saves the index (1 in our case) of the element from the array that matched the query. This means that if we knew the position of the element (which is nearly impossible in a real life case), we will just change the update statement to : {"$set" : {"array.1.text" : "blah"}}.
Please note that the $ positional operator (for now) updates the first relevant document ONLY. This means if the query was to update all elements where the value is greater than 10, it will just update the element where value is 10, and skip the other two (10gen are still working on this, and here's the ticket for it).
But you can always work around this, and the laziest way is to read the entire document, update it manually, and then save it back. You must be careful with this process since it isn't the safest: the same object might be subject to other updates while you're manually updating the array. To avoid that, the simplest way is to use the 'update if current' (will be the topic of the next post).