MongoDB聚合:能否在$sum操作符内使用$match实现属性求和?
问题解答
首先明确:$sum聚合函数里不能使用$match操作符,$match是聚合管道的独立阶段,只能作为管道中的一个步骤,不能嵌套在$sum这类表达式里使用。
针对你的需求——筛选FIGHT_PROP_CRITICAL和FIGHT_PROP_CRITICAL_HURT属性,计算(2*FIGHT_PROP_CRITICAL) + FIGHT_PROP_CRITICAL_HURT的结果并排序,下面是正确的实现方式:
假设你的原始数据结构
假设每个文档包含一个stats数组,结构如下:
{ "id": 1, "stats": [ {"propType": "FIGHT_PROP_CRITICAL", "statValue": 15}, {"propType": "FIGHT_PROP_CRITICAL_HURT", "statValue": 60}, {"propType": "FIGHT_PROP_ATTACK", "statValue": 100} ] }
正确的聚合管道
db.collection.aggregate([ // 提取目标属性值,处理缺失情况(缺失则设为0) { $addFields: { critical: { $ifNull: [ {$getField: { field: "statValue", input: {$arrayElemAt: [{$filter: { input: "$stats", cond: {$eq: ["$$this.propType", "FIGHT_PROP_CRITICAL"]} }}, 0]} }}, 0 ] }, criticalHurt: { $ifNull: [ {$getField: { field: "statValue", input: {$arrayElemAt: [{$filter: { input: "$stats", cond: {$eq: ["$$this.propType", "FIGHT_PROP_CRITICAL_HURT"]} }}, 0]} }}, 0 ] } } }, // 计算目标值 { $addFields: { totalCriticalValue: {$add: [{$multiply: [2, "$critical"]}, "$criticalHurt"]} } }, // 可选:过滤掉两个属性都为0的无效文档 { $match: { $or: [ {"critical": {$gt: 0}}, {"criticalHurt": {$gt: 0}} ] } }, // 按计算值排序(-1为降序,1为升序) { $sort: {totalCriticalValue: -1} }, // 可选:只保留需要的字段 { $project: { _id: 0, id: 1, totalCriticalValue: 1, critical: 1, criticalHurt: 1 } } ])
代码说明
- $addFields阶段:用
$filter从stats数组中筛选目标属性,$arrayElemAt取第一个匹配项,$getField提取对应的statValue,$ifNull处理属性缺失的情况,避免计算报错。 - 计算目标值:通过
$multiply计算2倍暴击值,再用$add叠加暴击伤害,得到最终的totalCriticalValue。 - 可选$match:过滤掉两个属性都不存在的文档,排除无效数据。
- $sort阶段:按计算出的结果排序,满足你的排序需求。
输入输出示例
输入文档
[ {"id": 1, "stats": [{"propType": "FIGHT_PROP_CRITICAL", "statValue": 15}, {"propType": "FIGHT_PROP_CRITICAL_HURT", "statValue": 60}]}, {"id": 2, "stats": [{"propType": "FIGHT_PROP_CRITICAL", "statValue": 20}, {"propType": "FIGHT_PROP_CRITICAL_HURT", "statValue": 50}]}, {"id": 3, "stats": [{"propType": "FIGHT_PROP_ATTACK", "statValue": 200}]} ]
输出结果
[ {"id": 2, "critical": 20, "criticalHurt": 50, "totalCriticalValue": 90}, {"id": 1, "critical": 15, "criticalHurt": 60, "totalCriticalValue": 90} // 开启可选$match后,id=3的文档会被过滤 ]
内容的提问来源于stack exchange,提问作者hat
相关产品推荐
相关产品推荐

