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 кажется самым близким к тому, что вы хотите.