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

时间:2014-02-10 19:32:33

标签: mongodb mongoose mongodb-query aggregation-framework

在我查询的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”,而正确的结果是空结果集。

2 个答案:

答案 0 :(得分: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进行过滤。但是您的分组文档将是最新的。

答案 1 :(得分:1)

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

{
    _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”})

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