web-dev-qa-db-fra.com

Comment additionner la valeur d'une clé dans tous les documents d'une collection MongoDB

J'ai collection dans 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 puis-je additionner la valeur d'une clé, par exemple "subida", dans tous les documents? Avec les documents ci-dessus, je devrais recevoir quelque chose comme:

{ "subida" : 17.47 }
37
JAM

Je personnellement effectuer une mapreduce sur la collection:

map 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éduction donnera l'objet unique {<key>: <sum>}, <key> étant la valeur que vous avez fournie dans l'émission.

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

réduire est aussi une simple fonction qui les résume:

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);

Ce qui créera une nouvelle collection temporaire que vous pourrez manipuler comme toute autre collection. La valeur renvoyée par mapReduce contient plusieurs valeurs concernant mapReduce, telles que la durée, l'état ..., ainsi que la température. nom de la collection créé dans le champ "résultat" . Pour obtenir les valeurs dont vous avez besoin, vous devez interroger cette collection:

db[res.result].find()

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

Si vous exécutez MongoDB version 1.7.4 ou supérieure, vous pouvez gagner du temps en demandant à MongoDB de renvoyer le résultat directement sans créer de collection:

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

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. utiliser $ group avec $ sum pour calculer la somme
  2. utiliser l'opérateur $ project de projection pour supprimer la clé d'identification requise par l'opérateur $ group
111
Ilya Builuk

Option 0: Utiliser le pipeline d'agrégation MongoDB
[NB: cette option a été ajoutée longtemps après que cette question a été posée, mais est la bonne approche maintenant]


Option 1: Interroger tous les enregistrements, renvoyer uniquement le champ subida de Mongo et les additionner en effectuant une itération sur le côté client du curseur Mongo.

Option 2: écrivez une commande de réduction de mappe qui n’émet que le champ de sous-tableau (la même clé pour tous), puis une commande de réduction qui les totalise.

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

Option 4: Cumulez les valeurs 'subida' au fur et à mesure que vous insérez des valeurs dans votre collection afin d'avoir un total à jour à portée de main chaque fois que vous en aurez besoin. Vous pouvez stocker le total dans un autre document et utiliser les opérations atomiques "update if current" pour le mettre à jour: http://www.mongodb.org/display/DOCS/Atomic+Operations

6
Ian Mercer

Vous pouvez utiliser la collection comme un tableau, ajoutez simplement les valeurs dans une boucle.

Edit : Oui, c'est une mauvaise pratique lorsque vous avez un grand jeu de données.

0
oscarcardoso