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

如何基于Mongoose聚合计算各产品五星评分平均值并返回前端

如何用Mongoose计算每个产品的平均五星评分

我来帮你搞定这个平均评分的计算问题,其实只需要调整Mongoose聚合管道的几个阶段就能实现需求。针对你的场景,我们需要在聚合操作里完成分组统计总星级、统计评分次数、计算平均值这几个步骤,然后把整理好的数据返回给前端。

方案1:获取所有产品的平均评分

如果你需要一次性拿到所有产品的平均评分,可以写一个专门的控制器函数:

const { Rating } = require('../models/rating');

exports.getProductAverageRatings = async (req, res) => {
  try {
    const averageRatings = await Rating.aggregate([
      // 第一步:按productId分组,统计总星级和评分次数
      {
        $group: {
          _id: "$productId", // 以productId作为分组依据
          totalStars: { $sum: "$noOfStars" }, // 累加该产品的所有星级
          ratingCount: { $sum: 1 } // 统计该产品的评分总次数
        }
      },
      // 第二步:格式化返回数据,计算平均值
      {
        $project: {
          productId: "$_id", // 将分组的_id重命名为productId,更直观
          averageRating: { $divide: ["$totalStars", "$ratingCount"] }, // 总星级 ÷ 评分次数 = 平均值
          _id: 0 // 隐藏默认的_id字段,让返回结构更清晰
        }
      }
    ]);

    // 返回给前端成功响应
    res.status(200).json({
      success: true,
      data: averageRatings
    });
  } catch (error) {
    // 捕获错误并返回
    res.status(500).json({
      success: false,
      message: "计算平均评分失败",
      error: error.message
    });
  }
};

方案2:提交评分后返回当前产品的最新平均评分

如果你希望用户提交评分后,直接返回该产品的最新平均评分,可以修改你现有的RatingAdd函数:

const { Rating } = require('../models/rating');

exports.RatingAdd = async (req, res) => {
  try {
    // 1. 插入用户提交的新评分
    const newRating = new Rating({
      userId: req.body.userId,
      productId: req.body.productId,
      noOfStars: req.body.noOfStars
    });
    await newRating.save();

    // 2. 计算当前产品的最新平均评分
    const productAverage = await Rating.aggregate([
      { $match: { productId: newRating.productId } }, // 只筛选当前产品的评分
      {
        $group: {
          _id: "$productId",
          totalStars: { $sum: "$noOfStars" },
          ratingCount: { $sum: 1 }
        }
      },
      {
        $project: {
          productId: "$_id",
          averageRating: { $divide: ["$totalStars", "$ratingCount"] },
          _id: 0
        }
      }
    ]);

    // 返回结果,处理无评分的边界情况
    res.status(201).json({
      success: true,
      message: "评分提交成功",
      averageRating: productAverage[0] || { 
        productId: newRating.productId, 
        averageRating: 0 
      }
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: "提交评分失败",
      error: error.message
    });
  }
};

额外注意事项

  • 你的Mongoose Schema里的时间戳字段拼写有误:{timestamp: true}应该改成{timestamps: true}(复数形式),这样才能自动生成createdAt和updatedAt字段。
  • 如果你需要对平均值进行四舍五入(比如保留1位小数),可以在$project里用$round修饰:
    averageRating: { $round: [{ $divide: ["$totalStars", "$ratingCount"] }, 1] }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 18:02:39