Multi — document update and atomicity in Mongodb
Documents updates in mongo are pretty straight forward when it comes to updating one document at a time.But updating multiple documents isn’t really that different, you just have to be aware of its pseudo-atomicity.
Let’s assume we have a collection ‘foo
’
that contains a list of documents
> db.foo.find()
[
{"_id" : ObjectId("4ec2e036e2a13727b"), "text" : "bar", "value" : 11},
{"_id" : ObjectId("4efba63c4d6a58d47"), "text" : "foo", "value" : 22},
{"_id" : ObjectId("4ecee6f9e2534534a"), "text" : "foo bar", "value" : 33},
{"_id" : ObjectId("4e9e46f9e2a4324a0"), "text" : "bar foo", "value" : 44}
]
Now let’s change the text to “blah” for every object that has a value higher than 30:
> db.foo.update({"value" : {$gt : 30}}, {$set : {"text" : "blah"}})
> db.foo.find()
[
{"_id" : ObjectId("4ec2e036e2a13727b"), "text" : "bar", "value" : 11},
{"_id" : ObjectId("4efba63c4d6a58d47"), "text" : "foo", "value" : 22},
{"_id" : ObjectId("4e9e46f9e2a4324a0"), "text" : "bar foo", "value" : 44},
{"_id" : ObjectId("4ecee6f9e2534534a"), "text" : "blah", "value" : 33}
]
Running this query updated only one document, why? Because Mongo updates affect (natively) only the 1st relevant object.
Looking closer at the update command, we can see that it takes a query, update, upsert, and multi as arguments, where query is your condition, update is the update object, upsert is a boolean flag (set to false by default) that creates a document if we don’t have any match against the query, and, yes you guessed it, the multi is a boolean flag (set to false by default) that forces the update to run against all relevant document. But as said above, this is a pseudo-atomic operation (it will allow some other operations, which could be writes, to interleave ). To avoid this issue, we simply need to add ‘$atomic : 1'
to the query statement like so:
> db.foo.update({$atomic : 1, "value" : {$gt : 30}}, {$set : {"text" : "mamba"}}, false, true)> db.foo.find()[
{"_id" : ObjectId("4ec2e036e2a13727b"), "text" : "bar", "value" : 11},
{"_id" : ObjectId("4efba63c4d6a58d47"), "text" : "foo", "value" : 22},
{"_id" : ObjectId("4e9e46f9e2a4324a0"), "text" : "mamba", "value" : 44},
{"_id" : ObjectId("4ecee6f9e2534534a"), "text" : "mamba", "value" : 33}
]