Databases Reference
In-Depth Information
Returning Updated Documents
You can get some limited information about what was updated by calling
getLastError , but it does not actually return the updated document. For that, you'll
need the findAndModify command.
findAndModify is called differently than a normal update and is a bit slower, because it
must wait for a database response. It is handy for manipulating queues and performing
other operations that need get-and-set style atomicity.
Suppose we have a collection of processes run in a certain order. Each is represented
with a document that has the following form:
{
"_id" : ObjectId(),
"status" : state ,
"priority" : N
}
"status" is a string that can be “READY,” “RUNNING,” or “DONE.” We need to find
the job with the highest priority in the “READY” state, run the process function, and
then update the status to “DONE.” We might try querying for the ready processes,
sorting by priority, and updating the status of the highest-priority process to mark it is
“RUNNING.” Once we have processed it, we update the status to “DONE.” This looks
something like the following:
ps = db.processes.find({"status" : "READY").sort({"priority" : -1}).limit(1).next()
db.processes.update({"_id" : ps._id}, {"$set" : {"status" : "RUNNING"}})
do_something(ps);
db.processes.update({"_id" : ps._id}, {"$set" : {"status" : "DONE"}})
This algorithm isn't great, because it is subject to a race condition. Suppose we have
two threads running. If one thread (call it A) retrieved the document and another thread
(call it B) retrieved the same document before A had updated its status to “RUNNING,”
then both threads would be running the same process. We can avoid this by checking
the status as part of the update query, but this becomes complex:
var cursor = db.processes.find({"status" : "READY"}).sort({"priority" : -1}).limit(1);
while ((ps = cursor.next()) != null) {
ps.update({"_id" : ps._id, "status" : "READY"},
{"$set" : {"status" : "RUNNING"}});
var lastOp = db.runCommand({getlasterror : 1});
if (lastOp.n == 1) {
do_something(ps);
db.processes.update({"_id" : ps._id}, {"$set" : {"status" : "DONE"}})
break;
}
cursor = db.processes.find({"status" : "READY"}).sort({"priority" : -1}).limit(1);
}
Also, depending on timing, one thread may end up doing all the work while another
thread is uselessly trailing it. Thread A could always grab the process, and then B would
 
Search WWH ::




Custom Search