如何利用MongoDB聚合框架计算问卷数组答案的统计数据?
MongoDB 问卷答案统计聚合方案
针对你这种数组存储多问题答案的场景,我们可以通过MongoDB聚合框架的多阶段处理实现按问题维度的占比统计,具体管道如下:
假设所有问卷提交文档都在survey_responses集合中,且每个问题的可选答案固定为A、B、C:
db.survey_responses.aggregate([ // 1. 拆分answers数组,保留每个元素的索引(对应问题编号:索引+1) { $unwind: { path: "$answers", includeArrayIndex: "questionIndex" } }, // 2. 按问卷ID、问题索引、答案分组,统计每个答案的提交次数 { $group: { _id: { surveyId: "$surveyId", questionIdx: "$questionIndex", answer: "$answers.answer" }, count: { $sum: 1 } } }, // 3. 按问卷ID、问题索引再次分组,汇总该问题的总提交数和各答案统计 { $group: { _id: { surveyId: "$_id.surveyId", questionIdx: "$_id.questionIdx" }, total: { $sum: "$count" }, answerStats: { $push: { answer: "$_id.answer", count: "$count" } } } }, // 4. 补全未出现的答案(设为0次),并计算占比 { $project: { _id: 0, surveyId: "$_id.surveyId", question: { $concat: ["Question ", { $toString: { $add: ["$_id.questionIdx", 1] } }] }, stats: { $map: { input: ["A", "B", "C"], as: "opt", in: { answer: "$$opt", percentage: { $round: [ { $multiply: [ { $divide: [ { $ifNull: [ { $arrayElemAt: [ "$answerStats.count", { $indexOfArray: ["$answerStats.answer", "$$opt"] } ] }, 0 ] }, "$total" ] }, 100 ] }, 0 // 保留0位小数,可根据需求调整 ] } } } } } }, // 5. 可选:按问题编号排序 { $sort: { question: 1 } } ])
步骤说明:
- $unwind拆分数组:把每个答案拆成独立文档,同时用
includeArrayIndex记录该答案对应的问题位置(索引从0开始,对应问题1、2...)。 - 第一次$group统计次数:统计同一问卷下,同一问题的每个答案被提交的次数。
- 第二次$group汇总问题维度数据:计算每个问题的总提交数,同时把各答案的统计结果整合到数组中。
- $project补全选项并计算占比:通过
$map遍历所有可选答案,用$indexOfArray匹配已统计的结果,未匹配到的用$ifNull设为0次,再通过除法和乘法计算百分比,最后用$round控制小数位数。 - $sort排序:按问题编号顺序输出结果。
输出示例:
[ { "surveyId": "xxxxx", "question": "Question 1", "stats": [ { "answer": "A", "percentage": 50 }, { "answer": "B", "percentage": 40 }, { "answer": "C", "percentage": 10 } ] }, { "surveyId": "xxxxx", "question": "Question 2", "stats": [ { "answer": "A", "percentage": 60 }, { "answer": "B", "percentage": 40 }, { "answer": "C", "percentage": 0 } ] } ]
如果需要更贴近你期望的纯文本格式,可以在应用层对聚合结果做简单格式化,这比在MongoDB中拼接字符串更灵活。
内容的提问来源于stack exchange,提问作者user824624
相关产品推荐
相关产品推荐

