【问题标题】:Select latest document after grouping them by a field in MongoDB按 MongoDB 中的字段对它们进行分组后选择最新文档
【发布时间】:2019-10-18 14:35:03
【问题描述】:

我收到了一个我认为很简单的问题,但我无法弄清楚。我想做的是这样的:

  • 查找集合中的所有文档并:
    • 按特定日期字段对文档进行排序
    • 在其其他字段之一上应用distinct但返回整个文档

最好在示例中显示。

这是一个模拟输入:

[
  {
    "commandName" : "migration_a",
    "executionDate" : ISODate("1998-11-04T18:46:14.000Z")
  },
  {
    "commandName" : "migration_a",
    "executionDate" : ISODate("1970-05-09T20:16:37.000Z")
  },
  {
    "commandName" : "migration_a",
    "executionDate" : ISODate("2005-11-08T11:58:52.000Z")
  },
  {
    "commandName" : "migration_b",
    "executionDate" : ISODate("2016-06-02T19:48:34.000Z")
  }
]

预期的输出是:

[
  {
    "commandName" : "migration_a",
    "executionDate" : ISODate("2005-11-08T11:58:52.000Z")
  },
  {
    "commandName" : "migration_b",
    "executionDate" : ISODate("2016-06-02T19:48:34.000Z")
  }
]

或者,换句话说:

  • commandName 字段对输入数据进行分组
  • 在每个组内对文档进行排序
  • 返回每个组中的最新文档

我编写此查询的尝试失败了:

  • distinct() 函数只会返回我正在区分的字段的值,而不是整个文档。这使得它不适合我的情况。

  • 尝试编写aggregate 查询,但遇到了如何从每个组内部排序和选择单个文档的问题? sort 聚合阶段将对 groups 进行排序,这不是我想要的。

我对 Mongo 不太精通,这就是我碰壁的地方。关于如何继续的任何想法?


作为参考,这是我正在尝试扩展的正在进行中的聚合查询:

db.getCollection('some_collection').aggregate([
{ $group: { '_id': '$commandName', 'docs': {$addToSet: '$$ROOT'} } }, 
{ $sort: {'_id.docs.???': 1}}
])

解决后的编辑

感谢您的回答。我得到了我需要的东西。以供将来参考,这是完整的查询,它将执行所请求的操作并返回已过滤文档的列表,而不是组

db.getCollection('some_collection').aggregate([
{ $sort: {'executionDate': 1}},
{ $group: { '_id': '$commandName', 'result': { $last: '$$ROOT'} } },
{ $replaceRoot: {newRoot: '$result'} }
])

没有$replaceRoot 阶段的查询结果将是:

[
  {
    "_id": "migration_a",
    "result": {
      "commandName" : "migration_a",
      "executionDate" : ISODate("2005-11-08T11:58:52.000Z")
    }
  },
  {
    "_id": "migration_b",
    "result": {
      "commandName" : "migration_b",
      "executionDate" : ISODate("2016-06-02T19:48:34.000Z")
    }
  }
]

外部的_id_result 只是我想要的实际文档的“组包装器”,它嵌套在result 键下。使用$replaceRoot 阶段将嵌套文档移动到结果的根目录。使用该阶段时的查询结果为:

[
  {
    "commandName" : "migration_a",
    "executionDate" : ISODate("2005-11-08T11:58:52.000Z")
  },
  {
    "commandName" : "migration_b",
    "executionDate" : ISODate("2016-06-02T19:48:34.000Z")
  }
]

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    试试这个:

    db.getCollection('some_collection').aggregate([
     { $sort: {'executionDate': -1}},
     { $group: { '_id': '$commandName', 'doc': {$first: '$$ROOT'} } }
    ])
    

    【讨论】:

      【解决方案2】:

      我相信这会产生您正在寻找的结果:

      db.collection.aggregate([
        {
          $group: {
            "_id": "$commandName",
            "executionDate": {
              "$last": "$executionDate"
            }
          }
        }
      ])
      

      您可以查看here

      当然,如果您想完全匹配您的预期输出,您可以添加一个排序(这可能不是必需的,因为您的目标是简单地返回每个组中的最新文档):

      {
       $sort: {
        "executionDate": 1
       }
      }
      

      您可以查看此版本here.

      【讨论】:

        【解决方案3】:

        $last aggregation 运算符文档几乎涵盖了该问题提出的用例。

        总结如下:

        $group 阶段应跟随$sort 阶段以获取输入 文件按定义的顺序。因为$last 只是选择了最后一个 来自一个组的文档。

        查询: Link

        db.collection.aggregate([
          {
            $sort: {
              executionDate: 1
            }
          },
          {
            $group: {
              _id: "$commandName",
              executionDate: {
                $last: "$executionDate"
              }
            }
          }
        ]);
        

        【讨论】:

          猜你喜欢
          • 2023-01-12
          • 1970-01-01
          • 1970-01-01
          • 2017-10-24
          • 2017-10-29
          • 1970-01-01
          • 2015-09-11
          • 2018-07-15
          • 1970-01-01
          相关资源
          最近更新 更多