MongoDB, условные обновления или обновления - PullRequest
13 голосов
/ 04 апреля 2011

При использовании MongoDB я в настоящее время делаю условное обновление как часть процесса агрегирования в форме (упрощенно):

db.dbname.update({attr1 : value1, attr2 : value2},
                 {"$inc" : { avg : current_value, nr : 1}},
                 false (multi), true (upsert))

Но я хочу также сохранить максимальное (и минимальное) значение без необходимости извлечения документа. Что-то вроде:

db.dbname.update({ attr1 : value1, attr2 : value2},
                 {"$inc" : { avg : current_value, nr : 1},
                  "$setIfBigger" : { max : current_value}},
                 false (multi), true (upsert))

Возможно ли это эффективным способом?

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

var obj = db.dbname.findOne({attr1 : value1, attr2 : value2},{_id:1});
if (obj != null) {
   db.dbname.update({attr1 : value1, attr2 : value2},
                    {"$inc" : { avg : current_value, nr : 1},
                     "$set" : { max : (obj.max > current_value ? obj.max : current_value}},
                    false (multi), true (upsert));
} else {
   db.dbname.save({attr1 : value1, attr2 : value2, 
                   avg : current_value, nr : 1,
                   max : current_value});
}

Реальная программа написана на Java и использует mongo-API, а процесс агрегирования довольно сложен и использует методы компоновки, выходящие за рамки Javascript, для взаимодействия с другими серверами, поэтому ergo mapreduce не подходит. Наконец, конечный результат - это огромный набор простых значений, которые я хочу сохранить наиболее эффективным способом, а также сохранить предварительно рассчитанные средние, максимумы и минимумы определенных комбинаций.

Одним из решений является создание уникальных объектов-функций в JS для каждого отдельного обновления, что, по моему мнению, не является эффективным способом?

Основная цель - сократить время, необходимое для выполнения агрегации этого типа, использование полосы пропускания является вторичным.

Ответы [ 2 ]

15 голосов
/ 29 мая 2014

Теперь это можно сделать намного проще в выпуске MongoDB 2.6, который включает Улучшения вставки и обновления .В частности, есть новые операторы $ min и $ max , которые выполняют условное обновление в зависимости от относительного размера указанного значения и текущего значения поля.

Так, например, это обновление:

db.scores.update( { _id: 1 }, { $max: { highScore: 950 } } )

будет условно обновлять указанный документ, если 950 больше текущего значения highScore.

3 голосов
/ 04 апреля 2011

Одним из решений является создание уникальных функциональных объектов в JS для каждого отдельного обновления, что, на мой взгляд, не является эффективным способом?

Может не работать так, как вы хотите:

https://jira.mongodb.org/browse/SERVER-458

Возможно ли это эффективным способом?

Проблема, с которой вы сталкиваетесь, заключается в том, что вы хотите, чтобы MongoDB выполнял переход с более сложной логикой. Таким образом, вы хотите использовать блокировку на уровне документа, чтобы эффективно «запускать» сразу несколько сложных изменений.

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

$set только при вставке , добавление только при отсутствии , push и set одновременно , координата «размер» с $addToSet.

В частности, SERVER-458 кажется наиболее близким к тому, что вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...