Podría agregar fácilmente el resultado, en lugar de optar por una solución de reducción de mapas:
-
Match
los registros donde la fecha es mayor que igual a la fecha especificada. -
Group
basado en elbrand_id
campo. -
Use el $addToSet operador para mantener un
products
lista deproduct_id
únicos para cada grupo. -
Project
elcount
de losproducts
matriz en cada tecla.
Código:
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"}}}
])
Llegando a su solución de reducción de mapas,
Esa es una forma en que mongodb puede invocar la función de reducción para cada grupo. De los docs :
Necesitas hacer alguna modificación a tu map
,reduce
funciones y agregar un nuevo finalize
función:
- Debe recordar que cuando
mongodb
invoca elreduce
función para la misma clave más de una vez, el resultado de la invocación anterior se pasa como entrada a la función reduce, junto con los otros valores la próxima vez que se invoca la función reduce. - Primer punto, por lo que debe asegurarse de que la entrada a la función de reducción y el valor de retorno de la función de reducción estén construidos de manera similar, de modo que la lógica escrita dentro de la función de reducción pueda acomodar el procesamiento de su propio valor devuelto en sus llamadas anteriores.
- Dado que no podríamos recuperar el recuento de valores distintos cuando se llaman por lotes, lo que podemos hacer es escribir un
reduce
función que acumula los distintosproduct_ids
para cada tecla y escriba unfinalize
función que calcula el recuento de esos valores únicos.
Código:
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;
}
}
)