如何用Mongoose聚合查询筛选reason为'A'的子文档转账记录
解决MongoDB/Mongoose聚合筛选转账记录的问题
我来帮你搞定这个问题!你遇到的MongoError: Unrecognized expression '$banks.transfers.reason'错误,是因为在$cond表达式里用错了条件判断的语法——MongoDB的条件判断必须用$eq这类官方操作符,而不是直接写键值对的形式。
错误原因分析
你原来的代码里,$cond的条件部分写了{'$banks.transfers.reason' : 'A'},这不符合MongoDB的表达式规则。正确的相等判断应该用$eq操作符,格式是{ $eq: ['字段路径', '目标值'] }。不过其实针对你的需求,我们有更简洁高效的实现方式,不需要用$cond。
正确实现方案
根据你想要的按bank_name分组、只保留reason为'A'的转账记录的需求,这里提供两种可行的聚合方案:
方案一:使用$filter筛选(推荐,性能更优)
这种方法不需要展开transfers数组,直接在数组内筛选符合条件的元素,适合处理大数组场景:
Model.aggregate([ // 展开banks数组,将每个银行转换为独立文档 { $unwind: '$banks' }, // 筛选当前银行中reason等于'A'的转账记录 { $addFields: { 'banks.transfers': { $filter: { input: '$banks.transfers', as: 'transfer', cond: { $eq: ['$$transfer.reason', 'A'] } } } } }, // 可选:过滤掉没有符合条件转账的银行(如果不需要空transfers数组的话) { $match: { 'banks.transfers': { $ne: [] } } }, // 整理输出结构,只保留需要的字段 { $project: { _id: 0, bank_name: '$banks.bank_name', transfers: '$banks.transfers' } } ])
方案二:使用unwind + match + group(逻辑更直观)
这种方法通过展开数组、筛选、再分组的流程实现,适合理解聚合的基础逻辑:
Model.aggregate([ // 展开banks数组 { $unwind: '$banks' }, // 展开transfers数组,将每笔转账转换为独立文档 { $unwind: '$banks.transfers' }, // 筛选出reason为'A'的转账记录 { $match: { 'banks.transfers.reason': 'A' } }, // 按bank_name分组,收集所有符合条件的转账 { $group: { _id: '$banks.bank_name', transfers: { $push: '$banks.transfers' } } }, // 重命名_id为bank_name,整理最终输出结构 { $project: { _id: 0, bank_name: '$_id', transfers: 1 } } ])
预期输出
两种方案都能得到你想要的结果:
[ { "bank_name": "bank1", "transfers": [ { "amount": 10, "reason": "A" } ] }, { "bank_name": "bank2", "transfers": [ { "amount": 9, "reason": "A" }, { "amount": 3, "reason": "A" } ] } ]
内容的提问来源于stack exchange,提问作者DeLac
相关产品推荐
相关产品推荐

