Potresti facilmente aggregare il risultato, invece di optare per una soluzione di riduzione della mappa:
-
Matchi record in cui la data è maggiore di uguale alla data specificata. -
Groupin base abrand_idcampo. -
Usa $addToSet operatore per mantenere un
productselenco diproduct_idunivoci per ogni gruppo. -
Projectilcountdeiproductsarray in ogni chiave.
Codice:
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"}}}
])
Venendo alla tua soluzione di riduzione della mappa,
Questo è un modo in cui mongodb può invocare la funzione di riduzione per ogni gruppo. Dai documenti :
Devi apportare alcune modifiche alla tua map ,reduce funzioni e aggiungi un nuovo finalize funzione:
- Devi ricordarlo quando
mongodbinvoca ilreducefunzione per la stessa chiave più di una volta, il risultato dell'invocazione precedente viene passato come input alla funzione di riduzione, insieme agli altri valori alla successiva chiamata della funzione di riduzione. - Primo punto, quindi devi assicurarti che l'input della funzione reduce e il valore restituito dalla funzione reduce siano costruiti in modo simile, in modo che la logica scritta all'interno della funzione reduce possa adattarsi all'elaborazione del proprio valore restituito nelle sue precedenti chiamate.
- Dato che non saremmo in grado di recuperare il conteggio di valori distinti quando vengono chiamati in batch, ciò che possiamo fare è scrivere un
reducefunzione che accumula i distintiproduct_idsper ogni chiave e scrivere unfinalizefunzione che calcola il conteggio di quei valori univoci.
Codice:
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;
}
}
)