如何使用MongoDB按数组的第一个元素进行分组?

时间:2015-10-28 10:27:31

标签: mongodb mongodb-query aggregation-framework

我开始学习MongoDB并使用这样的文档:

{
    "_id" : ObjectId("562fac8a4f9ecec40f5b8ff9"),
    "foo" : {
        "objectid" : "39",
        "stuff" : "65" 
    },
    "yearpublished" : [ 
        "1979"
    ],
    "bar": "1263"
}

yearpublished 是一个数组,我想按照此数组中的第一个值对我的集合进行分组,然后计算相关文档的数量。

我已经完成了这个查询:

db.foobar.aggregate(
   [
      {
        $group : {
           _id : '$yearpublished',
           count: { $sum: 1 }
        }
      }
   ]
)

并获得:

{
    "result" : [ 
        {
            "_id" : [ 
                "1923"
            ],
            "count" : 1.0000000000000000
        }, 
        {
            "_id" : [ 
                "1864"
            ],
            "count" : 1.0000000000000000
        }
}

但我正在寻找这种结果(即仅限第一个元素):

{
    "result" : [ 
        {
            "_id" : "1923,
            "count" : 1.0000000000000000
        }, 
        {
            "_id" : "1864",
            "count" : 1.0000000000000000
        }
}

我尝试_id : { $first: '$yearpublished.0' },_id : { $first: '$yearpublished[0]' },但没有成功。

您知道我可以按照数组的第一个元素 yearpublished 进行分组吗?

2 个答案:

答案 0 :(得分:8)

不幸的是,目前唯一的方法是在处理$first后从数组中提取$unwind元素。当然,你必须再次$group

db.foobar.aggregate([
    { "$unwind": "$yearpublished" },
    { "$group": {
        "_id": "$_id",
        "yearpublished": { "$first": "$yearpublished" }
    }},
    { "$group": {
        "_id": "$yearpublished",
        "count": { "$sum": 1 }
    }}
])

这是获得第一个"第一个"数组中的元素,通过解构它并使用运算符来获取条目。

未来的版本将有$arrayElemAt,可以在一个阶段内通过索引完成此任务:

db.foobar.aggregate([
    { "$group": {
        "_id": { "$arrayElemAt": [ "$yearpublished", 0 ] },
        "count": { "$sum": 1 }
    }}
])

但是目前聚合框架并没有处理"点符号"索引用法,如标准"投影"与.find()有,但不会,因此新的操作。

答案 1 :(得分:0)

Mongo 4.4开始,聚合运算符$first可用于访问数组的第一个元素。

在小组讨论中,我们给出的例子是

// { "yearpublished": ["1979", "2003"] }
// { "yearpublished": ["1954", "1979"] }
// { "yearpublished": ["1954"] }
db.collection.aggregate([
  { $group: {
    "_id": { $first: "$yearpublished" },
    "count": { $sum: 1 }
  }}
])
// { "_id" : "1954", "count" : 2 }
// { "_id" : "1979", "count" : 1 }