MongoDB:如何计算studentMarkDetails数组中指定考试的科目总分
解决MongoDB中计算指定考试类型成绩总和的问题
需求与问题
需要从studentMarkDetails数组中计算指定考试类型(如quaterly)下所有科目的成绩总和,此前使用$unwind操作符时返回0条记录,期望输出格式如下:
{ "_id": ObjectId("636efe231eeef2f46a31d7f4"), "sName": "Somu", "class": "tenth", "year": 2003, "examType": "quaterly", "total_marks": 300 }
对应的文档结构:
{ "_id": ObjectId("636efe231eeef2f46a31d7f4"), "sName": "Somu", "class": "tenth", "year": 2003, "studentMarkDetails": [ { "examType": "quaterly", "marks": { "Eng": 55, "Tel": 45, "Mat": 75, "Sec": 43, "Soc": 65 } }, { "examType": "halfyearly", "marks": { "Eng": 56, "Tel": 76, "Mat": 89, "Sec": 34, "Soc": 76 } }, { "examType": "final", "marks": { "Eng": 89, "Tel": 78, "Mat": 91, "Sec": 95, "Soc": 87 } } ] }
解决方案
方案一:无需$unwind的高效实现(推荐)
直接通过$filter筛选目标考试类型的数组元素,再用$reduce计算成绩总和,避免展开数组带来的性能损耗:
db.students.aggregate([ // 可选:如果需要限定特定文档,比如指定_id,添加此$match阶段 // { $match: { _id: ObjectId("636efe231eeef2f46a31d7f4") } }, { $addFields: { targetExam: { $first: { $filter: { input: "$studentMarkDetails", cond: { $eq: ["$$this.examType", "quaterly"] } } } } } }, { $addFields: { total_marks: { $reduce: { input: { $objectToArray: "$targetExam.marks" }, initialValue: 0, in: { $add: ["$$value", "$$this.v"] } } }, examType: "$targetExam.examType" } }, { $project: { sName: 1, class: 1, year: 1, examType: 1, total_marks: 1 } } ])
方案二:正确使用$unwind的实现
如果一定要用$unwind,需先筛选出目标考试类型的数组元素再展开,避免无效数据被展开后过滤导致无结果:
db.students.aggregate([ // 先筛选包含目标考试类型的文档,减少后续处理数据量 { $match: { "studentMarkDetails.examType": "quaterly" } }, { $addFields: { studentMarkDetails: { $filter: { input: "$studentMarkDetails", cond: { $eq: ["$$this.examType", "quaterly"] } } } } }, // 此时数组仅含目标元素,展开后不会出现无关数据 { $unwind: "$studentMarkDetails" }, { $addFields: { total_marks: { $reduce: { input: { $objectToArray: "$studentMarkDetails.marks" }, initialValue: 0, in: { $add: ["$$value", "$$this.v"] } } }, examType: "$studentMarkDetails.examType" } }, { $project: { sName: 1, class: 1, year: 1, examType: 1, total_marks: 1 } } ])
原问题原因分析
之前使用$unwind返回0条记录,通常是以下两种情况:
- 先执行
$unwind再用$match筛选examType,若原文档中无匹配元素,展开后筛选会过滤掉所有数据; - 筛选条件拼写错误(比如将文档中的
quaterly误写为quarterly)。
内容的提问来源于stack exchange,提问作者Somasekhar
相关产品推荐
相关产品推荐

