如何在Mongoose中基于孙级文档属性过滤父级关联文档
解决方案
因为你的三个数据是独立集合通过ObjectId关联,不是嵌套文档结构,不能直接用"child.grandchild.name"的点语法直接匹配,需要用聚合管道做两次关联后过滤,具体实现如下:
方法1:聚合管道实现(推荐,过滤逻辑更精准)
const Parent = require('./models/Parent'); // 引入你定义的Parent模型 const result = await Parent.aggregate([ // 第一次关联children集合 { $lookup: { from: "children", // 子集合在MongoDB中的实际表名 localField: "child", foreignField: "_id", as: "childInfo" } }, // 打平childInfo数组(1对1关联只会有一个元素) { $unwind: "$childInfo" }, // 第二次关联grandchildren集合 { $lookup: { from: "grandchildren", // 孙集合在MongoDB中的实际表名 localField: "childInfo.grandchild", foreignField: "_id", as: "grandchildInfo" } }, { $unwind: "$grandchildInfo" }, // 按孙文档的name字段过滤 { $match: { "grandchildInfo.name": "grandchild1" } }, // 可选:只保留父文档的原始字段,移除关联产生的额外字段 { $project: { childInfo: 0, grandchildInfo: 0 } } ])
执行后返回的结果就是你要求的仅符合条件的父文档。
方法2:populate 链式匹配实现
如果你更习惯用populate语法,也可以通过嵌套populate加match实现:
注意:使用该方法前需要确保你的Mongoose模型中已经正确配置了外键关联的ref属性:
- Parent模型的child字段:
child: { type: mongoose.Types.ObjectId, ref: 'Child' }- Child模型的grandchild字段:
grandchild: { type: mongoose.Types.ObjectId, ref: 'Grandchild' }
const result = await Parent.find() .populate({ path: 'child', populate: { path: 'grandchild', match: { name: 'grandchild1' } } }) .lean() // 过滤掉孙文档匹配失败的父文档(匹配失败时child.grandchild为null) .then(parents => parents.filter(p => p.child?.grandchild)) // 可选:移除关联的嵌套字段,返回父文档原始结构 .then(parents => parents.map(p => ({ _id: p._id, child: p.child._id })))
内容的提问来源于stack exchange,提问作者Afam Ezechukwu
相关产品推荐
相关产品推荐

