MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

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


Você pode agregar facilmente o resultado, em vez de optar por uma solução de redução de mapa:

  • Match os registros onde a data é maior que igual à data especificada.

  • Group com base no brand_id campo.

  • Use o $addToSet operador para manter um products lista deproduct_id exclusivos para cada grupo.

  • Project a count dos products matriz em cada chave.

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"}}}
])

Chegando à sua solução de redução de mapas,

Essa é uma maneira que o mongodb pode invocar a função de redução para cada grupo. Dos documentos :

Você precisa fazer alguma modificação em seu map ,reduce funções e adicione um novo finalize função:
  • Você precisa se lembrar disso quando mongodb invoca o reduce função para a mesma chave mais de uma vez, o resultado da invocação anterior é passado como uma entrada para a função de redução, juntamente com os outros valores na próxima vez que a função de redução for invocada.
  • Primeiro ponto, então você precisa garantir que a entrada para a função reduce e o valor de retorno da função reduce sejam construídos de forma semelhante, para que a lógica escrita dentro da função reduce possa acomodar o processamento de seu próprio valor retornado em suas chamadas anteriores.
  • l>
  • Como não poderíamos recuperar a contagem de valores distintos quando chamados em lotes, o que podemos fazer é escrever um reduce função que acumula os distintos product_ids para cada chave e escreva umfinalize função que calcula a contagem desses valores exclusivos.

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;
        }
    }
)