Мне нужно выполнить операции обновления в документах, в которых мне нужно повернуть некоторые значения в массиве. В настоящее время запросы обновления MongoDB не позволяют вам $pop
, а затем $push
в том же поле в обновлении. После поиска рекомендаций в Интернете я решил, что db.eval()
будет наиболее подходящим для моего использования, поскольку он обеспечивает атомарность и выполняемую мной операцию очень короткую, поэтому она не будет слишком долго блокировать db.
Вот пример того, что я пытаюсь сделать:
db.eval(function (id, newVal) {
doc = db.collection.findOne({_id: id});
doc.values.shift();
doc.values.push(newVal);
db.collection.save(doc);
}, id, newVal);
И это прекрасно работает! Затем я включил профилирование mongoDB, чтобы узнать, сколько миллисекунд использовала команда eval()
, и я всегда получаю результаты меньше 1 миллисекунды:
> db.system.profile.find({op: "command"}, {"millis": 1})
{ "millis" : 0 }
{ "millis" : 0 }
...
Это хорошая новость для меня, за исключением того, что мое приложение находится на python, поэтому я использую клиент pymongo для выполнения команд eval()
. (Данные выше из оболочки mongo). Но теперь, когда я запускаю идентичные команды eval()
, используя 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)
Я получаю очень разные профилирующие результаты:
> db.system.profile.find({op: "command"}, {"millis": 1})
{ "millis" : 13 }
{ "millis" : 14 }
{ "millis" : 14 }
...
Есть ли что-то принципиально иное в том, как запускать те же команды eval()
из оболочки mongo и pymongo, что приводит к тому, что сервер занимает 14 мс для выполнения идентичных команд из pymongo?