Как суммировать значение ключа по всем документам в коллекции MongoDB
У меня есть коллекция в MongoDB:
{ "_id" : ObjectId("4d2407265ff08824e3000001"), "subida" : 3.95 }
{ "_id" : ObjectId("4d2551b4ae9fa739640df821"), "subida" : 6.03 }
{ "_id" : ObjectId("4d255b115ff08821c2000001"), "subida" : 5.53 }
{ "_id" : ObjectId("4d25e8d55ff08814f8000001"), "subida" : 1.96 }
Как я могу суммировать значение ключа, например "subida"
, по всем документам? С приведенными выше документами я должен получить что-то вроде:
{ "subida" : 17.47 }
Ответы
Ответ 1
Я лично выполнил бы mapreduce в коллекции:
map - простая функция, испускающая поле "субида". Ключ должен совпадать, если вам нужна одна сумма; результат после уменьшения приведет к единому объекту {<key>: <sum>}
, причем <key>
будет любым значением, которое вы предоставили в испускании.
map = function() { emit(<key>, this.subida); }
уменьшить также простую функцию, суммирующую их:
red = function(k, v) {
var i, sum = 0;
for (i in v) {
sum += v[i];
}
return sum;
}
Затем вы можете вызвать mapreduce в своей коллекции <mycollection>
:
res = db.<mycollection>.mapReduce(map, red);
Что создаст временную новую коллекцию, которую вы можете манипулировать, как и любая другая коллекция. Значение, возвращаемое mapReduce, содержит несколько значений в отношении mapReduce, таких как время, статус..., а также временные параметры. имя коллекции, созданное в поле "результат".
Чтобы получить нужные значения, вы должны запросить эту коллекцию:
db[res.result].find()
Что должно дать вам объект {<key>: <sum>}
.
Если вы запустите MongoDB 1.7.4 или выше, вы можете немного сэкономить, попросив MongoDB напрямую вернуть результат без создания коллекции:
db.<mycollection>.mapReduce(map, red, {out : {inline: 1}});
Ответ 2
В этом случае агрегация намного проще и намного эффективнее, чем mapReduce:
db.collection.aggregate({
$group: {
_id: '',
subida: { $sum: '$subida' }
}
}, {
$project: {
_id: 0,
subida: '$subida'
}
})
- использовать $group с $sum для вычисления суммы
- использовать проектор $project для удаления ключа id, требуемого оператором $group
Ответ 3
Вариант 0: используйте конвейер агрегации MongoDB
[NB: эта опция была добавлена долго после того, как этот вопрос был задан, но теперь это правильный подход)
Вариант 1. Запросите все записи, верните только поле субиды из Mongo и добавьте их, итерации по стороне клиента Mongo.
Вариант 2: напишите команду уменьшения карты, которая испускает только поле subdia (тот же ключ для всех), а затем команду уменьшения, которая их суммирует.
Вариант 3: используйте db.eval для запуска javascript на сервере: http://www.mongodb.org/display/DOCS/Server-side+Code+Execution
Вариант 4: накапливайте значения "субида", когда вы вставляете значения в свою коллекцию, чтобы у вас была актуальная сумма под рукой, когда вам это нужно. Вы можете сохранить общее количество в другом документе и использовать атомарные обновления для текущих операций: http://www.mongodb.org/display/DOCS/Atomic+Operations
Ответ 4
Вы можете использовать коллекцию как массив, просто добавив значения в цикл.
Изменить: Да, это плохая практика, когда большой набор данных.
Ответ 5
Используйте этот самый простой запрос, чтобы получить сумму результата
db.collection.aggregate({
$group: {
_id: '',
subida: { $sum: '$subida' }
}
}
)