Express操作MongoDB:提交评分成功但更新平均评分报400错误求助
解决Node.js+MongoDB评分API更新平均评分的400错误
问题根源分析
你的代码里有几个关键问题直接导致了400错误和功能异常:
- 错误调用
.save():Book.updateOne()执行后返回的是MongoDB操作结果对象,不是文档实例,不存在.save()方法,这是触发400错误的核心原因。 - 异步操作未等待:
book.save()是异步Promise操作,直接调用不等待就执行updateOne,会导致数据一致性问题——新评分可能还没写入数据库,就基于旧数据计算平均分。 - 分支逻辑遗漏响应:用户已评分、书籍不存在的分支没有返回响应,会导致客户端请求挂起。
- 书籍不存在时逻辑无效:创建
newRating后没有保存到数据库,也未关联书籍ID,等于没做任何操作。
修正后的完整代码
exports.bookRating = async (req, res) => { try { const book = await Book.findOne({ _id: req.params.id }); // 处理书籍不存在的情况:创建新书籍并初始化评分与平均分 if (!book) { const newBook = new Book({ _id: req.params.id, ratings: [{ userId: req.auth.userId, grade: req.body.rating }], averageRating: req.body.rating }); await newBook.save(); return res.status(201).json({ book: newBook }); } // 验证评分范围是否合法 if (req.body.rating < 1 || req.body.rating > 5) { return res.status(400).json({ error: "La note n'est pas valide !" }); } const ratings = book.ratings; // 检查用户是否已提交过评分 const hasRated = ratings.some(rating => rating.userId === req.auth.userId); if (hasRated) { return res.status(400).json({ error: "Vous avez déjà noté ce livre !" }); } // 添加新评分并计算平均分 ratings.push({ userId: req.auth.userId, grade: req.body.rating }); const calculatedAverage = calculateAverageRating(ratings); book.averageRating = calculatedAverage; // 一次性保存所有更新,保证数据原子性 await book.save(); return res.status(200).json({ book }); } catch (error) { console.error(error); // 打印错误日志方便调试 return res.status(400).json({ error: error.message || "Erreur lors de la notation" }); } }; function calculateAverageRating(ratings) { const totalGrades = ratings.reduce((sum, rating) => sum + rating.grade, 0); return totalGrades / ratings.length; }
关键修改说明
- 改用
async/await简化异步逻辑,避免Promise嵌套,代码可读性和可维护性更高。 - 移除错误的
updateOne().save()调用,直接修改book实例的averageRating字段,通过一次book.save()完成评分添加和平均分更新,保证数据操作的原子性。 - 补全所有分支的响应返回,包括书籍不存在、评分无效、用户已评分的场景,避免客户端请求无响应。
- 修正书籍不存在时的逻辑,创建完整的Book文档并初始化评分与平均分。
- 添加错误日志打印,方便定位调试过程中出现的具体问题。
内容的提问来源于stack exchange,提问作者Brimel
相关产品推荐
相关产品推荐

