You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

关键修改说明

  1. 改用async/await简化异步逻辑,避免Promise嵌套,代码可读性和可维护性更高。
  2. 移除错误的updateOne().save()调用,直接修改book实例的averageRating字段,通过一次book.save()完成评分添加和平均分更新,保证数据操作的原子性。
  3. 补全所有分支的响应返回,包括书籍不存在、评分无效、用户已评分的场景,避免客户端请求无响应。
  4. 修正书籍不存在时的逻辑,创建完整的Book文档并初始化评分与平均分。
  5. 添加错误日志打印,方便定位调试过程中出现的具体问题。

内容的提问来源于stack exchange,提问作者Brimel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 10:22:48