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

如何在Node.js(Mongoose)中正确聚合过滤MongoDB嵌套数组集合?

问题:筛选MongoDB文档中包含指定SKU的units数组元素

在MongoDB的motorcycles集合中,每个文档包含units数组,每个unit下又有parts数组(包含name和SKU字段)。需要仅获取包含指定SKU(示例为PT00002)的units元素。

我的尝试(无效,返回空units数组)

let responseData = await Model.aggregate([
            {
                $match: {
                    'units.parts.SKU': sku,
                }
            },
            {
                $project: {
                    'units': {
                        $filter: {
                            input: '$units',
                            as: 'unit',
                            cond: {
                                $eq: [
                                    '$$unit.parts.SKU', sku
                                ]
                            }
                        }
                    }
                }
            }
        ]);

文档结构示例

文档1:

{
    _id: ObjectId('6351183b841ef5ca0e090482'),
    name: 'Yamaha Tenere 2022',
    units: [
        {
            name: 'Front wheel',
            parts: [
                {
                    SKU: 'PT00001',
                    name: 'Bolt m7'
                },
                {
                    SKU: 'PT00002',
                    name: 'Oring'
                },
            ]
        },
        {
            name: 'Rear wheel',
            parts: [
                {
                    SKU: 'PT00003',
                    name: 'Bolt m7'
                },
                {
                    SKU: 'PT00002',
                    name: 'Oring'
                },
            ]
        }
    ]
}

文档2:

{
    _id: ObjectId('6351183b841ef5ca0e090483'),
    name: 'Yamaha Tenere 2021',
    units: [
        {
            name: 'Exhaust system',
            parts: [
                {
                    SKU: 'PT00012',
                    name: 'Screw torx'
                },
                {
                    SKU: 'PT00002',
                    name: 'Oring'
                },
            ]
        },
        {
            name: 'Suspension',
            parts: [
                {
                    SKU: 'GGG02',
                    name: 'Front fork'
                },
                {
                    SKU: 'GGG02',
                    name: 'Rear fork'
                },
            ]
        }
    ]
}

期望输出(针对SKU PT00002)

{
    _id: ObjectId('6351183b841ef5ca0e090482'),
    name: 'Yamaha Tenere 2022',
    units: [
        {
            name: 'Front wheel',
            parts: [
                {
                    SKU: 'PT00001',
                    name: 'Bolt m7'
                },
                {
                    SKU: 'PT00002',
                    name: 'Oring'
                },
            ]
        },
        {
            name: 'Rear wheel',
            parts: [
                {
                    SKU: 'PT00003',
                    name: 'Bolt m7'
                },
                {
                    SKU: 'PT00002',
                    name: 'Oring'
                },
            ]
        }
    ]
},
{
    _id: ObjectId('6351183b841ef5ca0e090483'),
    name: 'Yamaha Tenere 2021',
    units: [
        {
            name: 'Exhaust system',
            parts: [
                {
                    SKU: 'PT00012',
                    name: 'Screw torx'
                },
                {
                    SKU: 'PT00002',
                    name: 'Oring'
                },
            ]
        },
    ]
}

解决方案

问题出在$filter的条件判断上:$$unit.parts.SKU返回的是当前unit下所有parts的SKU组成的数组(比如['PT00001', 'PT00002']),直接用$eq和字符串sku比较永远不成立,所以过滤后返回空数组。

正确的做法是使用$in操作符,检查指定SKU是否存在于当前unit的parts.SKU数组中:

let responseData = await Model.aggregate([
  {
    $match: {
      'units.parts.SKU': sku
    }
  },
  {
    $project: {
      name: 1, // 保留文档的name字段
      units: {
        $filter: {
          input: '$units',
          as: 'unit',
          cond: {
            $in: [sku, '$$unit.parts.SKU']
          }
        }
      }
    }
  }
]);

说明

  1. $match阶段:先筛选出至少有一个unit包含目标SKU的文档,减少后续处理的数据量。
  2. $project阶段:
    • 保留原文档的name字段(如果需要保留其他字段,也可以类似添加,比如_id:1)
    • 用$filter遍历units数组,仅保留满足条件的unit:通过$in判断目标SKU是否在当前unit的parts.SKU数组中。

这样就能得到期望的结果,只保留包含指定SKU的units元素。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 16:25:35