我需要根据数据/时间获取一系列ID中的最新文档。我有以下查询执行此操作,但它只返回_id
和acquiredTime
字段。如何让它返回包含所有字段的完整文档?
db.trip.aggregate([
{ $match: { tripId: { $in: ["trip01", "trip02" ]}} },
{ $sort: { acquiredTime: -1} },
{ $group: { _id: "$tripId" , acquiredTime: { $first: "$acquiredTime" }}}
])
该集合看起来像:
[{
"tripId": "trip01",
"acquiredTime": 1000,
"name": "abc",
"value": "abc"
},{
"tripId": "trip02",
"acquiredTime": 1000,
"name": "xyz",
"value": "xyz"
},{
"tripId": "trip01",
"acquiredTime": 2000,
"name": "def",
"value": "abc"
},{
"tripId": "trip02",
"acquiredTime": 2000,
"name": "ghi",
"value": "xyz"
}]
我得到的那一刻:
[{
"tripId": "trip01",
"acquiredTime": 2000
},{
"tripId": "trip02",
"acquiredTime": 2000
}]
我需要得到:
[{
"tripId": "trip01",
"acquiredTime": 2000,
"name": "def",
"value": "abc"
},{
"tripId": "trip02",
"acquiredTime": 2000,
"name": "ghi",
"value": "xyz"
}]
答案 0 :(得分:2)
您的方法是正确的方法,但问题是$group
和$project
只是不这样做,并要求您在结果中命名所需的所有字段。
如果您不介意结构看起来有点不同,那么您可以在MongoDB 2.6及更高版本中使用$$ROOT
:
db.trip.aggregate([
{ "$match": { "tripId": { "$in": ["trip01", "trip02" ]}} },
{ "$sort": { "acquiredTime": -1} },
{ "$group": { "_id": "$tripId" , "doc": { "$first": "$$ROOT" }}}
])
所以整个文档都在那里,但只是作为子文档包含在" doc"在结果中。
对于其他任何东西或更漂亮的东西,你必须指定你想要的每个领域。它只是一个数据结构,所以你总是可以从代码中生成它。
db.trip.aggregate([
{ "$match": { "tripId": { "$in": ["trip01", "trip02" ]}} },
{ "$sort": { "acquiredTime": -1} },
{ "$group": {
"_id": "$tripId" ,
"acquiredTime": { "$first": "$acquiredTime" },
"name": { "$first": "$name" },
"value": { "$first": "$value" }
}}
])
答案 1 :(得分:0)
对于我的理解,当要返回大量唯一文档时,上述解决方案会遇到性能和RAM问题,因为$ match的输出将在内存中排序,无论如何您可能拥有的索引。
参考:https://docs.mongodb.com/manual/tutorial/sort-results-with-indexes/
要最大化性能并最小化RAM使用量:
[(tripId, 1), (acquiredTime, -1)]
这当然会花费您一个索引,这会降低插入速度-没有免费的食物:)
此外,使用$replaceRoot
可以轻松解决将原始文档移至子文档的外观问题,而无需明确列出文档密钥。
db.trip.aggregate([
{ "$match": { "tripId": { "$in": ["trip01", "trip02" ]}} },
{ "$sort": SON([("tripId", 1), ("acquiredTime", -1)],
{ "$group": { "_id": "$tripId" , "doc": { "$first": "$$ROOT" }}},
{ "$replaceRoot": { "newRoot": "$doc"}}
])
最后,值得注意的是,如果acquiredTime只是您的服务器时间,您就可以摆脱它,因为_id
已经嵌入了创建时间戳。因此,唯一索引将继续在[(tripId, 1), (_id, -1)]
上,查询变为:
db.trip.aggregate([
{ "$match": { "tripId": { "$in": ["trip01", "trip02" ]}} },
{ "$sort": SON([("tripId", 1), ("_id", -1)],
{ "$group": { "_id": "$tripId" , "doc": { "$first": "$$ROOT" }}},
{ "$replaceRoot": { "newRoot": "$doc"}}
])
这也更好,因为MongoDB中的日期对象具有1毫秒的分辨率,这取决于插入频率,可能会导致极难重现竞争条件,而保证自动生成的_id
严格递增。