如何在MongoDB中查询条目时统计各选项的投票数?
嘿,我懂你现在的需求——要查询投票条目时,同时返回每个选项的对应投票数对吧?刚接触MongoDB的聚合、lookup这些概念确实需要点时间适应,我一步步给你拆解怎么实现这个需求,完全贴合你给出的数据模型和期望结果。
首先先确认下:看你给出的Votes数据,里面的entryId其实应该是指向选项的_id对吧?(可能是字段名笔误,不过我先按你给的字段来写,后面会提怎么改)
实现思路
核心思路是先统计每个选项的投票数,再把统计结果关联到对应的条目选项上,同时要保证所有原始选项都保留,哪怕是0票的选项。用MongoDB的聚合管道可以分两步完成:
- 对Votes集合分组统计每个选项的投票数,再和Entries做关联
- 把统计的投票数匹配到每个条目对应的选项中,补全0票的情况
完整聚合查询代码
db.Entries.aggregate([ // 第一步:关联Votes并获取当前条目下所有选项的投票统计 { $lookup: { from: "Votes", let: { entryOptions: "$options" }, pipeline: [ // 先统计每个选项的总票数 { $group: { _id: "$entryId", // 这里如果你的字段是optionId,就改成"$optionId" votes: { $sum: 1 } } }, // 只保留当前条目包含的选项的统计结果 { $match: { $expr: { $in: ["$_id", "$$entryOptions._id"] } } } ], as: "voteCounts" } }, // 第二步:将投票数匹配到对应的选项上,补全0票的情况 { $project: { options: { $map: { input: "$options", as: "opt", in: { _id: "$$opt._id", name: "$$opt.name", votes: { $let: { vars: { // 从voteCounts里找到当前选项对应的统计项 matchedVote: { $arrayElemAt: [ { $filter: { input: "$voteCounts", cond: { $eq: ["$$this._id", "$$opt._id"] } } }, 0 ] } }, // 如果没找到匹配的统计项,就设为0 in: { $ifNull: ["$$matchedVote.votes", 0] } } } } } } } } ])
逐阶段解释
$lookup阶段:这里用了带子管道的lookup(MongoDB 3.6+支持),比普通lookup更灵活:
- 先定义变量
entryOptions存储当前条目的所有选项 - 子管道里先对Votes按
entryId分组,统计每个选项的投票数 - 再用
$match过滤出只属于当前条目的选项统计结果,最后放到voteCounts数组中
- 先定义变量
$project阶段:
- 用
$map遍历原始的options数组,给每个选项添加votes字段 - 用
$filter从voteCounts里找到和当前选项_id匹配的统计项,再用$arrayElemAt取出唯一的结果 - 最后用
$ifNull处理没有投票的情况,直接赋值为0
- 用
小提示
如果你的Votes集合里,指向选项的字段不是entryId而是optionId(更合理的命名),只需要把$group里的_id: "$entryId"改成_id: "$optionId"就行。
执行这个聚合查询后,就能得到你期望的结果:每个条目下的所有选项都会带上对应的投票数,0票的选项也不会被漏掉。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

