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

MongoDB如何按收发双方分组并筛选最大日期文档?

解决MongoDB按收发双方双向分组并取最新文档的问题

这问题挺典型的,要实现按收发双方双向分组(A-B和B-A归为同一组),同时取每组最新文档、统计组内数量,核心是先生成统一的会话标识,再通过MongoDB的聚合管道一步步处理。我给你详细拆解实现步骤:

1. 生成统一会话ID

首先要把收发双方的标识(sender/recipient)按固定顺序排序后拼接,确保A-B和B-A得到同一个会话ID。用$sortArray排序、$join拼接:

{
  $addFields: {
    sessionId: {
      $join: [
        { $sortArray: { input: ["$sender", "$recipient"], sortBy: 1 } },
        ""
      ]
    }
  }
}

这一步会给每个文档新增一个sessionId字段,比如sender=B、recipient=A的文档,sessionId会是"AB",和sender=A、recipient=B的文档保持一致。

2. 按会话ID分组统计

接下来按sessionId分组,统计组内文档数量、记录最大日期,同时把组内所有文档暂存到数组中:

{
  $group: {
    _id: "$sessionId",
    count: { $sum: 1 },
    maxDate: { $max: "$date" },
    messages: { $push: "$$ROOT" }
  }
}
  • count: { $sum: 1 }:统计每组的文档总数
  • maxDate: { $max: "$date" }:记录组内最大的日期值
  • messages: { $push: "$$ROOT" }:把组内所有原始文档(包含新增的sessionId)存入数组,方便后续筛选最新文档

3. 筛选出组内最新文档

从messages数组中过滤出日期等于maxDate的文档,用$arrayElemAt取第一个(如果有多个同最大日期的文档,可根据需求调整逻辑):

{
  $addFields: {
    latestMessage: {
      $arrayElemAt: [
        { $filter: {
            input: "$messages",
            cond: { $eq: ["$$this.date", "$maxDate"] }
          }
        },
        0
      ]
    }
  }
}

4. 整理最终输出结构

把筛选出的最新文档作为根文档,同时合并会话ID(作为_id)和统计数量count:

{
  $replaceRoot: {
    newRoot: {
      $mergeObjects: [
        "$latestMessage",
        { _id: "$_id", count: "$count" }
      ]
    }
  }
}

5. (可选)移除冗余字段

如果不需要保留临时的sessionId字段,用$project移除:

{
  $project: { sessionId: 0 }
}

完整聚合管道代码

把以上步骤组合起来,完整的聚合查询如下:

db.yourCollectionName.aggregate([
  // 步骤1:生成统一会话ID
  {
    $addFields: {
      sessionId: {
        $join: [
          { $sortArray: { input: ["$sender", "$recipient"], sortBy: 1 } },
          ""
        ]
      }
    }
  },
  // 步骤2:按会话ID分组统计
  {
    $group: {
      _id: "$sessionId",
      count: { $sum: 1 },
      maxDate: { $max: "$date" },
      messages: { $push: "$$ROOT" }
    }
  },
  // 步骤3:筛选最新文档
  {
    $addFields: {
      latestMessage: {
        $arrayElemAt: [
          { $filter: {
              input: "$messages",
              cond: { $eq: ["$$this.date", "$maxDate"] }
            }
          },
          0
        ]
      }
    }
  },
  // 步骤4:整理输出结构
  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          "$latestMessage",
          { _id: "$_id", count: "$count" }
        ]
      }
    }
  },
  // 步骤5:移除冗余字段
  {
    $project: { sessionId: 0 }
  }
])

验证结果

运行这个聚合后,会得到你期望的结果:

[ 
  { _id: 'AB', sender: 'B', recipient: 'A', date: 2, contents: 'Blablabla2', count: 2 }, 
  { _id: 'AC', sender: 'A', recipient: 'C', date: 4, contents: 'Blablabla1', count: 2 },
  { _id: 'CD', sender: 'C', recipient: 'D', date: 3, contents: 'Blablabla2', count: 1 } 
]

内容的提问来源于stack exchange,提问作者nelkor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:43:55