MongoDB为每个组返回两个对象

时间:2014-06-12 15:59:05

标签: mongodb mongodb-query aggregation-framework

我希望在分组后获得两个$ first和$ last。有可能吗?

这样的事情,但这不起作用:

{ "$group": {
  "_id": "type",
  "values": [{
        "time": { "$first": "$time" },
        "value": { "$first": "$value" }
        }, 
        {
          "time": { "$last": "$time" },
          "value": { "$last": "$value" }
        }]
   }
}

1 个答案:

答案 0 :(得分:1)

为了从具有聚合框架的数组中获取$first$last值,您需要首先使用$unwind将数组“反规范化”为单个文档。还有另一种技巧可以将它们放回阵列中。

假设有这样的文件

{
    "type": "abc",
    "values": [
        { "time": ISODate("2014-06-12T22:35:42.260Z"), "value": "ZZZ" },
        { "time": ISODate("2014-06-12T22:36:45.921Z"), "value": "KKK" },
        { "time": ISODate("2014-06-12T22:37:18.237Z"), "value": "AAA" } 
    ]
}

假设您的数组已经排序,您可以这样做:

如果您不关心数组$unwind$group中的结果:

db.junk.aggregate([
    { "$unwind": "$values" },
    { "$group": {
        "_id": "$type",
        "ftime":  { "$first": "$values.time" },
        "fvalue": { "$first": "$values.value" },
        "ltime":  { "$last": "$values.time" },
        "lvalue": { "$last": "$values.value" },
    }}
])

对于那些数组中的结果,有一个技巧:

db.collection.aggregate([
    { "$unwind": "$values" },
    { "$project": {
        "type": 1,
        "values": 1,
        "indicator": { "$literal": ["first", "last"] }
    }},
    { "$group": {
        "_id": "$type",
        "ftime":  { "$first": "$values.time" },
        "fvalue": { "$first": "$values.value" },
        "ltime":  { "$last": "$values.time" },
        "lvalue": { "$last": "$values.value" },
        "indicator": { "$first": "$indicator" }
    }},
    { "$unwind": "$indicator" },
    { "$project": {
        "values": {
            "time": {
                "$cond": [
                    { "$eq": [ "$indicator", "first" ] },
                    "$ftime",
                    "$ltime"
                ]
            },
            "value": {
                "$cond": [
                    { "$eq": [ "$indicator", "first" ] },
                    "$fvalue",
                    "$lvalue"
                ]
            }
        }
    }},
    { "$group": {
        "_id": "$_id",
        "values": { "$push": "$values" }
    }}
])

如果您的数组未排序,请在第一个$sort之前放置一个额外的$group阶段,以确保您的商品符合您希望$first和{$last对其进行评估的顺序{3}}。逻辑顺序,其中是“时间”字段,所以:

{ "$sort": { "type": 1, "values.time": 1 } }

$literal声明一个数组,用于标识“first”和“last”的值,这些值稍后“展开”以创建每个分组文档的两个副本。然后使用$cond运算符对这些值进行评估,以便为“值”重新分配单个字段,最后使用$push将其推回到数组中。

请记住,总是首先在管道中尝试$match,以便将您正在处理的文档数量减少到合理需要的数量。您几乎不想在整个集合中执行此操作,尤其是在阵列上使用$unwind时。


正如在MongoDB 2.6及更高版本中引入/公开最终注释$literal一样。对于以前的版本,您可以将其与未记录的 $const

互换