Vous pourriez facilement agréger le résultat, au lieu d'opter pour une solution de map-reduce :
-
Match
les enregistrements dont la date est supérieure ou égale à la date spécifiée. -
Group
basé sur lebrand_id
champ. -
Utilisez le $addToSet opérateur pour maintenir un
products
liste desproduct_id
uniques pour chaque groupe. -
Project
lecount
desproducts
tableau dans chaque clé.
Code :
db.collection.aggregate([
{$match:{"date":{$gte:new Date('2014-11-20')}}},
{$group:{"_id":"$brand_id","products":{$addToSet:"$product_id"}}},
{$project:{"_id":0,"brand_id":"$_id","distinct_prod":{$size:"$products"}}}
])
En venant à votre solution de réduction de carte,
C'est une façon pour mongodb d'invoquer la fonction reduce pour chaque groupe. À partir de la documentation :
Vous devez apporter quelques modifications à votre map
,reduce
fonctions et ajouter un nouveau finalize
fonction :
- Vous devez vous rappeler que lorsque
mongodb
invoque lereduce
fonction pour la même clé plus d'une fois, le résultat de l'invocation précédente est transmis en tant qu'entrée à la fonction reduce, avec les autres valeurs la prochaine fois que la fonction reduce est appelée. - Premier point, vous devez donc vous assurer que l'entrée de la fonction reduce et la valeur de retour de la fonction reduce sont construites de la même manière, de sorte que la logique écrite à l'intérieur de la fonction reduce puisse s'adapter au traitement de sa propre valeur retournée dans ses appels précédents.
- Puisque nous ne serions pas en mesure de récupérer le nombre de valeurs distinctes lorsqu'elles sont appelées par lots, ce que nous pouvons faire est d'écrire un
reduce
fonction qui accumule lesproduct_ids
distincts pour chaque clé et écrivez unfinalize
fonction qui calcule le nombre de ces valeurs uniques.
Code :
db.collection.mapReduce(
function() {
// emitting the same structure returned by the reduce function.
emit(this.brand_id, {"prod_id":[this.product_id]});
},
function(key, values) {
// the return value would be a list of unique product_ids.
var res = {"prod_id":[]};
for(var i=0;i<values.length;i++)
{
for(var j=0;j<values[i].prod_id.length;j++){
if(res.prod_id.indexOf(values[i].prod_id[j]) == -1){
res.prod_id.push(values[i].prod_id[j]);
}
}}
return res;
},
{
query: {date: {$gte: new Date('2014-11-20')}},
out: "example",
finalize: function(key, reducedValue){
// it returns just the count
return reducedValue.prod_id.length;
}
}
)