2011-01-06 6 views
32

Je collection MongoDB:Comment résumer la valeur d'une clé dans tous les documents dans une collection 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 } 

Comment je peux résumer la valeur d'une clé, par exemple, "subida", dans tous les documents? Avec les documents ci-dessus, je recevoir quelque chose le long des lignes de:

{ "subida" : 17.47 } 

Répondre

15

personnellement j'effectue une MapReduce sur la collection:

carte

est une fonction simple émettant le champ « Subida ». La clé devrait être la même si vous avez besoin d'une somme unique; le résultat après réduire donnera l'objet unique {<key>: <sum>}, avec <key> étant la valeur que vous avez fournie dans l'émission.

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

réduire est également une fonction simple en les sommant:

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

Vous pouvez ensuite appeler MapReduce sur votre collection <mycollection>:

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

qui va créer une nouvelle collection temporaire vous pouvez manipuler comme toute autre collection. La valeur renvoyée par mapReduce contient plusieurs valeurs concernant mapReduce telles que le temps pris, le statut ..., ainsi que le temp. nom de collection créé dans le champ "résultat". Pour obtenir les valeurs dont vous avez besoin, vous devez interroger cette collection:

db[res.result].find() 

qui devrait vous donner l'objet {<key>: <sum>}.

Si vous exécutez MongoDB 1.7.4 ou plus, vous pouvez vous faire économiser un peu de tracas en demandant MongoDB pour retourner le résultat directement sans créer une collection:

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

Merci beaucoup ami, je peux enfin faire cette requête, fonctionne parfaitement dans mongo shell. J'ai été implémenté en python dans mon application ... Je vois maintenant que les requêtes mongodb map/reduce ne sont pas égales à CouchDB map/reduce queries ... LOL: D – JAM

+1

c'est la requête implémentée en python http://pastebin.com/du8yrk3p: D – JAM

+0

Juste intéressé pourquoi vous choisiriez mapreduce au-dessus de l'agrégation? – UpTheCreek

5

Option 0: Utilisez le MongoDB aggregation pipeline
[NB: cette option a été ajoutée longtemps après cette question a été posée mais l'approche en ce moment ]


Option 1: Interroger tous les enregistrements, retourner seul le champ Subida de Mongo et les ajouter par itérer sur le côté client du curseur Mongo.

Option 2: Écrivez une commande map reduce qui n'émet que le champ subdia (même clé pour tous) et ensuite une commande reduce qui les totalise.

Option 3: Utilisez db.eval javascript pour exécuter sur le serveur: http://www.mongodb.org/display/DOCS/Server-side+Code+Execution

Option 4: Les valeurs Accumulez « Subida » que vous insérez des valeurs dans votre collection afin que vous ayez un total de mise à jour à main quand vous en avez besoin. Vous pouvez stocker le total dans un document différent et utiliser les opérations atomiques "update if current" pour le mettre à jour: http://www.mongodb.org/display/DOCS/Atomic+Operations

+0

N'importe quel exemple sera plus vivant et facile à comprendre? – Eddy

+0

L'option 1 causera des problèmes de performance à mesure que vos données augmentent –

0

Vous pouvez utiliser la collection sous forme de tableau, ajoutez simplement les valeurs dans une boucle.

Modifier: Oui, ceci est une mauvaise pratique lorsque vous avez un grand ensemble de données.

+6

mauvaise pratique sur les grandes dates – sinoohe

93

Dans ce cas, l'agrégation est beaucoup plus simple et beaucoup plus efficace que MapReduce:

db.collection.aggregate({ 
    $group: { 
     _id: '', 
     subida: { $sum: '$subida' } 
    } 
}, { 
    $project: { 
     _id: 0, 
     subida: '$subida' 
    } 
}) 
  1. utilisation groupe $ avec la somme de $ pour calculer la somme
  2. opérateur de projection d'utilisation du projet $ pour retirer la clé id requis par l'opérateur de groupe $
+2

Cette méthode est beaucoup plus efficace que l'implémentation actuelle de Map/Reduce – rdrkt

+0

+1 excellente réponse. Je me trompais avec l'utilisation de {"$ sum": {"subida": 1}} –

+1

Shamt que Spring DB ne supporte pas encore le framework d'agrégation :( – will824

Questions connexes