sql >> Base de Datos >  >> NoSQL >> MongoDB

Mongo Map-Reduce To Mimic count(distinct(...)) group by en SQL

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 el brand_id campo.

  • Use el $addToSet operador para mantener un products lista de product_id únicos para cada grupo.

  • Project el count de los products 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 el reduce 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 distintos product_ids para cada tecla y escriba un finalize 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;
        }
    }
)