Как суммировать значение ключа во всех документах в коллекции MongoDB - PullRequest
39 голосов
/ 07 января 2011

У меня есть коллекция в 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 }

Ответы [ 5 ]

115 голосов
/ 14 декабря 2012

В этом случае агрегирование намного проще и эффективнее, чем mapReduce:

db.collection.aggregate({
    $group: {
        _id: '',
        subida: { $sum: '$subida' }
    }
 }, {
    $project: {
        _id: 0,
        subida: '$subida'
    }
})
  1. использовать $ group с $ sum для вычисления суммы
  2. использовать оператор проекции $ projectудалить ключ идентификатора, требуемый оператором $ group
16 голосов
/ 07 января 2011

Я бы лично выполнил mapreduce для коллекции:

map - это простая функция, генерирующая поле "subida".Ключ должен быть таким же, если вам нужна единственная сумма;В результате после сокращения будет получен единственный объект {<key>: <sum>}, где <key> будет любым значением, которое вы указали в emit.

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}});
6 голосов
/ 07 января 2011

Опция 0: использовать конвейер агрегации MongoDB
[NB: эта опция была добавлена ​​долгое время после того, как этот вопрос был задан, но сейчас это правильный подход]


Вариант 1: запросить все записи, вернуть только поле subida из Mongo и сложить их, выполнив итерации по клиентской стороне курсора Mongo.

Вариант 2: Напишите команду уменьшения карты, которая генерирует только поле subdia (один и тот же ключ для всех), а затем команду уменьшения, которая их суммирует.

Вариант 3: Используйте db.eval для запуска javascript на сервере: http://www.mongodb.org/display/DOCS/Server-side+Code+Execution

Вариант 4: накапливайте значения «subida» по мере того, как вы вставляете значения в свою коллекцию, так что у вас есть актуальная сумма под рукой, когда вам это нужно. Вы можете сохранить итоговую сумму в другом документе и использовать атомарные операции «обновить, если текущие» для ее обновления: http://www.mongodb.org/display/DOCS/Atomic+Operations

0 голосов
/ 21 мая 2019

Используйте этот самый простой запрос, чтобы получить сумму результата

db.collection.aggregate({
    $group: {
        _id: '',
        subida: { $sum: '$subida' }
    }
 }
)
0 голосов
/ 07 января 2011

Вы можете использовать коллекцию как массив, просто добавьте значения в цикл.

Редактировать : Да, это плохая практика при наличии большого набора данных.

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