Mongoose调用findOne后save不生效,无法更新投票文档票数如何解决?
问题原因
Mongoose 对嵌套数组内对象属性的深层变更默认无法自动触发变更跟踪,因此你修改了options[i].votes后,Mongoose 认为该文档没有发生变更,save()操作不会实际执行数据库写入。
解决方案1:手动标记变更(适配你现有写法)
在调用save()前手动标记options字段发生了变更即可,同时建议补充错误处理逻辑避免空值报错:
router.put("/vote", async (req, res) => { try { let pollId = req.body.pollId; let voteTarget = req.body.voteTarget; const filter = { pollId: pollId }; let pollToUpdate = await Poll.findOne(filter); if (!pollToUpdate) { return res.status(404).send("对应投票不存在"); } let newPollValue; let targetExists = false; for (let i = 0; i < pollToUpdate.options.length; i++) { if (pollToUpdate.options[i].label === voteTarget) { targetExists = true; pollToUpdate.options[i].votes += 1; newPollValue = pollToUpdate.options[i].votes; break; } } if (!targetExists) { return res.status(400).send("投票选项不存在"); } // 手动标记options字段发生变更 pollToUpdate.markModified('options'); await pollToUpdate.save(); res.status(200).send( "successfully updated poll value for " + voteTarget + " to value " + newPollValue ); } catch (err) { res.status(500).send("更新失败:" + err.message); } });
解决方案2:使用原子操作直接更新(更推荐)
不需要先查询再修改,直接通过MongoDB的$inc原子操作完成票数递增,不仅写法更简洁,还能避免并发请求下的票数计算错误问题:
router.put("/vote", async (req, res) => { try { let pollId = req.body.pollId; let voteTarget = req.body.voteTarget; const updateResult = await Poll.findOneAndUpdate( // 匹配条件:投票ID匹配 + 选项标签匹配 { pollId: pollId, "options.label": voteTarget }, // 原子操作:给匹配到的数组元素的votes字段加1 { $inc: { "options.$.votes": 1 } }, // 可选配置:返回更新后的文档 { new: true } ); if (!updateResult) { return res.status(404).send("投票或对应选项不存在"); } res.status(200).send(`successfully updated poll value for ${voteTarget}`); } catch (err) { res.status(500).send("更新失败:" + err.message); } });
内容的提问来源于stack exchange,提问作者plutownium
相关产品推荐
相关产品推荐

