如何在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+),可以先将两个聚合结果分别写入同一个临时集合,再查询该集合得到合并结果:
- 写入零访问客户到临时集合:
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" } } ]);
- 写入最少访问客户到临时集合:
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" } } ]);
- 查询临时集合并排序:
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
相关产品推荐
相关产品推荐

