【问题标题】:Mongoose/Express : average of subdocumentsMongoose/Express:子文档的平均值
【发布时间】:2015-06-02 01:39:03
【问题描述】:

我有以下型号:

产品:

var ProductSchema = new Schema({
name: String,
comments: [{ type: Schema.Types.ObjectId, ref: 'Comment'}],
_user: { type: Schema.Types.ObjectId, ref: 'User'}
});

评论:

var CommentSchema = new Schema({
text: String,
rating: Number,
_product: { type: Schema.Types.ObjectId, ref: 'Product'}
});

我目前所做的是检索所有产品及其用户:

router.get('/', function(req, res, next) {
Product.find().populate('_user').exec(function (err, products) {
    if (err) return next(err);
    res.json(products);
});
});

我想在结果中添加一个“平均”字段,其中包含每种产品的所有 cmets 的平均值,因此结果如下所示:

[{name: "Product 1", _user: {name: "Bob"}, average: 7.65},...]

这可以通过唯一查询实现吗?每次添加新评论时,我是否需要计算平均值并将其存储在产品文档中?

谢谢!

【问题讨论】:

标签: node.js mongodb mongoose aggregation-framework


【解决方案1】:

也许您应该尝试计算“运行平均值”。 您只需要知道有多少评分,以及它们的平均值是多少。为 MongoDB 中的每个文档保存相同的平均值应该是不好的做法,我希望这会对你有所帮助。 所以你可以像这样创建模式:

var AverageProductRatingSchema = new Schema({
  productId:       {type: Schema.Types.ObjectId, ref: 'Product'},
  averageRating:   {type: Number},
  numberOfRatings: {type: Number}
});

然后只需实现 addRating() 函数,如下所示:

function addRating(newRating, productId) {
  /* Find document that holds average rating of wanted product */
  AverageProductRating.findOneAsync({productId: productId})
    .then(function (avgProdRating) {

       /* 
         Calculate new average using the Running Average method.
         http://www.bennadel.com/blog/1627-create-a-running-average-without-storing-individual-values.htm
       */
       var newAverageRating = (avgProdRating.averageRating * avgProdRating.numberOfRatings + newRating) / (avgProdRating.numberOfRatings + 1);
       var newNumberOfRatings = avgProdRating.numberOfRatings + 1;

       AverageProductRating.update(
         { productId: productId },
         {
           $set: {
             averageRating:   newAverageRating,
             numberOfRatings: newNumberOfRatings 
         }
       });
     });

}

这是描述类似问题的链接: http://www.bennadel.com/blog/1627-create-a-running-average-without-storing-individual-values.htm

【讨论】:

  • 为什么说每个文档都保存相同的平均值?每个产品都有其所有评论的平均值。平均值存储在产品文档中,只有在添加、更改或删除新评论时才会重新计算。
  • 也许我们有一点误会。我想帮助你,这样你就不必通过所有 cmets 计算新的评级。您只需从新评论中添加评分并进行简单计算。现在想象一下,您有数千个对某些产品有评级的 cmets。每次需要平均评分时,您都必须查询所有 cmets 的 DB 并计算平均值。这种“运行平均”算法应该可以防止这种情况。当然,您可以将平均评分保存在您已有的产品文档集合中。
  • 哦,我明白你的意思了,这是有道理的。谢谢!
猜你喜欢
  • 2020-05-27
  • 2016-06-14
  • 2019-10-09
  • 2012-11-04
  • 1970-01-01
  • 2021-05-07
  • 2017-09-25
  • 2021-05-16
  • 2014-09-15
相关资源
最近更新 更多