MongoDB如何动态获取每个用户最新更新的全字段记录?
MongoDB 获取每个用户最新全字段记录的高效方案
问题场景
现有users集合包含以下记录:
{ _id: 63f3456fcdd8b763618809c1, userName: 'john', status: 'created', updatedAt: "2023-02-21T10:29:08.032Z" }, { _id: 63f3456fcdd8b763618809c2, userName: 'john', status: 'sent', updatedAt: "2023-02-21T10:30:16.456Z" }, { _id: 63f3456fcdd8b763618809c3, userName: 'john', status: 'approved', updatedAt: "2023-02-21T10:30:29.157Z" }, { _id: 63f3456fcdd8b763618809e1, userName: 'ella', status: 'created', updatedAt: "2023-02-14T07:52:48.45Z" }, { _id: 63f3456fcdd8b763618809e2, userName: 'ella', status: 'sent', updatedAt: "2023-02-14T07:53:11.989Z" }
需查询每个用户最新更新的记录,预期结果:
{ _id: 63f3456fcdd8b763618809c3, userName: 'john', status: 'approved', updatedAt: "2023-02-21T10:30:29.157Z" }, { _id: 63f3456fcdd8b763618809e2, userName: 'ella', status: 'sent', updatedAt: "2023-02-14T07:53:11.989Z" }
当前已实现的聚合语句需手动指定字段,不适用于多字段场景:
db.users.aggregate([ { $group : { _id : "$userName", userName: { $last: "$userName" }, status: { $last: "$status" }, updatedAt: { $last: "$updatedAt" }, } }, { $sort: { updatedAt: -1 } } ]);
解决方案
方法1:先排序再分组(推荐,性能最优)
先按userName分组前,对所有文档按userName和updatedAt降序排序,确保每个用户的最新记录排在组内首位,再通过$first直接获取完整文档,无需逐个指定字段:
db.users.aggregate([ // 按用户分组,组内按更新时间降序排序 { $sort: { userName: 1, updatedAt: -1 } }, // 分组后取每个用户的第一条(最新)完整文档 { $group: { _id: "$userName", latestDoc: { $first: "$$ROOT" } } }, // 将嵌套的完整文档转为根文档 { $replaceRoot: { newRoot: "$latestDoc" } }, // 可选:按更新时间降序排序最终结果 { $sort: { updatedAt: -1 } } ]);
说明:$$ROOT指代当前完整文档,$first直接取排序后的组内首条记录,$replaceRoot将嵌套的latestDoc转为顶层文档,自动保留所有原始字段。
方法2:分组筛选最新文档(MongoDB 4.2+)
若无需提前排序,可通过分组收集每个用户的所有文档和最新更新时间,再筛选出对应文档:
db.users.aggregate([ { $group: { _id: "$userName", maxUpdatedAt: { $max: "$updatedAt" }, allDocs: { $push: "$$ROOT" } } }, { $project: { latestDoc: { $first: { $filter: { input: "$allDocs", cond: { $eq: ["$$this.updatedAt", "$maxUpdatedAt"] } } } } } }, { $replaceRoot: { newRoot: "$latestDoc" } }, { $sort: { updatedAt: -1 } } ]);
说明:先分组获取每个用户的最新更新时间和所有文档,再用$filter匹配对应时间的文档,最后转为根文档。此方法性能略逊于前者,因为需要存储每个用户的所有文档。
方案对比
- 方法1性能更优:排序后分组直接取首条记录,避免了大量文档存储开销,适合大数据量场景。
- 两种方法均无需手动指定字段,自动保留所有原始字段,完美解决多字段场景的繁琐问题。
内容的提问来源于stack exchange,提问作者user1776711
相关产品推荐
相关产品推荐

