2011-01-06 157 views
32

tengo colección en MongoDB:Cómo sumar el valor de una clave en todos los documentos en una colección 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 } 

cómo puedo sumar el valor de una clave, por ejemplo, "subida", en todos los documentos? Con los anteriores documentos, que debería recibir algo a lo largo de las líneas de:

{ "subida" : 17.47 } 

Respuesta

15

Personalmente me realizo una mapreduce en la colección:

mapa es una función simple que emite el campo "subida". La clave debería ser la misma si necesita una sola suma; el resultado después de reducir arrojará el único objeto {<key>: <sum>}, siendo <key> el valor que haya proporcionado en la emisión.

map = function() { emit(<key>, this.subida); } 

reducir también es una función simple sumándolos:

red = function(k, v) { 
    var i, sum = 0; 
    for (i in v) { 
    sum += v[i]; 
    } 
    return sum; 
} 

A continuación, puede llamar mapreduce en su colección <mycollection>:

res = db.<mycollection>.mapReduce(map, red); 

que va a crear una nueva colección temporal se puede manipular como cualquier otra colección El valor devuelto por mapReduce contiene varios valores con respecto al mapReduce, como el tiempo empleado, el estado ..., así como la temperatura. nombre de la colección creado en el campo "resultado". para obtener los valores que necesita, usted tiene que consultar esa colección:

db[res.result].find() 

que debe dar el objeto {<key>: <sum>}.

Si ejecuta MongoDB 1.7.4 o superior, se puede ahorrar un poco de molestia preguntando MongoDB vuelta el resultado directamente sin crear una colección:

db.<mycollection>.mapReduce(map, red, {out : {inline: 1}}); 
+0

Muchas gracias amigo, finalmente puedo hacer esta consulta, funciona perfectamente en mongo shell. Fui implementado en python en mi aplicación ... Ahora veo que mongodb map/reduce consultas no son iguales a CouchDB map/reduce consultas ... LOL: D – JAM

+1

esta es la consulta implementada en python http://pastebin.com/du8yrk3p: D – JAM

+0

¿Te interesa por qué elegir mapreduce sobre agregación? – UpTheCreek

5

Opción 0: Usar la MongoDB aggregation pipeline
[Nota: esta opción se añadió un largo tiempo después de esta pregunta fue hecha, pero es el enfoque en este momento ]


Opción 1: Consulta todos los registros, devolver sólo el campo de subida de Mongo y sumarlos iterando sobre el lado del cliente cursor Mongo.

Opción 2: escribir un comando map reduce que emite solo el campo de subdiadia (misma clave para todos) y luego un comando de reducción que los totaliza.

Opción 3: Uso db.eval para ejecutar JavaScript en el servidor: http://www.mongodb.org/display/DOCS/Server-side+Code+Execution

Opción 4: Acumular valores 'Subida' a medida que inserta valores en su colección para que tenga un total de hasta a la fecha a las mano siempre que lo necesites. Puede almacenar el total en un documento diferente y usar operaciones atómicas de "actualización si es actual" para actualizarlo: http://www.mongodb.org/display/DOCS/Atomic+Operations

+0

¿Algún ejemplo será más vivo y fácil de entender? – Eddy

+0

La opción 1 causará problemas de rendimiento a medida que crezca su información –

0

Puede usar la colección como una matriz, solo agregue los valores en un bucle.

Editar: Sí, esta es una mala práctica cuando se tiene un gran conjunto de datos.

+6

mala práctica en grandes conjuntos de fechas – sinoohe

93

En este caso, la agregación es mucho más simple y mucho más eficiente que MapReduce:

db.collection.aggregate({ 
    $group: { 
     _id: '', 
     subida: { $sum: '$subida' } 
    } 
}, { 
    $project: { 
     _id: 0, 
     subida: '$subida' 
    } 
}) 
  1. uso del grupo $ $ con suma para calcular la suma
  2. operador proyecto de $
  3. uso de proyección al retirar la llave de identificación requerida por el operador de grupo $
+2

Este método es mucho MUCHO más eficiente que la implementación actual de Map/Reduce – rdrkt

+0

+1 excelente respuesta. Me estaba equivocando al usar {"$ sum": {"subida": 1}} –

+1

Shamt that Spring DB aún no es compatible con el framework de agregación :( – will824

Cuestiones relacionadas