Вставка данных, если они не существуют с использованием ошибки pymongo generate, индексы TypeError: list должны быть целыми числами или срезами, а не str [duplicate]

Класс SimpleNamespace может использоваться для создания новых атрибутов с помощью setattr или подкласса SimpleNamespace и создания вашей собственной функции для добавления новых имен атрибутов (переменных).

from types import SimpleNamespace variables = {"b":"B","c":"C"} a = SimpleNamespace(**v) setattr(a,"g","G") a.g = "G+" something = a.a
105
задан Michael Currie 7 June 2015 в 03:20
поделиться

8 ответов

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

113
ответ дан penguin2048 20 August 2018 в 22:48
поделиться
  • 1
    Это почти то, что я хочу! Как я могу не коснуться поля insertion_date, если объект уже присутствует? – LeMiz 27 May 2010 в 22:24
  • 2
    можете ли вы привести пример просто установки поля для первой вставки и не обновлять его, если он существует? @VanNguyen – Ali Shakiba 8 April 2012 в 02:04
  • 3
    Думаю, первая часть вашего ответа неверна. coll.update будет заменять данные, если вы не используете $ set. Итак, на самом деле: {'key2': 'value2', 'key3': 'value3'} – James Blackburn 22 January 2013 в 15:13
  • 4
    -1 Этот ответ опасен. Вы находите по значению «ключ». и затем вы удаляете «ключ», так что впоследствии вы не сможете найти его снова. Это очень маловероятный вариант использования. – Mark E. Haase 29 December 2013 в 23:33
  • 5
    Вы должны использовать оператор $ setOnInsert! Upsert даже обновит документ, если будет найден запрос. – YulCheney 14 September 2014 в 16:54

