【问题标题】: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”,而正确的结果是一个空结果集。

【问题讨论】:

    标签: mongodb mongoose mongodb-query aggregation-framework


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

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

    【讨论】:

    • 谢谢!这是一个好主意,因为当前模式在计算查询时也很麻烦。我必须运行整个聚合管道才能获得正确的项目数。
    猜你喜欢
    • 2021-12-24
    • 1970-01-01
    • 2020-03-18
    • 2019-11-25
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多