2012-12-28 4 views
1

J'ai des documents avec la structure suivante:MongoDB: compter les valeurs de tableau avec MapReduce/agrégation

{ 
    "name" : "John", 
    "items" : [ 
     {"key1" : "value1"}, 
     {"key1" : "value1"} 
    ] 
} 

et ont construit une fonction simple de compter le nombre du total « articles ».

var count = 0; 
db.collection.find({},{items:1}).limit(10000).forEach(
    function (doc) { 
     if(doc.items){ 
       count += doc.items.length; 
     } 
    } 
) 
print(count); 

Mais après ~ 1 million d'éléments, ma fonction se brise, Mongo se ferme. J'ai examiné le nouveau cadre d'agrégation ainsi que les fonctions mapreduce, et je ne suis pas sûr de savoir quel serait le meilleur à utiliser pour un simple compte comme celui-ci.

Suggestions bienvenues! Merci.

+0

Vous obtenez un délai d'attente du curseur prolly sur ce point, si vous deviez exécuter disons 10K comme vous montrez à temps dans une boucle il devrait ouvrir un nouveau curseur chaque fois et ainsi vous ne devriez pas souffrir le problème de dépassement de temps. – Sammaye

Répondre

0

Vous pouvez stocker la longueur de doc.items en tant qu'élément de doc. Cette méthode entraîne une redondance de disque mais constitue un moyen rapide et facile de traiter les grandes collections.

{ 
    "name" : "John", 
    "itemsLength" : 2, 
    "items" : [ 
     {"key1" : "value1"}, 
     {"key1" : "value1"} 
    ] 
} 

Une autre option peut être utilise MapReduce mais, je pense, sans sharding MapReduce serait lente.

+0

La longueur des "éléments" est en train d'être comptée maintenant, mais j'ai encore besoin de compter les documents précédents qui ne l'ont pas encore. –

+0

Vous pouvez mettre à jour les documents précédents pour une fois, afin que tous les documents aient la propriété itemLength. Lorsque tous les documents ont itemLength, vous pouvez agréger avec $ sum. – Muatik

1

Il devient très facile lorsque vous utilisez l'agrégation http://docs.mongodb.org/manual/core/aggregation-pipeline/

db.collection.aggregate(
    { $unwind : "$items" }, 
    { $group : {_id:null, items_count : {$sum:1} }} 
) 

pour retourner le nombre d'éléments pour chaque document,

{ $group : {_id:"$_id", items_count : {$sum:1} }} 
Questions connexes