MongoDB聚合实现同集合父子分类关联填充parentCategory
问题解决思路
你之前的聚合逻辑存在三个核心问题,导致无法得到预期结构:
- 第一次
$lookup关联categories集合得到的是数组结果,没有转换为单个文档对象,后续字段路径取值错误 - 拿到当前分类的
parentCategory父分类ID列表后,没有二次关联拉取父分类完整信息,反而用多余的$project/$group阶段破坏了原有正确的字段结构 - 你存储的
parentCategory是字符串类型的ID,关联_id(ObjectId类型)时没有做类型转换,会出现匹配不到数据的问题
正确实现代码
直接替换你原有聚合管道的内容即可,核心调整是补全父分类关联逻辑、修正字段结构:
export const categoriesAtHome = async (req: Request & any, res: Response, next: NextFunction) => { try { const { affiliateId } = req.params; const affiliateObjectId = Types.ObjectId(affiliateId); const categoryConditions = { enabled: true, active: true }; const data = await ServicesByAffiliate.aggregate([ // 1. 匹配关联关系表有效数据 { $match: { affiliate: affiliateObjectId, enabled: true } }, // 2. 关联服务信息 { $lookup: { from: "services", localField: "service", foreignField: "_id", as: "service" } }, { $unwind: "$service" }, // 3. 关联当前分类信息,把数组结果转为单个对象 { $lookup: { from: "categories", localField: "category", foreignField: "_id", as: "category", } }, { $addFields: { // lookup返回数组,取第一个元素作为当前分类对象 category: { $arrayElemAt: ["$category", 0] } } }, // 4. 关联父分类完整信息 { $lookup: { from: "categories", let: { // 转换父分类ID为ObjectId类型匹配外键 parentIds: { $map: { input: "$category.parentCategory", as: "pid", in: { $toObjectId: "$$pid" } } } }, pipeline: [ { $match: { $expr: { $in: ["$_id", "$$parentIds"] }, ...categoryConditions } } ], as: "category.parentCategory" } }, { $addFields: { // 父分类lookup结果是数组,按需求取第一个转为单个对象,无父分类则为null "category.parentCategory": { $ifNull: [{ $arrayElemAt: ["$category.parentCategory", 0] }, null] } } } ]); res.status(200).json({ data: data }); } catch (error) { res.status(500).json({ error: true, message: error.toString() }); } };
补充说明
- 如果业务场景中一个分类存在多个父分类,删掉最后一个
$addFields阶段即可,parentCategory会保留为父分类对象数组 - 如果
parentCategory字段存储的本身就是ObjectId类型,删掉$map里的$toObjectId转换逻辑即可 - 该场景只需要一层父分类关联,不需要用
$graphLookup,普通$lookup性能更好
内容的提问来源于stack exchange,提问作者Izlia
相关产品推荐
相关产品推荐

