【问题标题】:MongoDB return two object for every groupMongoDB为每个组返回两个对象
【发布时间】:2014-06-12 15:59:05
【问题描述】:

我想在分组后得到两个对象 $first 和 $last。有可能吗?

类似这样的东西,但这不起作用:

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

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案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" }
        }}
    ])
    

    如果您的数组未排序,则在第一个 $group 之前放置一个额外的 $sort 阶段,以确保您的项目按照您希望它们被 $first 和 $last 评估的顺序。 “时间”字段的逻辑顺序,所以:

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

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

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


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

    【讨论】:

      猜你喜欢
      • 2018-01-09
      • 2017-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-29
      • 2023-03-16
      • 2014-08-02
      相关资源
      最近更新 更多