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 }
代码说明
- $graphLookup:递归查询每个分类的所有父级,返回包含所有祖先分类的数组,同时附带深度字段标记层级。
- $map:遍历商品的每个分类,把原始分类数据和父级查询结果合并。
- $reduce:将
$graphLookup返回的父级数组转换为嵌套结构,最顶层的分类会被嵌套在最内层,完全符合你需要的格式。
如果你的分类层级是固定的(比如最多3层),也可以用多次$lookup结合$unwind、$group实现,但$graphLookup更适配不确定层级的场景。
内容的提问来源于stack exchange,提问作者chuckieDub
相关产品推荐
相关产品推荐

