MongoDb根据值聚合并分组两个字段

时间:2014-10-21 21:54:28

标签: mongodb mongodb-query aggregation-framework

我希望在给出类型的集合上进行聚合。如果类型为 foo ,我想按作者字段进行分组,如果类型为,我想按用户<进行分组/强>

所有这些都应该在一个查询中发生。

示例数据:

{
   "_id": 1,
   "author": {
     "someField": "abc",
  },
   "type": "foo" 
}

{
   "_id": 2,
   "author": {
     "someField": "abc",
  },
   "type": "foo" 
}

{
   "_id": 3,
   "user": {
     "someField": "abc",
  },
   "type": "bar" 
}

如果类型为 bar ,则此用户字段仅存在。

所以基本上就是这样...试图用$or来表达它。

function () { 
var results = db.vote.aggregate( [ 
   { $or: [ {

      { $match : { type : "foo" } },
      { $group :    { _id : "$author", sumAuthor : {$sum : 1} } } },

      { { $match : { type : "bar" } },
      { $group : { _id : "$user", sumUser : {$sum : 1} } } 
   } ] }
] );
return results;
}

有人有一个很好的解决方案吗?

3 个答案:

答案 0 :(得分:2)

我认为可以通过

来完成
db.c.aggregate([{
    $group : {
        _id : {
            $cond : [{
                $eq : [ "$type", "foo"]
            }, "author", "user"]
        },
        sum : {
            $sum : 1
        }
    }
}]);

答案 1 :(得分:0)

下面的解决方案可以稍微清理一下......

对于“bar”(注意:对于“foo”,你必须改变一点)

    db.vote.aggregate(
        {
            $project:{
                user:{ $ifNull: ["$user", "notbar"]},
                type:1
            }
        },
        {
            $group:{
                _id:{_id:"$user.someField"},
                sumUser:{$sum:1}
            }
        }
    )

另请注意:在最终答案中,任何非“bar”类型的内容都将具有_id = null

答案 2 :(得分:0)

这里你想要的是$cond运算符,它是一个三元运算符,返回条件为真或假的特定值。

db.vote.aggregate([
    { "$group": {
        "_id": null,
        "sumUser": { 
            "$sum": {
                "$cond": [ { "$eq": [ "$type", "user" ] }, 1, 0 ]
            }
        },
        "sumAuhtor": { 
            "$sum": {
                "$cond": [ { "$eq": [ "$type", "auhtor" ] }, 1, 0 ]
            }
        }
    }}
])

这基本上测试&#34;类型&#34;当前文档,并决定是否将10传递给$sum操作。

这也可以避免错误的分组,如果&#34;用户&#34;和&#34;作者&#34;字段包含与示例中相同的值。最终结果是一个包含两种类型计数的单个文档。