Mongo聚合使用多个group by计算键的出现次数

时间:2014-01-09 11:08:31

标签: mongodb aggregation-framework

假设我的mongo架构如下所示:

db.events = [
{
    "_id" : ObjectId("528cb8f06e95520dd7000004"),
    "user_id" : "1",
    "event_name" : "view",
    "product_id" : 20
},
{
    "_id" : ObjectId("528cb8f06e95520dd7000004"),
    "user_id" : "1",
    "event_name" : "like",
    "product_id" : 20
},
{
    "_id" : ObjectId("528cb8f06e95520dd7000004"),
    "user_id" : "2",
    "event_name" : "view",
    "product_id" : 20
},
{
    "_id" : ObjectId("528cb8f06e95520dd7000004"),
    "user_id" : "1",
    "event_name" : "buy",
    "product_id" : 21
}

]

我想输出每个事件的计数,按用户和产品分组,例如:

[
    { 
        "user_id" : 1,
        "product_id" : 20,
        "view_count" : 1,
        "buy_count" : 0,
        "like_count" :  1,
    },
    {
        "user_id" : 1,
        "product_id" : 21,
        "view_count" : 0,
        "buy_count" : 1,
        "like_count" :  0,
    },
    {
        "user_id" : 2,
        "product_id" : 20,
        "view_count" : 1,
        "buy_count" : 0,
        "like_count" :  0,
    }

]

我陷入了最后一步,即“合并”一行中每个事件的计数。到目前为止我的解决方案:

db.events.aggregate([
    { $group: {             // Group users and products, collects event names
        _id: { user_id: '$user_id', product_id: '$product_id' },
        events: { $addToSet: "$event_name" }

    }},
    { $unwind : "$events" },    // unwind the events as document stream so they can be counted
    { $group : {                // group and count by event name 
        _id : { user: "$_id.user_id", product: "$_id.product_id", action: "$events" },
        count: { $sum: 1 }
    }},
    { $project: {   // rename some attributes...
        _id: 0,
        user_id: '$_id.user',
    product_id: '$_id.product',
    event_name: '$_id.action',
        event_count: '$count'
    }},
    { $group : {    // finally group everything in one row
        _id : { user: "$user_id", product: "$product_id"},
       "$event_name" : { $sum: "$actions_with" } // ERROR group aggregate field name '$event_name' cannot be an operator name"
    }}

    ]
);

1 个答案:

答案 0 :(得分:8)

对此的聚合查询非常简单:

db.test.aggregate( [
    { $group: {
        '_id' : { user_id: '$user_id', product_id: '$product_id' },
        view_count: { $sum: {
            $cond: [ { $eq: [ '$event_name', 'view' ] }, 1, 0 ]
        } },
        like_count: { $sum: {
            $cond: [ { $eq: [ '$event_name', 'like' ] }, 1, 0 ]
        } },
        buy_count: { $sum: {
            $cond: [ { $eq: [ '$event_name', 'buy' ] }, 1, 0 ]
        } },
    } },
    { $project: {
        _id: 0,
        user_id: '$_id.user_id',
        product_id: '$_id.product_id',
        view_count: 1,
        like_count: 1,
        buy_count: 1
    } }
] );

然而,没有方法可以将任意数量的键(操作)分组 - 您的聚合查询需要全部指定它们。