Multi — document update and atomicity in Mongodb

Supun Dharmarathne
technodyne
Published in
2 min readMar 6, 2013

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}

]

--

--