MongoDB, условные взлеты или обновления

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

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))

Возможно ли это эффективно?

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

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 для каждого отдельного обновления, которое, я считаю, не является эффективным способом?

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

Ответ 1

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

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

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

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

Ответ 2

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

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

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

Возможно ли это эффективно?

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

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

$set только при вставке, добавить только тогда, когда не существует, push и set в то же время, скопируйте "размер" с помощью $addToSet.

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