Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map/Reduce task in MongoDB: Aggregation of nested objects

I have a collection with let's say the following content:

{
    "_id":ObjectId("5051c4778ec2487f7c000001"),
    "user_id":"978956784678",
    "likes":{
        "data":[
            {
                "name":"Store 1",
                "category":"Retail and consumer merchandise",
                "id":"354412263434",
                "created_time":"2012-09-07T11:36:05+0000"
            },
            {
                "name":"Store 2",
                "category":"Retail and consumer merchandise",
                "id":"293088074081904",
                "created_time":"2012-08-13T20:06:49+0000"
            }
        ],
        "paging":{
            "next":"https://test.com/next"
        }
    }
}

I am trying to build a Map/Reduce or aggregation in MongoDB to give me the following output (schematically):

user_id, category, "Count of likes"

Somehow I don't find an appropriate solution... What I got so far is an total aggregation of the category likes, but not per user_id:

db.runCommand({ 
mapreduce: "likes",
map: function() { 
    this.likes.data.forEach(
       function(z){
            emit( z.category , { count : 1 } );
        }
    );
},
reduce: function(key, values) {
    var total = 0;
    for ( var i=0; i<values.length; i++ )
        total += values[i].count;
    return { count : total };
},
out: 'result3',
verbose: true
});

Can somebody give me a hint? Help is much appreciated!

Tobi

like image 839
Tobi Avatar asked Mar 24 '26 20:03

Tobi


1 Answers

If possible, I would recommend using the new aggregation framework, which comes with MongoDB version 2.2, the newest stable release. The aggregation framework is written in C++ rather than Javascript, and should have better performance for many aggregation commands.

The following aggregate() counts the number of likes per category, per user. Please let me know if this is not the desired output.

Command:

    db.collection.aggregate(
        { $unwind : "$likes.data" }, 
        { $group : 
           {
             _id: {user: "$user_id", category: "$likes.data.category"}, 
             count: {$sum:1}
           }
        }
   );

Result:

{
    "result" : [
        {
            "_id" : {
                "user" : "978956784678",
                "category" : "Retail and consumer merchandise"
            },
            "count" : 2
        }
    ],
    "ok" : 1
}
like image 68
Jenna Avatar answered Mar 26 '26 14:03

Jenna



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!