MongoDB聚合查询:关联多集合返回嵌套评论及回复数据
解决方案
直接上可运行的聚合管道,一次性完成主评论嵌套回复+关联用户信息的需求:
db.comments.aggregate([ // 1. 筛选目标文章的所有评论(主评论+回复) { $match: { article_id: ObjectId("目标文章ID") } }, // 2. 关联用户表,获取评论者的display_name { $lookup: { from: "users", localField: "user_id", foreignField: "_id", as: "user_info" } }, // 3. 展开用户信息数组,方便后续字段提取 { $unwind: "$user_info" }, // 4. 整理评论字段,只保留需要的内容 { $project: { content: 1, user_id: 1, display_name: "$user_info.display_name", reply_to: 1, article_id: 1 } }, // 5. 分组:主评论作为分组key,收集对应回复 { $group: { _id: { $cond: { if: { $eq: ["$reply_to", null] }, then: "$_id", // 主评论用自身ID分组 else: "$reply_to" // 回复用所属主评论的ID分组 } }, // 提取主评论的完整信息 mainComment: { $first: { $cond: [{ $eq: ["$reply_to", null] }, "$$ROOT", null] } }, // 收集当前分组下的所有回复 replies: { $push: { $cond: { if: { $ne: ["$reply_to", null] }, then: "$$ROOT", else: null } } } } }, // 6. 过滤掉replies数组中的null值(主评论自身会被push为null) { $addFields: { replies: { $filter: { input: "$replies", cond: { $ne: ["$$this", null] } } } } }, // 7. 合并主评论字段和replies,生成最终嵌套结构 { $replaceRoot: { newRoot: { $mergeObjects: [ "$mainComment", { replies: "$replies" } ] } } }, // 8. 过滤无效分组(避免出现无主评论的异常数据) { $match: { mainComment: { $ne: null } } } ])
关键逻辑说明
- $match:先缩小处理范围,只针对目标文章的评论操作,提升查询性能。
- $lookup + $unwind:关联用户表并展开数组,直接将用户的
display_name整合到评论文档中。 - $group:核心分组逻辑,通过
$cond区分主评论和回复,将同一主评论下的回复收集到数组中。 - $filter:清理回复数组中的无效null值,保证结构整洁。
- $replaceRoot:将主评论的字段与回复数组合并,生成你需要的嵌套文档格式。
输出示例
最终返回的文档结构如下:
[ { "_id": ObjectId("主评论ID"), "content": "主评论内容", "user_id": ObjectId("用户ID"), "display_name": "用户名", "article_id": ObjectId("目标文章ID"), "reply_to": null, "replies": [ { "_id": ObjectId("回复ID"), "content": "回复内容", "user_id": ObjectId("回复用户ID"), "display_name": "回复用户名", "article_id": ObjectId("目标文章ID"), "reply_to": ObjectId("主评论ID") } ] } ]
内容的提问来源于stack exchange,提问作者chuckieDub
相关产品推荐
相关产品推荐

