Mongodb 如何从组中仅查询具有最新时间戳的文档?
在我查询的MongoDB集合中,每个文档在特定时间代表一个项。更新文档时,将创建具有相同项目id和新时间戳的新文档。所有项目都有唯一的项目ID 为了说明,请考虑这个例子。我们从项目的一个修订版开始:Mongodb 如何从组中仅查询具有最新时间戳的文档?,mongodb,mongoose,mongodb-query,aggregation-framework,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 } 更新之后,我们对该项进行了两次修订,具有相同的itemI
{
_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”,而正确的结果是一个空结果集 当您可以在聚合管道中执行所有操作时,您在这里混合了一些方法。否则,只需按照正确的顺序进行步骤:
db.collection.aggregate([
{$sort: { createdOn: -1 }},
{$group: { _id: "$itemId",
createdOn: {$first: "$createdOn"},
field1: {$first: "$field1" },
field2: {$first: "$field2" }
}},
{$match: { field1: "foo" }}
])
因此,首先对最新文档进行排序。在
itemId
上分组(订单将首先维护$first),如果必须,则使用$match进行筛选。但是您的分组文档将是最新的。当您可以在聚合管道中执行所有操作时,您在这里混合了一些方法。否则,只需按照正确的顺序进行步骤:
db.collection.aggregate([
{$sort: { createdOn: -1 }},
{$group: { _id: "$itemId",
createdOn: {$first: "$createdOn"},
field1: {$first: "$field1" },
field2: {$first: "$field2" }
}},
{$match: { field1: "foo" }}
])
因此,首先对最新文档进行排序。在
itemId
上分组(订单将首先维护$first),如果必须,则使用$match进行筛选。但是您的分组文档将是最新的文档。 可以考虑更改文档的模式,以更好地适合您的查询,并减少聚合的开销。您可以将修订子文档推送到数组中,并在父文档中维护最新修订,而不是为每个修订创建新文档;例如:
{
_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})
另一种方法…
< P>可以考虑更改文档的模式,以更好地适合查询,并减少聚合的开销。您可以将修订子文档推送到数组中,并在父文档中维护最新修订,而不是为每个修订创建新文档;例如:{
_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})
只是另一种方法…谢谢!这是一个好主意,因为当前模式在计数查询时也很麻烦。我必须运行整个聚合管道才能获得正确的项目计数。谢谢!这是一个好主意,因为当前模式在计数查询时也很麻烦。我必须运行整个聚合管道才能获得正确的项目计数。谢谢,我还没有意识到聚合管道有多灵活。我在开头和结尾都进行了匹配步骤,因为这样可以通过减少通过管道的文档数量来提高性能。谢谢,我还没有意识到聚合管道有多灵活。我在开头和结尾都使用了匹配步骤,因为这样可以减少通过管道传输的文档数量,从而提高性能。