【问题标题】:How to get the latest document of each group efficiently?如何高效获取各组的最新文档?
【发布时间】:2020-10-01 22:54:04
【问题描述】:

我们来看一个名为values 的集合,其中包含以下文档。

{ "_id" : 1, "name" : "value1", "date" :  ISODate("2020-02-06T15:20:13Z"), "x" : 1, "y" : 2 }
{ "_id" : 2, "name" : "value1", "date" :  ISODate("2020-02-06T16:20:13Z"), "x" : 3, "y" : 3 }
{ "_id" : 3, "name" : "value1", "date" :  ISODate("2020-02-06T17:20:13Z"), "x" : 3, "y" : 4 }
{ "_id" : 4, "name" : "value2", "date" :  ISODate("2020-02-06T16:20:13Z"), "x" : 10, "y" : 20 }
{ "_id" : 5, "name" : "value2", "date" :  ISODate("2020-02-06T17:20:13Z"), "x" : 20, "y" : 30 }
{ "_id" : 6, "name" : "value2", "date" :  ISODate("2020-02-06T18:20:13Z"), "x" : 10, "y" : 40 }

在这里,如果我按name 分组,那么我应该得到每个组的最新文档(基于date)。所以,我应该得到以下文件。

{ "name" : "value1", "x" : 3, "y" : 4 }
{ "name" : "value2", "x" : 10, "y" : 40 }

我可以先根据date 对文档进行降序排序,然后在$group 中使用$first 运算符来获取文档。但是,我认为这可能由于排序而效率低下,因为它会对整个集合进行排序以获得最后一个值(我可能错了)。

有没有更好的方法来有效地做到这一点?

(注意:date 没有唯一值)

【问题讨论】:

  • $group 中使用$max 聚合运算符来获取分组的最新日期。
  • $max 用于date 字段?您的意思是在$match 中这样做吗?
  • $max 应用于日期字段。像这样:{ $group: { _id: "$name", date: { $max: "$date" } } },而不是排序,然后在小组赛中应用 $first。
  • 您不能使用$max 运算符,因为它会检查所有字段是否大于其他字段...在您当前的示例中$max 可以工作,但它会为许多其他名称返回错误结果
  • @Valijon 所以$max 实际上会占据所有date 中最高的name?如果是这样的话,我们就不能那样使用它了。

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

我可以先按降序对文档进行排序 on date 并在 $group 中使用 $first 运算符来获取文档。 但是,我认为这可能由于排序而效率低下,因为它会 对整个集合进行排序以获得最后一个值(我可能错了)。

您可以在 date 字段上建立索引 - 排序操作将很快(或高效),因为它出现在管道的第一阶段。

可选,您可以尝试这种聚合(提供相同的输出):

db.collection.aggregate([ 
  { 
      $group: { 
          _id: "$name", 
          max_date: { $max: "$date" }, 
          docs: { $push: "$$ROOT" }
      } 
  }, 
  { 
      $replaceRoot: { 
          newRoot: { 
              $mergeObjects: [
                   { $arrayElemAt: [
                         { $filter: { input: "$docs", cond: { $eq: [ "$max_date", "$$this.date" ] } } },
                          0 
                    ] }, 
                    "$$ROOT"
              ]
          } 
      } 
  },
  { 
      $project: { _id: 0, docs: 0 } 
  }
] )

【讨论】:

  • 当您说“date 字段上的索引”时,您的意思是让date 成为索引还是在date 上排序很快?
  • create an index在用于高效排序的日期字段上。另见Use Indexes to Sort Query Results
  • 问题是date 字段不是唯一的,如您所见。但是我们可以在多个字段上创建一个索引,这样namedate 的组合将是唯一的。是这个意思吗?
  • 另外,您提议的聚合的问题是$group 中的$push 将在其中存储所有文档。因此,如果我有一百万个文档,比如value1,它将存储所有这些文档以供下一个阶段使用。这会使其效率非常低。
猜你喜欢
  • 2021-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-22
  • 2016-05-25
  • 1970-01-01
  • 2021-05-07
  • 1970-01-01
相关资源
最近更新 更多