MongoDB聚合:不使用Mongoose关联嵌套数组的subject与content文档
MongoDB 嵌套数组关联聚合解决方案(不使用Mongoose)
完全可以直接通过MongoDB原生聚合框架实现该需求,无需依赖Mongoose。以下是针对你的场景设计的聚合管道:
聚合管道代码
db.subject.aggregate([ // 拆解topics数组,将每个topic转为独立文档 { $unwind: "$topics" }, // 拆解每个topic下的content数组,将每个content项转为独立文档 { $unwind: "$topics.content" }, // 关联content集合,仅匹配包含contentId的content项 { $lookup: { from: "content", localField: "topics.content.contentId", foreignField: "_id", as: "contentDetails" } }, // 合并关联结果与原content项的字段 { $addFields: { "topics.content": { $cond: { // 判断当前content项是否有contentId if: { $ne: ["$topics.content.contentId", undefined] }, // 有则合并content文档数据与visibility字段 then: { $mergeObjects: [ { $arrayElemAt: ["$contentDetails", 0] }, { visibility: "$topics.content.visibility" } ] }, // 没有则保留原content项 else: "$topics.content" } } } }, // 移除临时的contentDetails字段 { $unset: "contentDetails" }, // 按topic的id分组,重新组装content数组 { $group: { _id: { subjectId: "$_id", topicId: "$topics.id", topicName: "$topics.name", topicDescription: "$topics.description", subjectName: "$name", subjectDescription: "$description", subjectLanguage: "$language" }, content: { $push: "$topics.content" } } }, // 重组topic结构 { $addFields: { "topics.id": "$_id.topicId", "topics.name": "$_id.topicName", "topics.description": "$_id.topicDescription", "topics.content": "$content" } }, // 移除临时分组字段 { $unset: ["_id", "content"] }, // 按subject的id分组,重新组装topics数组 { $group: { _id: "$_id.subjectId", name: { $first: "$_id.subjectName" }, description: { $first: "$_id.subjectDescription" }, language: { $first: "$_id.subjectLanguage" }, topics: { $push: "$topics" } } } ])
逻辑说明
- 多层拆解数组:通过两次
$unwind将嵌套的topics和topics.content数组拆解为扁平结构,方便后续关联操作。 - 精准关联:
$lookup仅对包含contentId的content项关联content集合,避免无效匹配。 - 字段合并:使用
$mergeObjects将关联到的content文档数据与原项的visibility字段合并,保留你需要的所有信息。 - 重新组装结构:通过两次
$group逐步将扁平数据重新聚合为原始的嵌套数组结构,还原subject文档的层级。
执行该聚合管道后,即可得到你期望的结果。
内容的提问来源于stack exchange,提问作者Marek Balvín
相关产品推荐
相关产品推荐

