mongodb: вставьте, если не существует

Каждый день я получаю запас документов (обновление). То, что я хочу сделать, является вставкой каждый объект, который уже не существует.

  • Я также хочу отслеживать первый раз, когда я вставил их и в прошлый раз, когда я видел их в обновлении.
  • Я не хочу иметь дублирующиеся документы.
  • Я не хочу удалять документ, который был ранее сохранен, но не находится в моем обновлении.
  • 95% (оцененных) записей, не изменяются со дня на день.

Я использую драйвер 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)

Кто-то может советовать, как сделать это быстрее?

125
задан Michael Currie 7 June 2015 в 03:20
поделиться

3 ответа

Похоже, вы хотите сделать "апсерт". 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" и оставит все остальное нетронутым.

134
ответ дан 24 November 2019 в 01:00
поделиться

Вообще, использование update лучше в MongoDB, так как он просто создаст документ, если он еще не существует, хотя я не уверен, как это работает с вашим адаптером python.

Во-вторых, если вам нужно знать, существует ли документ, то count(), возвращающий только число, будет лучшим вариантом, чем find_one, который, предположительно, передаст весь документ из вашей MongoDB, вызывая ненужный трафик.

4
ответ дан 24 November 2019 в 01:00
поделиться

Я не думаю, что 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 , выполнить вставку и сразу после этого выполнить обновление только для поля «обновлено».

5
ответ дан 24 November 2019 в 01:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: