如何在Mongoose中查询辩论列表并添加用户是否投票的isVoted标记
问题原因分析
$lookup关联votes集合后返回的votes是数组类型,$votes.user会提取为所有投票用户ID组成的数组,直接用$eq和单个用户ID比较永远不成立,所以isVoted字段计算失败。- 原
$project阶段没有保留Votes(模型中字段为大写开头)和category关联数据,导致输出缺少对应字段。 - 没有关联Category集合,无法拿到分类name数据。
- 原
$cond返回的是字符串类型的'true'/'false',不符合预期的布尔值类型。
修复后的查询代码
// 需提前引入mongoose的ObjectId const ObjectId = require('mongoose').Types.ObjectId; // 建议先校验req.query.userId是否为合法ObjectId格式,避免转换报错 if (!ObjectId.isValid(req.query.userId)) { return res.status(400).json({ success: false, status: 400, message: '用户ID格式错误' }); } DebateData.aggregate([ { $match: query }, { $sort : { createdAt : -1 } }, // 关联分类集合获取分类名称,from参数替换为Category模型对应的实际物理集合名 { $lookup: { from: "categories", localField: "category", foreignField: "_id", as: "category" } }, // 关联投票集合,直接过滤当前用户的投票记录,减少后续计算量 { $lookup: { from: "votes", let: { debateId: "$_id" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: [ "$debate", "$$debateId" ] }, { $eq: [ "$user", ObjectId(req.query.userId) ] } ] } } } ], as: "userVote" } }, // 计算isVoted字段,映射投票数字段名匹配预期输出 { $addFields: { 'isVoted': { $gt: [ { $size: "$userVote" }, 0 ] }, 'votes': "$Votes" } }, // 保留所有需要返回的字段 { $project: { '_id': 1, 'question': 1, 'isVoted': 1, 'createdAt': 1, 'votes': 1, 'category.name': 1 } }, ]).then(result => { res.status(200).json({ success: true, status: 200, message: 'Debate videos', data: result}); }).catch(err => { res.status(500).json({ success: false, status: 500, message: err.message }) });
关键修改说明
- 新增Category集合关联逻辑,拿到分类name数据,匹配预期输出的category字段结构。
- 优化投票关联逻辑,直接在lookup阶段过滤当前用户的投票,后续只需判断返回数组长度即可得到isVoted状态,比全量拉取所有投票再过滤效率更高。
- 修复isVoted计算逻辑,返回布尔值而非字符串。
- 映射模型中大写开头的
Votes字段为小写votes,和预期输出字段名保持一致。 $project阶段补充了需要返回的votes和category字段,避免丢失数据。
内容的提问来源于stack exchange,提问作者Sachin Kumar
相关产品推荐
相关产品推荐

