Каждый день я получаю запас документов (обновление). То, что я хочу сделать, является вставкой каждый объект, который уже не существует.
Я использую драйвер Python (pymongo).
То, что я в настоящее время делаю, (псевдокодируйте):
for each document in update:
existing_document = collection.find_one(document)
if not existing_document:
document['insertion_date'] = now
else:
document = existing_document
document['last_update_date'] = now
my_collection.save(document)
Моя проблема состоит в том, что это очень медленно (40 минут меньше чем для 100 000 записей, и у меня есть миллионы из них в обновлении). Я вполне уверен существует что-то встроенное для того, чтобы сделать это, но документ для обновления () является mmmhhh.... немного кратким.... (http://www.mongodb.org/display/DOCS/Updating)
Кто-то может советовать, как сделать это быстрее?
Похоже, вы хотите сделать "апсерт". MongoDB имеет встроенную поддержку для этого. Передайте дополнительный параметр в вызов update(): {upsert:true}. Например:
key = {'key':'value'}
data = {'key2':'value2', 'key3':'value3'};
coll.update(key, data, upsert=True); #In python upsert must be passed as a keyword argument
Это полностью заменяет блок if-find-else-update. Он вставит, если ключ не существует, и обновит, если существует.
До:
{"key":"value", "key2":"Ohai."}
После:
{"key":"value", "key2":"value2", "key3":"value3"}
Вы также можете указать, какие данные вы хотите записать:
data = {"$set":{"key2":"value2"}}
Теперь ваш выбранный документ обновит только значение "key2" и оставит все остальное нетронутым.
Вообще, использование update лучше в MongoDB, так как он просто создаст документ, если он еще не существует, хотя я не уверен, как это работает с вашим адаптером python.
Во-вторых, если вам нужно знать, существует ли документ, то count(), возвращающий только число, будет лучшим вариантом, чем find_one, который, предположительно, передаст весь документ из вашей MongoDB, вызывая ненужный трафик.
Я не думаю, что mongodb поддерживает этот тип выборочного обновления. У меня та же проблема, что и у LeMiz, и использование update (критериев, newObj, upsert, multi) не работает правильно при работе с метками времени как «создано», так и «обновлено». Учитывая следующее утверждение upsert:
update( { "name": "abc" },
{ $set: { "created": "2010-07-14 11:11:11",
"updated": "2010-07-14 11:11:11" }},
true, true )
Сценарий № 1 - документ с 'name' из 'abc' не существует: Новый документ создается с 'name' = 'abc', 'created' = 2010-07-14 11:11:11 и 'updated' = 2010-07-14 11:11:11.
Сценарий №2 - документ с 'именем' abc 'уже существует со следующим: 'name' = 'abc', 'created' = 2010-07-12 09:09:09 и 'updated' = 2010-07-13 10:10:10. После обновления документ будет таким же, как результат в сценарии №1. Невозможно указать в upsert, какие поля будут установлены при вставке, а какие поля оставить без изменений при обновлении.
Мое решение состояло в том, чтобы создать уникальный индекс для полей critera , выполнить вставку и сразу после этого выполнить обновление только для поля «обновлено».