I need to perform update operations on documents in which I need to rotate some values in an array. MongoDB update queries currently do not allow you to $pop and then $push on the same field in an update. After searching for advice online, I decided that db.eval() would be most appropriate for my use since it ensures atomicity and the operation that I'm performing is very short so it wont lock up the db for too long.
Here's an example of something I'm trying to do:
db.eval(function (id, newVal) {
doc = db.collection.findOne({_id: id});
doc.values.shift();
doc.values.push(newVal);
db.collection.save(doc);
}, id, newVal);
And this works perfectly! I then enabled mongoDB profiling to see how many milliseconds the eval() command was taking and I'd always get results of less that 1 millisecond:
> db.system.profile.find({op: "command"}, {"millis": 1})
{ "millis" : 0 }
{ "millis" : 0 }
...
This is good news to me, except that my application is in python, so I'm using a pymongo client to perform the eval() commands. (The data above is from the mongo shell) But now, when I run identical eval() commands using pymongo:
conn = pymongo.Connection(mongo_server_hostname)
db = conn.my_db
db.eval("""function (id, newVal) {
doc = db.collection.findOne({_id: id});
doc.values.shift();
doc.values.push(newVal);
db.collection.save(doc);
}""", id, new_val)
I get very different profiling results:
> db.system.profile.find({op: "command"}, {"millis": 1})
{ "millis" : 13 }
{ "millis" : 14 }
{ "millis" : 14 }
...
Is there something fundamentally different about running the same eval() commands from within the mongo shell and pymongo that results in the server taking 14ms more to run identical commands from pymongo?
evallocks the shell takes?db.evalcallsdb.commandwhich has an argumentcheck=Trueas default. According to the file:'check' (optional): check the response for errors, raising :class:'~pymongo.errors.OperationFailure' if there are any. Maybe the delay is being caused by the checking procedure.