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

如何在MongoDB中合并两个聚合查询结果(非数组拼接方式)

实现方案:无需数组concat合并两个聚合结果

可以直接通过MongoDB的聚合操作在数据库层面完成结果合并,不需要在代码中使用Array.concat()方法,以下是两种可行方案:

方案一:使用$unionWith合并两个聚合管道

将两个独立的聚合查询通过$unionWith合并,同时为两组数据添加优先级标识来保证顺序(零访问客户优先级设为1,最少访问客户设为2),最后按优先级排序并移除标识字段:

const combinedResult = await clientModel.aggregate([
  // 第一部分:获取零访问客户,添加优先级标识
  {
    $lookup: {
      from: "visits",
      localField: "_id",
      foreignField: "client",
      as: "visits",
    },
  },
  {
    $project: {
      _id: 1,
      name: 1,
      count: { $size: "$visits" },
      priority: 1 // 零访问客户优先级设为1,确保排在前面
    },
  },
  { $match: { count: 0 } },
  { $project: { _id: 1, name: 1, priority: 1 } },
  // 合并第二部分:访问量最少的客户聚合结果
  {
    $unionWith: {
      coll: "visits",
      pipeline: [
        { $match: { time: { $lte: +to, $gte: +from } } },
        {
          $project: {
            date: { $toDate: "$time" },
            client: 1,
          },
        },
        {
          $project: {
            day: { $dayOfWeek: "$date" },
            client: 1,
          },
        },
        { $match: { day: 2 } },
        {
          $group: {
            _id: { client: "$client" },
            count: { $sum: 1 },
          },
        },
        { $sort: { count: 1 } },
        { $limit: 10 },
        {
          $lookup: {
            from: "clients",
            localField: "_id.client",
            foreignField: "_id",
            as: "client",
          },
        },
        { $unwind: { path: "$client", preserveNullAndEmptyArrays: false } },
        {
          $project: {
            _id: "$client._id",
            name: "$client.name",
            priority: 2 // 最少访问客户优先级设为2,排在后面
          },
        },
      ]
    }
  },
  // 按优先级排序,确保零访问客户在前
  { $sort: { priority: 1 } },
  // 移除优先级标识字段
  { $project: { _id: 1, name: 1 } }
]);

// 返回合并后的结果
res.json({
  success: true,
  combined: combinedResult
});

方案二:使用$merge将两个聚合结果写入临时集合后查询

如果你的MongoDB版本不支持$unionWith(需要MongoDB 4.4+),可以先将两个聚合结果分别写入同一个临时集合,再查询该集合得到合并结果:

  1. 写入零访问客户到临时集合:
await clientModel.aggregate([
  { $lookup: { from: "visits", localField: "_id", foreignField: "client", as: "visits" } },
  { $project: { _id: 1, name: 1, count: { $size: "$visits" } } },
  { $match: { count: 0 } },
  { $project: { _id: 1, name: 1, priority: 1 } },
  { $merge: { into: "temp_combined_clients", whenMatched: "replace", whenNotMatched: "insert" } }
]);
  1. 写入最少访问客户到临时集合:
await visitModel.aggregate([
  { $match: { time: { $lte: +to, $gte: +from } } },
  { $project: { date: { $toDate: "$time" }, client: 1 } },
  { $project: { day: { $dayOfWeek: "$date" }, client: 1 } },
  { $match: { day: 2 } },
  { $group: { _id: { client: "$client" }, count: { $sum: 1 } } },
  { $sort: { count: 1 } },
  { $limit: 10 },
  { $lookup: { from: "clients", localField: "_id.client", foreignField: "_id", as: "client" } },
  { $unwind: { path: "$client", preserveNullAndEmptyArrays: false } },
  { $project: { _id: "$client._id", name: "$client.name", priority: 2 } },
  { $merge: { into: "temp_combined_clients", whenMatched: "replace", whenNotMatched: "insert" } }
]);
  1. 查询临时集合并排序:
const combinedResult = await db.collection("temp_combined_clients")
  .find()
  .sort({ priority: 1 })
  .project({ _id: 1, name: 1 })
  .toArray();

// 返回结果后可以删除临时集合
await db.collection("temp_combined_clients").drop();

res.json({
  success: true,
  combined: combinedResult
});

说明

  • 方案一使用$unionWith更简洁高效,直接在单个聚合管道中完成合并和排序,推荐使用(需MongoDB 4.4及以上版本)。
  • 方案二兼容更低版本的MongoDB,但需要额外的临时集合操作,记得在查询完成后清理临时集合。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:35:16