NodeJS+Mongoose嵌套函数执行异常:取消预订接口故障求助
问题排查与解决方案
首先看你代码里的核心语法错误:在findOneAndUpdate调用的结尾,你错误地加了一个逗号,然后把回调函数写在了外面——这就导致这个回调函数根本不会被findOneAndUpdate触发,相当于你只执行了更新操作,但没有监听它的完成结果,也不会处理响应。
除此之外,你当前的更新逻辑还有一个隐患:先查询图书再手动修改quantity,再执行更新,这种操作不是原子性的,如果同时有多个取消请求进来,可能会出现数量更新不准确的问题。
具体修正步骤:
修复回调函数的语法问题
把回调函数作为findOneAndUpdate的第三个参数传入,而不是用逗号分开。不过更推荐你用Promise/async-await的写法,回调嵌套容易出错,代码可读性也差。使用MongoDB的原子更新操作
$inc
直接用$inc来让quantity字段自增1,不需要先查询再修改,这样能保证操作的原子性,避免并发问题。
修正后的代码示例(改用async-await优化可读性):
router.post('/cancel-reservation', async (req, res) => { try { const reservation = req.body.reservation; // 第一步:删除预订记录 await Reservation.findByIdAndRemove(reservation._id); // 第二步:处理图书数量 const book = await Book.findById(reservation.idBook); if (!book) { // 图书不存在则创建 const bookObj = { name: reservation.nameBook, description: reservation.description, publishingHouse: reservation.publishingHouse, quantity: 1, year: reservation.year, sites: reservation.sites }; const newBook = new Book(bookObj); const savedBook = await newBook.save(); return res.json(savedBook); } // 图书存在则原子更新数量 const updatedBook = await Book.findOneAndUpdate( { _id: book._id }, { $inc: { quantity: 1 } }, // 用$inc原子自增,更安全 { new: true } // 返回更新后的文档,而不是更新前的 ); console.log('更新完成:', updatedBook); res.json(updatedBook); } catch (err) { console.error('操作出错:', err); res.status(500).json({ error: err.message }); } });
关键说明:
- 用
async-await替代嵌套回调,代码逻辑更清晰,也更容易捕获错误。 - 使用
$inc替代手动修改quantity,保证数据库操作的原子性,避免并发场景下的数量错误。 - 统一用
try-catch捕获所有异步操作的错误,避免throw err导致服务器崩溃,同时给客户端返回合适的错误响应。
如果你坚持要用回调写法,那需要把回调函数正确传入findOneAndUpdate,修正后的回调版本片段如下:
// ... 前面的代码不变 else if (book) { Book.findOneAndUpdate( { _id: book._id }, { $inc: { quantity: 1 } }, { new: true }, (err, complete) => { if(err) { console.log('errrrrr:', err); return res.status(500).json({ error: err.message }); } console.log(complete); console.log('complete'); res.json(complete); } ); } // ...
这个错误确实和回调嵌套的写法有关——嵌套太深很容易犯这种语法错误,改用Promise/async-await能大大降低这类问题的出现概率。
内容的提问来源于stack exchange,提问作者Bartłomiej Flis
相关产品推荐
相关产品推荐

