разнородное массовое обновление в mongodb

#mongodb

#mongodb

Вопрос:

Я знаю, что мы можем массово обновлять документы в mongodb с

 db.collection.update( criteria, objNew, upsert, multi )
  

в одном вызове БД, но оно однородное, т.Е. Все затронутые документы соответствуют одному типу критериев. Но то, что я хотел бы сделать, это что-то вроде

 db.collection.update([{criteria1, objNew1}, {criteria2, objNew2}, ...]
  

для отправки множественного запроса на обновление, который обновит, возможно, абсолютно разные документы или класс документов в одном вызове БД.

Что я хочу сделать в своем приложении, так это вставить / обновить кучу объектов с составным первичным ключом, если ключ уже существует, обновите его; вставьте его в противном случае.

Могу ли я сделать все это в одном сочетании в mongodb?

Ответ №1:

Это два отдельных вопроса. К первому; нет встроенного механизма MongoDB для массовой отправки пар критериев / обновлений, хотя технически выполнение этого в цикле самостоятельно должно быть примерно таким же эффективным, как любая встроенная массовая поддержка.

Проверка наличия документа на основе встроенного документа (то, что вы называете составным ключом, но в интересах правильной терминологии, чтобы избежать путаницы, в этом случае лучше использовать имя mongo) и вставка / обновление в зависимости от этого проверка существования может быть выполнена с помощью upsert :

документ A :

 {
    _id: ObjectId(...),
    key: {
        name: "Will",
        age: 20
    }
}

db.users.update({name:"Will", age:20}, {$set:{age: 21}}), true, false)
  

Это обновление (обновление с помощью вставки, если ни один документ не соответствует критериям) будет выполнять одно из двух действий в зависимости от наличия документа A :

  • Существует: выполняет обновление «$ set: {возраст: 21}» для существующего документа
  • Не существует : создайте новый документ с полями «имя» и полем «возраст» со значениями «Будет» и «20» соответственно (в основном критерии копируются в новый документ), а затем применяется обновление ($set: {возраст: 21}). Конечным результатом является документ с «name» =»Will» и «age» = 21.

Надеюсь, это поможет

Комментарии:

1. спасибо за ваш быстрый ответ. Во-первых, не будет ли намного эффективнее отправлять несколько пар критериев / обновлений в одном вызове БД, особенно когда требуется обновить множество документов, а драйвер / сервер mongodb находятся на разных компьютерах? Второй вопрос, который вы упомянули, не является новым вопросом. Возможно, я не очень хорошо его представил. Я имею в виду, что составной ключ не имеет ничего общего с _id, это всего лишь два поля (скажем, тип и имя) документа, и я использую их вместе, чтобы определить, существует ли объект уже в БД, и использовать op. Это просто для представления сценария.

2. Привет. Да, это было бы более эффективно, но такая массовая операция в настоящее время поддерживается только для вставок. Одной из причин может быть то, что сложно представить возможные ошибки клиенту при каждой попытке обновления. Сообщите об этом как о проблеме / вопросе на jira.mongodb.com если вы чувствуете, что это должно быть добавлено. Я неправильно понял вторую часть вашего вопроса из-за терминологии. То, что вам нужно, звучит как базовая ошибка. Я соответствующим образом отредактирую свой ответ, поэтому проверьте, поможет ли это вам.

3. Да, getLastError возможно, проблема, если поддерживается массовое обновление с несколькими критериями, и все может быть сложнее, если транзакция будет принята. Итак, я изменил свою реализацию с помощью цикла обновления, и теперь upsert точно вписывается в нее. Решено!

Ответ №2:

мы видим некоторые преимущества предложения $in . нашим вариантом использования было обновление «статуса» в документе для большого количества записей. В нашем первом разрезе мы выполняли цикл for и выполняли обновления один за другим. 1. Но затем мы перешли на использование предложения $in, и это значительно улучшило ситуацию.

Ответ №3:

Нет никакой реальной выгоды от выполнения обновлений так, как вы предлагаете.

Причина, по которой существует API массовой вставки и что он быстрее, заключается в том, что Mongo может записывать все новые документы последовательно в память и обновлять индексы и другую бухгалтерию за одну операцию.

Аналогичная вещь происходит с обновлениями, которые затрагивают более одного документа: обновление будет проходить по индексу только один раз и обновлять объекты по мере их обнаружения.

Отправка нескольких критериев с несколькими критериями не может выиграть ни от одной из этих оптимизаций. Каждый критерий означает отдельный запрос, как если бы вы выпускали каждое обновление отдельно. Единственным возможным преимуществом будет отправка немного меньшего количества байтов по соединению. Базе данных все равно придется выполнять каждый запрос отдельно и обновлять каждый документ отдельно.

Все, что могло бы произойти, это то, что Mongo поместит обновления в очередь внутри и выполнит их последовательно (поскольку одновременно может произойти только одно обновление), это точно так же, как если бы все обновления отправлялись отдельно.

Маловероятно, что накладные расходы при отправке запросов по отдельности будут значительными, глобальная блокировка записи Mongo в любом случае будет ограничивающим фактором.

Комментарии:

1. Я думаю, вы забыли: массовая вставка уменьшает количество обходов сервера. Массовое обновление сделало бы то же самое.

2. В некоторых случаях это может быть фактором, но в общем случае добавленные обходы не являются проблемой из-за глобальной блокировки записи. Для многих других баз данных вы совершенно правы, и в будущем это может быть верно и для Mongo.