如何在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'] } } } } } ]);
说明
$match阶段:先筛选出至少有一个unit包含目标SKU的文档,减少后续处理的数据量。$project阶段:- 保留原文档的
name字段(如果需要保留其他字段,也可以类似添加,比如_id:1) - 用
$filter遍历units数组,仅保留满足条件的unit:通过$in判断目标SKU是否在当前unit的parts.SKU数组中。
- 保留原文档的
这样就能得到期望的结果,只保留包含指定SKU的units元素。
内容的提问来源于stack exchange,提问作者feyen01
相关产品推荐
相关产品推荐

