如何仅从组中查询具有最新时间戳的文档?

Posted

技术标签:

【中文标题】如何仅从组中查询具有最新时间戳的文档?【英文标题】:How to query only documents with the latest timestamp from a group? 【发布时间】:2014-03-08 07:36:26 【问题描述】:

在我查询的 MongoDB 集合中,每个文档代表特定时间的一个项目。更新文档时,会创建一个具有相同项目 ID 和新时间戳的新文档。所有项目都有唯一的项目 ID。

为了说明,考虑这个例子。我们从一个项目的一个修订开始:


    _id: x,
    itemId: 123,
    createdOn: ISODate("2013-01-30T11:16:20.102Z"),
    field1: "foo",
    field2: "bar

更新后,我们有两个版本的项目,具有相同的 itemId 和不同的时间戳。

[
  _id: x,
  itemId: 123,
  createdOn: ISODate("2013-01-30T11:16:20.102Z"),
  field1: "foo",
  field2: "bar"
,

  _id: y,
  itemId: 123,
  createdOn: ISODate("2014-02-09T14:26:20.102Z"),
  field1: "baz",
  field2: "fiz"
]

如何找到在其最新修订版中满足特定查询的所有项目?

我目前(错误)的做法是先找到匹配的文档,然后按时间戳排序,按itemId分组,然后从组中的第一个文档返回值:

ItemModel.aggregate( $match:  field1: "foo" ).sort(createdOn: -1).group(
    
        _id: '$itemId', // grouping key
        createdOn: $first: '$createdOn',
        field1: $first: '$field1',
        field2: $first: '$field2'
    ).exec(...);

这是错误的,因为它匹配项目的旧版本。只有项目的最新版本应该匹配。在上面的示例中,此方法返回项目“123”,而正确的结果是一个空结果集。

【问题讨论】:

【参考方案1】:

当您可以在聚合管道中做所有事情时,您在这里混合了几种方法。否则,只需按正确的顺序执行步骤即可:

db.collection.aggregate([
    $sort:  createdOn: -1 ,
    $group:  _id: "$itemId", 
        createdOn: $first: "$createdOn",
        field1: $first: "$field1" ,
        field2: $first: "$field2" 
    ,
    $match:  field1: "foo" 
])

所以首先对最新的文档进行排序。对itemId 进行分组($first 将保持顺序),然​​后在必要时使用 $match 进行过滤。但您的分组文档将是最新的。

【讨论】:

谢谢,我还没有意识到聚合管道有多灵活。我最终在开始和结束时都有一个匹配步骤,因为这通过减少通过管道的文档数量来提高性能。【参考方案2】:

可以考虑更改文档的架构以更好地适应您的查询,并减少聚合开销。您可以将修订子文档推送到数组中并在父文档中维护最新修订,而不是为每个修订创建一个新文档;例如:


    _id: x,
    itemId: 123,
    createdOn: ISODate("2014-02-09T14:26:20.102Z"),
    field1: "baz",
    field2: "fiz,
    revisions: [
        createdOn: ISODate("2013-01-30T11:16:20.102Z"), field1: "foo", field2: "bar",
        createdOn: ISODate("2014-02-09T14:26:20.102Z"), field1: "baz", field2: "fiz"
    ]

请记住,MongoDB 强制执行 16MB 的文档大小限制;这应该足以满足大多数用例。这将使您的查询非常简单:db.collection.find(field1: "foo")

只是另一种方法......

【讨论】:

谢谢!这是一个好主意,因为当前模式在计算查询时也很麻烦。我必须运行整个聚合管道才能获得正确的项目数。

以上是关于如何仅从组中查询具有最新时间戳的文档?的主要内容,如果未能解决你的问题,请参考以下文章

通过 linq 对实体查询进行分组,以通过加入表来获取具有最新时间戳的一条记录

仅从组中选择第一行的 SQL 模式

CouchDB 查询以获取具有 MAX 时间戳的文档

SQL查询以获取具有不同时间戳的多行

用于从表中选择具有最新时间戳的行的 JOOQ 代码

如何选择每个项目具有最大时间戳的行集?