MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

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

Potresti facilmente aggregare il risultato, invece di optare per una soluzione di riduzione della mappa:

  • Match i record in cui la data è maggiore di uguale alla data specificata.

  • Group in base a brand_id campo.

  • Usa $addToSet operatore per mantenere un products elenco di product_id univoci per ogni gruppo.

  • Project il count dei products array 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 mongodb invoca il reduce funzione 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 reduce funzione che accumula i distinti product_ids per ogni chiave e scrivere unfinalize funzione 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;
        }
    }
)