Начиная с MongoDB 2.4 вы можете использовать $ setOnInsert ( http://docs.mongodb.org/manual/reference/operator/setOnInsert/ )

Установить 'insertion_date 'используя $ setOnInsert и' last_update_date ', используя $ set в вашей команде upsert.

Чтобы превратить ваш псевдокод в рабочий пример:

now = datetime.utcnow()
for document in update:
    collection.update_one(
        {"_id": document["_id"]},
        {
            "$setOnInsert": {"insertion_date": now},
            "$set": {"last_update_date": now},
        },
        upsert=True,
    )
40
ответ дан Felk 20 August 2018 в 22:48
поделиться
  • 1
    Это правильно, вы можете проверить документ, соответствующий фильтру, и вставить что-то, если не найдено, используя $ setOnInsert. Обратите внимание, что была ошибка, в которой вы не могли $ setOnInsert с полем _id - он сказал бы что-то вроде «не может изменить поле _id». Это была ошибка, исправленная в версии 2.5.4 или там. Если вы видите это сообщение или проблему, просто получите последнюю версию. – Kieren Johnstone 17 May 2015 в 20:16

Резюме

  • У вас есть существующая коллекция записей.
  • У вас есть набор записей, содержащих обновления существующих записей.
  • Some Обновления ничего не обновляют, они дублируют то, что у вас уже есть.
  • Все обновления содержат те же самые поля, которые уже есть, возможно, разные значения.
  • Вы хотите (/ g5)

Заметьте, я предполагаю, что PyMongo изменится в соответствии с вашим выбранным языком.

Инструкции:

  1. Создайте коллекцию с индексом с уникальным значением = true, чтобы вы не получали повторяющиеся записи.
  2. Итерируйте по своим входным записям, создавая их из 15 000 записей или так. Для каждой записи в партии создайте dict, состоящий из данных, которые вы хотите вставить, предполагая, что каждый из них будет новой записью. Добавьте к ним «созданные» и «обновленные» временные метки. Выполните это как команду пакетной вставки с флагом 'ContinueOnError' = true, поэтому вставка всего остального происходит, даже если есть дубликат (там, где это будет похоже). ЭТО ПРОИСХОДИТ ОЧЕНЬ БЫСТРО. Массовые вставки рок, я получил 15k / секунду производительности. Дальнейшие примечания о ContinueOnError см. В http://docs.mongodb.org/manual/core/write-operations/ Запись вставки происходит ОЧЕНЬ быстро, так что вы будете с этими вставками в кратчайшие сроки. Теперь пришло время обновить соответствующие записи. Сделайте это с помощью пакетного поиска, намного быстрее, чем по одному.
  3. Повторите все ваши записи ввода, создав партии 15K или около того. Извлеките ключи (лучше всего, если есть один ключ, но не может быть помог, если нет). Получите эту группу записей из Mongo с помощью запроса db.collectionNameBlah.find ({field: {$ in: [1, 2,3 ...}). Для каждой из этих записей определите, есть ли обновление, и если да, выполните обновление, включая обновление «обновленной» метки времени. К сожалению, следует отметить, что MongoDB 2.4 и ниже НЕ включают операцию массового обновления. Они работают над этим.

Точки оптимизации клавиш:

  • Вставки значительно ускорят ваши операции навалом.
  • Извлечение записей в массовом порядке также ускорит процесс.
  • Индивидуальные обновления - единственный возможный маршрут, но 10Gen работает над ним. Предположительно, это будет в 2.6, хотя я не уверен, что он будет закончен к тому времени, есть много чего заняться (я слежу за их системой Jira).
5
ответ дан Kevin J. Rice 20 August 2018 в 22:48
поделиться

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

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

4
ответ дан Luke B_ 20 August 2018 в 22:48
поделиться
[Д2] 1. Использовать обновление.

Рисование из ответа Ван Нгуена выше, используйте обновление вместо сохранения. Это дает вам доступ к опции upsert.

ПРИМЕЧАНИЕ. Этот метод переопределяет весь документ при обнаружении ( из документов )

var conditions = { name: 'borne' }   , update = { $inc: { visits: 1 }} , options = { multi: true };

Model.update(conditions, update, options, callback);

function callback (err, numAffected) {   // numAffected is the number of updated documents })

1.a. Используйте $ set

Если вы хотите обновить выбор документа, но не все это, вы можете использовать метод $ set с обновлением. (опять же, Из документов ) ... Итак, если вы хотите установить ...

var query = { name: 'borne' };  Model.update(query, ***{ name: 'jason borne' }***, options, callback)

Отправить его как ...

Model.update(query, ***{ $set: { name: 'jason borne' }}***, options, callback)

Это помогает предотвратить случайную перезапись всех ваших документов с помощью { name: 'jason borne' }.

6
ответ дан Martijn Pieters 20 August 2018 в 22:48
поделиться

Вы всегда можете создать уникальный индекс, который заставит MongoDB отклонить конфликтующее сохранение. Рассмотрим следующее, выполненное с использованием оболочки mongodb:

> db.getCollection("test").insert ({a:1, b:2, c:3})
> db.getCollection("test").find()
{ "_id" : ObjectId("50c8e35adde18a44f284e7ac"), "a" : 1, "b" : 2, "c" : 3 }
> db.getCollection("test").ensureIndex ({"a" : 1}, {unique: true})
> db.getCollection("test").insert({a:2, b:12, c:13})      # This works
> db.getCollection("test").insert({a:1, b:12, c:13})      # This fails
E11000 duplicate key error index: foo.test.$a_1  dup key: { : 1.0 }
13
ответ дан Ram Rajamony 20 August 2018 в 22:48
поделиться

Я не думаю, что 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 - документ с именем «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
ответ дан Yonsink 20 August 2018 в 22:48
поделиться

Вы можете использовать Upsert с оператором $ setOnInsert.

db.Table.update({noExist: true}, {"$setOnInsert": {xxxYourDocumentxxx}}, {upsert: true})
9
ответ дан YulCheney 20 August 2018 в 22:48
поделиться
  • 1
    [Д0] docs.mongodb.org/manual/reference/operator/update/setOnInsert/… – The Demz 13 July 2015 в 21:31
  • 2
    Для тех, кто запрашивает pymongo, третий параметр должен быть истинным или upsert = True, а не dict – S.. 3 October 2015 в 07:22
Другие вопросы по тегам:

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