Node.js异步函数中使用push操作MongoDB出现相同ID重复记录问题
问题根因
- 你当前混用了
async/await异步语法和Mongoose的回调写法,导致异步逻辑混乱:Mongoose的查询方法如果传入回调函数,就不会返回Promise,外层的try/catch无法捕获到更新操作的错误,甚至可能出现响应未正确返回、前端重复触发请求的情况。 $push操作本身默认允许插入重复元素,你没有做接口幂等校验,一旦前端重复触发请求(比如用户多次点击提交、前端自动重试),就会生成多条重复评论。- 你没有对同一用户的高频重复提交做拦截,相同参数短时间多次调用接口就会插入多条重复数据。
修复方案
- 首先统一异步写法,移除回调,全用
async/await,确保错误能被正常捕获、响应能正确返回:
module.exports.commentPost = async (req, res) => { // 建议先放开注释的ID合法性校验,提前拦截非法请求 if (!ObjectID.isValid(req.params.id)) { return res.status(400).send("ID unknown : " + req.params.id); } const check_post = await PostModel.exists({ _id: req.params.id }); if (!check_post) { return res.status(400).send("ID unknown : " + req.params.id); } try { // 新增重复提交校验:判断同一用户10秒内是否给同一条帖子提交过相同内容的评论 const post = await PostModel.findById(req.params.id); const recentDuplicate = post.comment.find(item => item.commenterId === req.body.commenterId && item.text === req.body.text && Date.now() - item.timestamp < 10 * 1000 ); if (recentDuplicate) { return res.status(400).send("请勿重复提交评论"); } // 移除回调,用await接收更新结果 const updatedPost = await PostModel.findByIdAndUpdate( req.params.id, { $push: { comment: { commenterId: req.body.commenterId, commenterPseudo: req.body.commenterPseudo, text: req.body.text, timestamp: new Date().getTime(), }, }, }, { new: true } ); return res.send(updatedPost); } catch (err) { return res.status(400).send(err); } };
- 前端配合做提交防抖:评论提交按钮点击后立即置灰,直到接口返回成功/失败结果后再恢复可点击状态,避免用户误点多次触发请求。
- 如果需要彻底避免完全相同的评论插入,可以给评论对象新增唯一的请求标识字段(比如前端生成的
requestId),把$push改成$addToSet,只要requestId相同就不会重复插入。
内容的提问来源于stack exchange,提问作者byrd reda
相关产品推荐
相关产品推荐

