MongoDB聚合$facet结果合并问题:按insuredId统计理赔数据
问题:MongoDB聚合$facet结果合并实现理赔统计
定义的理赔类型
type TClaim = { insuredId: number, treatmentInfo: { amount: number }[] }
原始理赔数据
[ { insuredId: 1, treatmentInfo: [{amount: 1}, {amount: 2}] }, { insuredId: 1, treatmentInfo: [{amount: 3}, {amount: 4}] }, { insuredId: 2, treatmentInfo: [{amount: 1}, {amount: 2}] } ]
期望统计结果
[ {insuredId: 1, numberOfClaims: 2, amount: 10}, {insuredId: 2, numberOfClaims: 1, amount: 3} ]
当前使用的$facet管道
$facet: { totalClaims: [ { $group: { _id: '$insuredId', totalClaims: { $count: {} } } } ], amount: [ { $unwind: { path: '$treatmentInfo'}}, { $group: { _id: '$insuredId', amount: { $sum: '$treatmentInfo.amount' } } } ] }
解决方案:合并$facet分支结果
要合并两个$facet分支的统计结果,需在$facet之后添加以下聚合阶段:
完整聚合管道
db.claims.aggregate([ { $facet: { totalClaims: [ { $group: { _id: '$insuredId', totalClaims: { $count: {} } } } ], amount: [ { $unwind: { path: '$treatmentInfo' } }, { $group: { _id: '$insuredId', amount: { $sum: '$treatmentInfo.amount' } } } ] } }, { $zip: { inputs: ['$totalClaims', '$amount'], useLongestLength: true // 兼容某分支缺失数据的场景 } }, { $unwind: '$zip' }, { $replaceRoot: { newRoot: { $mergeObjects: ['$$zip.0', '$$zip.1'] } } }, { $project: { _id: 0, insuredId: '$_id', numberOfClaims: '$totalClaims', amount: 1 } }, { $match: { insuredId: { $exists: true }, numberOfClaims: { $exists: true }, amount: { $exists: true } } } ])
关键步骤说明
- $zip:将
totalClaims和amount两个数组的元素按位置一一配对,生成包含两个统计对象的子数组。useLongestLength参数确保即使某分支存在遗漏的insuredId,另一分支的数据仍能被保留。 - $unwind:将
$zip生成的配对数组展开为单个文档,每个文档对应一组同被保险人的两类统计数据。 - $replaceRoot + $mergeObjects:将配对的两个统计对象合并为一个文档,此时文档包含
_id(对应insuredId)、totalClaims和amount字段。 - $project:重构文档结构,将
_id重命名为insuredId,totalClaims重命名为numberOfClaims,同时移除原始_id字段。 - $match:过滤可能存在的不完整文档,确保最终结果的每个文档都包含所有必填字段。
内容的提问来源于stack exchange,提问作者Nguyễn Đức Hiếu
相关产品推荐
相关产品推荐

