Вставлять или игнорировать несколько документов в mongoDB

У меня есть коллекция, в которой все мои документы имеют по крайней мере эти 2 поля, например name и url (где url уникально, поэтому я установил на нем уникальный индекс). Теперь, если я попытаюсь вставить документ с дубликатом url, он даст ошибку и остановит программу. Я не хочу этого поведения, но мне нужно что-то вроде mysql insert or ignore, так что mongoDB не должен вставлять документ с дубликатом url и продолжить со следующими документами.

Есть ли какой-нибудь параметр, который я могу передать команде insert для достижения такого поведения? Я обычно делаю пакет вставки с помощью pymongo как:

collection.insert(document_array)

Здесь collection представляет собой набор, а document_array - это массив документов.

Итак, можно ли каким-либо образом реализовать функциональность insert or ignore для вставки нескольких документов?

Ответ 1

Установите флаг continue_on_error при вызове insert(). Обратите внимание на драйвер PyMongo 2.1 и версию сервера 1.9.1:

continue_on_error (необязательно): если True, база данных не остановится обрабатывая объемную вставку, если не удается (например, из-за дубликатов идентификаторов). Это приводит к тому, что объемная вставка ведет себя так же, как серия одиночных вставок, кроме lastError будет установлен, если какая-либо вставка не удалась, а не только последняя один. Если возникает несколько ошибок, будут сообщены только самые последние данные по ошибке().

Ответ 3

Попробуйте следующее:

try:
    coll.insert(
        doc_or_docs=doc_array,
        continue_on_error=True)
except pymongo.errors.DuplicateKeyError:
    pass

Операция вставки все равно выдает исключение, если во вставке возникает ошибка (например, попытка вставить дублирующее значение для уникального индекса), но это не повлияет на другие элементы массива. Затем вы можете усвоить ошибку, как показано выше.

Ответ 4

Почему бы просто не поместить ваш вызов в .insert() внутри блока try: ... except: и продолжить, если вставка не удалась?

Кроме того, вы также можете использовать обычный вызов update() с флагом upsert. Подробности здесь: http://www.mongodb.org/display/DOCS/Updating#Updating-update%28%29

Ответ 5

Если у вас есть свой массив документов, уже находящихся в памяти вашего python script, почему бы не вставить их путем итерации через них и просто поймать те, которые не могут быть вставлены из-за уникального индекса?

for doc in docs:
  try:
    collection.insert(doc)
  except pymongo.errors.DuplicateKeyError:
    print 'Duplicate url %s' % doc

Где коллекция представляет собой экземпляр коллекции, созданной из ваших экземпляров соединения/базы данных, а документы - это массив словарей (документов), которые вы в настоящее время передаете для вставки.

Вы также можете решить, что делать с дублирующимися ключами, которые нарушают ваш уникальный индекс в блоке except.

Ответ 6

Что я делаю:

  • Генерировать массив идентификаторов MongoDB, которые я хочу вставить (хэш некоторых значений в моем случае)
  • Удалите существующие идентификаторы (я использую команду redis queue bcoz, но вы можете запросить mongo)
  • Вставьте очищенные данные!

Redis идеально подходит для этого, вы можете использовать Memcached или Mysql Memory, в соответствии с вашими потребностями.

Ответ 7

Настоятельно рекомендуется использовать upsert

  stat.update({'location': d['user']['location']}, \
       {'$inc': {'count': 1}},upsert = True, safe = True)

Здесь stat - это коллекция, если местоположение посетителя уже присутствует в коллекции, count увеличивается на единицу, иначе count устанавливается на 1.

Вот ссылка для документации http://www.mongodb.org/display/DOCS/Updating#Updating-UpsertswithModifiers