2011-01-06 4 views
32

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

ответ

15

Я лично выполнить MapReduce на коллекции:

карта является простой функцией испуская поле «subida». Ключ должен совпадать, если вам нужна одна сумма; результат после уменьшения даст единственный объект {<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}}); 
+0

Большое спасибо, я могу, наконец, сделать этот запрос, отлично работает в оболочке mongo. Я был реализован в python в своем приложении ... Теперь я вижу, что mongodb map/reduce query не равны CouchDB карте/уменьшению запросов ... LOL: D – JAM

+1

это запрос, реализованный в python http://pastebin.com/du8yrk3p: D – JAM

+0

Просто интересно, почему вы выбрали mapreduce over aggregation? – UpTheCreek

5

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


Вариант 1: Запрос всех записей, возвращать только поле subida из Монго и добавить их на итерации стороны клиента курсор Монго.

Вариант 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

Любой пример будет более живым и понятным? – Eddy

+0

Вариант 1 вызовет проблемы с производительностью, так как ваши данные растут –

0

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

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

+6

Плохая практика в больших датах – sinoohe

93

В этом случае агрегация гораздо проще и гораздо эффективнее, чем MapReduce:

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

Этот метод намного эффективнее, чем текущая реализация Map/Reduce – rdrkt

+0

+1 отличный ответ. Я ошибался в использовании {"$ sum": {"subida": 1}} –

+1

Shamt, что Spring DB еще не поддерживает структуру агрегации :( – will824

Смежные вопросы