MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

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

Vous pourriez facilement agréger le résultat, au lieu d'opter pour une solution de map-reduce :

  • Match les enregistrements dont la date est supérieure ou égale à la date spécifiée.

  • Group basé sur le brand_id champ.

  • Utilisez le $addToSet opérateur pour maintenir un products liste des product_id uniques pour chaque groupe.

  • Project le count des products tableau dans chaque clé.

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

En venant à votre solution de réduction de carte,

C'est une façon pour mongodb d'invoquer la fonction reduce pour chaque groupe. À partir de la documentation :

Vous devez apporter quelques modifications à votre map ,reduce fonctions et ajouter un nouveau finalize fonction :

  • Vous devez vous rappeler que lorsque mongodb invoque le reduce fonction pour la même clé plus d'une fois, le résultat de l'invocation précédente est transmis en tant qu'entrée à la fonction reduce, avec les autres valeurs la prochaine fois que la fonction reduce est appelée.
  • Premier point, vous devez donc vous assurer que l'entrée de la fonction reduce et la valeur de retour de la fonction reduce sont construites de la même manière, de sorte que la logique écrite à l'intérieur de la fonction reduce puisse s'adapter au traitement de sa propre valeur retournée dans ses appels précédents.
  • Puisque nous ne serions pas en mesure de récupérer le nombre de valeurs distinctes lorsqu'elles sont appelées par lots, ce que nous pouvons faire est d'écrire un reduce fonction qui accumule les product_ids distincts pour chaque clé et écrivez un finalize fonction qui calcule le nombre de ces valeurs uniques.

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