You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 20:24:33