Find and Modify (or Remove)
MongoDB 1.3+ supports a "find, modify, and return" command. This command can be used to atomically modify a document (at most one) and return it. Note that, by default, the document returned will not include the modifications made on the update.
The general form is db.runCommand( { findAndModify : <collection>,
<options> } )
The MongoDB shell includes a helper method, findAndModify(), for executing the command. Some drivers provide helpers also. At least one of the update or remove parameters is required; the other arguments are optional.
The sort option is useful when storing queue-like data. Let's take the example of fetching the highest priority job that hasn't been grabbed yet and atomically marking it as grabbed:
> db.jobs.save( {
name: "Next promo",
inprogress: false, priority:0,
tasks : [ "select product", "add inventory", "do placement"]
} );
> db.jobs.save( {
name: "Biz report",
inprogress: false, priority:1,
tasks : [ "run sales report", "email report" ]
} );
> db.jobs.save( {
name: "Biz report",
inprogress: false, priority:2,
tasks : [ "run marketing report", "email report" ]
} );
> job = db.jobs.findAndModify({
query: {inprogress: false, name: "Biz report"},
sort : {priority:-1},
update: {$set: {inprogress: true, started: new Date()}},
new: true
});
{
"_id" : ...,
"inprogress" : true,
"name" : "Biz report",
"priority" : 2,
"started" : "Mon Oct 25 2010 11:15:07 GMT-0700 (PDT)",
"tasks" : [
"run marketing report",
"email report"
]
}
You can pop an element from an array for processing and update in a single atomic operation:
> task = db.jobs.findAndModify({
query: {inprogress: false, name: "Next promo"},
update : {$pop : { tasks:-1}}, fields: {tasks:1},
new: false } )
{
"_id" : ...,
"tasks" : [
"select product",
"add inventory",
"do placement"
]
}
> db.jobs.find( { name : "Next promo"} )
{
"_id" : ...,
"inprogress" : false,
"name" : "Next promo",
"priority" : 0,
"tasks" : [ "add inventory", "do placement" ]
}
You can also simply remove the object to be returned.
> job = db.jobs.findAndModify( {sort:{priority:-1}, remove:true} );
{
"_id" : ...,
"inprogress" : true,
"name" : "Biz report",
"priority" : 2,
"started" : "Mon Oct 25 2010 10:44:15 GMT-0700 (PDT)",
"tasks" : [
"run marketing report",
"email report"
]
}
> db.jobs.find()
{
"_id" : ...,
"inprogress" : false,
"name" : "Next promo",
"priority" : 0,
"tasks" : [ "add inventory", "do placement" ]
}
{
"_id" : ...,
"name" : "Biz report",
"inprogress" : false,
"priority" : 1,
"tasks" : [ "run sales report", "email report" ]
}
If the client crashes before processing the job or task in the above examples, the data will be lost forever. See the tests for more examples. If your driver doesn't provide a helper function for this command, run the command directly with something like this: job = db.runCommand({ findAndModify : "jobs",
sort : { priority : -1 },
remove : true
}).value;
Sharding limitationsfindandmodify will behave the same when called through a mongos as long as the collection it is modifying is unsharded. If the collection is sharded, then the query must contain the shard key. See Also |

PLEASE POST QUESTIONS IN THE USER GROUPS FORUM. Post non-question comments and helpful hints here.
blog comments powered by Disqus