MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

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

Sie könnten das Ergebnis einfach aggregieren, anstatt sich für eine Map-Reduce-Lösung zu entscheiden:

  • Match die Datensätze, bei denen das Datum größer als gleich dem angegebenen Datum ist.

  • Group basierend auf der brand_id Feld.

  • Verwenden Sie $addToSet Betreiber zur Pflege eines products Liste der eindeutigen product_id für jede Gruppe.

  • Project die count der products Array in jedem Schlüssel.

Code:

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

Kommen wir zu Ihrer Map-Reduce-Lösung,

Auf diese Weise kann mongodb die Reduce-Funktion für jede Gruppe aufrufen. Aus den docs :

Sie müssen einige Änderungen an Ihrer map vornehmen ,reduce Funktionen und füge ein neues finalize hinzu Funktion:

  • Daran müssen Sie denken, wenn mongodb ruft das reduce auf Funktion für denselben Schlüssel mehr als einmal ausführen, wird das Ergebnis des vorherigen Aufrufs zusammen mit den anderen Werten als Eingabe an die Reduce-Funktion übergeben, wenn die Reduce-Funktion das nächste Mal aufgerufen wird.
  • Erster Punkt:Sie müssen also sicherstellen, dass die Eingabe für die Reduce-Funktion und der Rückgabewert der Reduce-Funktion ähnlich aufgebaut sind, sodass die in der Reduce-Funktion geschriebene Logik ihren eigenen zurückgegebenen Wert in ihren vorherigen Aufrufen verarbeiten kann.
  • Da wir nicht in der Lage wären, die Anzahl der unterschiedlichen Werte abzurufen, wenn sie in Stapeln aufgerufen werden, können wir ein reduce schreiben Funktion, die die unterschiedlichen product_ids akkumuliert für jeden Schlüssel und schreibe einfinalize Funktion, die die Anzahl dieser eindeutigen Werte berechnet.

Code:

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