You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB聚合查询:实现多层级商品分类嵌套展开

多层级嵌套分类的商品聚合查询实现方案

我在使用支持聚合查询的电商平台Swell,需要返回包含多层级展开分类的商品数据。商品有category_index.id字段,是分类ID的数组,要求把所有分类放到categories数组中,同时将每个分类的父级嵌套到对应分类内部。

初始数据格式

// 商品数据
{
  _id: 'xxx',
  category_index: {
    id: ['123','456','789']
  }
}

// 分类数据
{
  _id: 'xxxx',
  'parent_id': 'xxx' // 分类支持多级嵌套
}

现有代码问题

我写了一段聚合查询代码,但它只能把父级分类返回至单独字段,无法嵌套到对应分类内部:

export const getProductBySlug = async (slug: string) => {
    const product = await swell.get('/products', {
        aggregate: [
            {
                $match: {
                    slug
                }
            },
            {
                $lookup: {
                    from: 'com.categories',
                    localField: 'category_index.id',
                    foreignField: '_id',
                    as: 'categories'
                }
            },
            {
                $lookup: {
                    from: 'com.categories',
                    localField: 'categories.parent_id',
                    foreignField: '_id',
                    as: 'categories.parent'
                }
            }
        ]
    })
}

期望返回格式

{
  /* 商品数据 */
  id: 'xxx',
  name: 'productName',
  slug: 'product-slug',
  categories: [{
    /* 分类数据 */
    parent: {
      /* 分类数据 */
      parent: {
        /* 最顶层分类数据 */
      }
    }
  }]
}

解决方案:用$graphLookup实现多层嵌套

要实现分类的多层嵌套,推荐使用MongoDB聚合中的$graphLookup,它专门用于处理文档的层级关联查询。修改后的代码如下:

export const getProductBySlug = async (slug: string) => {
    const product = await swell.get('/products', {
        aggregate: [
            // 匹配指定slug的商品
            { $match: { slug } },
            // 关联获取商品直接所属的分类
            {
                $lookup: {
                    from: 'com.categories',
                    localField: 'category_index.id',
                    foreignField: '_id',
                    as: 'categories'
                }
            },
            // 为每个分类递归查询所有父级分类
            {
                $addFields: {
                    categories: {
                        $map: {
                            input: '$categories',
                            as: 'cat',
                            in: {
                                $mergeObjects: [
                                    '$$cat',
                                    {
                                        parent: {
                                            $graphLookup: {
                                                from: 'com.categories',
                                                startWith: '$$cat.parent_id',
                                                connectFromField: 'parent_id',
                                                connectToField: '_id',
                                                as: 'ancestors',
                                                depthField: 'depth'
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            },
            // 将父级分类数组转换为嵌套层级对象
            {
                $addFields: {
                    categories: {
                        $map: {
                            input: '$categories',
                            as: 'cat',
                            in: {
                                $mergeObjects: [
                                    '$$cat',
                                    {
                                        parent: {
                                            $reduce: {
                                                input: '$$cat.parent.ancestors',
                                                initialValue: null,
                                                in: {
                                                    $mergeObjects: [
                                                        '$$this',
                                                        { parent: '$$value' }
                                                    ]
                                                }
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            }
        ]
    })
    return product
}

代码说明

  1. $graphLookup:递归查询每个分类的所有父级,返回包含所有祖先分类的数组,同时附带深度字段标记层级。
  2. $map:遍历商品的每个分类,把原始分类数据和父级查询结果合并。
  3. $reduce:将$graphLookup返回的父级数组转换为嵌套结构,最顶层的分类会被嵌套在最内层,完全符合你需要的格式。

如果你的分类层级是固定的(比如最多3层),也可以用多次$lookup结合$unwind、$group实现,但$graphLookup更适配不确定层级的场景。

内容的提问来源于stack exchange,提问作者chuckieDub

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 12:58:19