【问题标题】:How to calculate Rating in my MongoDB design如何在我的 MongoDB 设计中计算评级
【发布时间】:2015-01-04 16:15:51
【问题描述】:

我正在创建一个系统,用户可以对某个项目进行评论并从 0 到 5 对其进行评分。我正在为此使用 MongoDB。我的问题是找到计算产品架构中总评分的最佳解决方案。我不认为查询所有 cmets 以获取大小并将其除以总评级是一个很好的解决方案。这是我的架构。我感谢任何建议:

评论:

var commentSchema = new Schema({
Rating : {  type: Number, default:0 },
Helpful : {  type: Number, default:0 },
User :{
    type: Schema.ObjectId,
    ref: 'users'
     },
Content: String,


});

这是我的项目架构:

var productSchema = new Schema({
 //id is barcode
_id : String,
Rating : {  type: Number, default:0 },
Comments :[
    {
        type: Schema.ObjectId,
        ref: 'comments'
    }
],

});

编辑:这是我从另一个主题得到的解决方案:calculating average in Mongoose

【问题讨论】:

  • 你真的想要total(如总和),还是不想得到平均
  • @Philipp 我想要平均,因为最终评分也必须在 0-5 之间。

标签: node.js mongodb database-design architecture mongoose


【解决方案1】:

需要了解的潜在问题是为什么您认为查找所有评级、将它们相加并除以总数不是一种有用的方法。了解根本原因将有助于推动更好的解决方案。

根据下面的 cmets,听起来您主要关心的是性能以及每次用户想要查看总评分时都需要运行 map-reduce(或其他聚合框架)。

此人在此处解决了类似问题:http://markembling.info/2010/11/using-map-reduce-in-a-mongodb-app

他们确定的解决方案是将 map-reduce 函数的执行与视图中查看总值的需求分开。在这种情况下,最佳解决方案是定期运行 map-reduce 并将结果存储在另一个集合中,并根据存储平均值的集合获得平均评分,而不是每次都实时计算。

正如我在此答案的上一版本中提到的,您可以通过将 map-reduce 限制为添加最近创建或更新的评级或自上次 map-reduce 聚合以来的评级来进一步提高性能。

【讨论】:

  • 您的帖子提供了宝贵的意见,但不幸的是它没有回答问题。因此,除非您对其进行编辑以添加问题的实际解决方案,否则恐怕我不得不对其投反对票。
  • 嗯,是的,我想避免 map-reduce,而且我认为每次用户想要查看评分时查询所有评分并除以大小并不是最佳选择。我想也许我可以删除产品并在我的评论中添加产品 ID,这样我只需要处理 1 个模式,但我仍然必须查询 Comments.find(_id:item-id){}。我真的很困惑。
  • @Philipp - 这取决于 Hirad 的问题是什么。我认为他不太关心如何执行实际操作,而更关心缩小操作范围。所以我认为在这里添加一个 map-reduce 示例是矫枉过正的。不过,我很感激您为什么不赞成我的回答,并已对其进行了更新以反映您的反馈。
【解决方案2】:

您可以使用聚合框架获取总数。首先,您使用$unwind 运算符将 cmets 转换为文档流:

 { $unwind: "$Comments" }

结果是,对于每个产品文档,其Comments 数组中的每个条目都会转换为一个产品文档。该评论条目将转换为字段Comments 下的单个对象,所有其他字段均取自原始产品文档。

然后您使用$group 通过它们的_id 重新加入每个产品的文档,同时使用$avg 运算符计算评级字段的平均值:

 { $group: {
     _id: "$_id",
     average: { $avg: "$Comments.Rating" }
 } }

将这两个步骤放入聚合管道中,可以计算出您收藏中每个产品的平均评分。您可能希望将其缩小到一个或一小部分产品,具体取决于用户现在的要求。为此,请在管道前面添加 $match 步骤。 $match 对象的工作方式与您传递给 find() 的对象一样。

【讨论】:

  • 我有点困惑。那么这是否意味着我可以从我的产品架构中删除 Rating:?我应该将产品 ID 添加到我的评级架构吗?而且我还应该在哪里/如何在猫鼬中编写您的代码?我应该这样使用它: Product.aggregate([ { $match: { _id: req.body.id }}, { $unwind: "$Comments" }, { $group: { _id: "$_id", average : { $avg: "$Comments.Rating" } }} ]
  • 此聚合不需要产品中的评级字段。但是,当用户给出评分的频率远低于查询产品的用户时,您可以通过重新计算评分来优化查询性能,正如我在用户发布评分并将结果缓存在产品文档中所展示的那样。这使您无需通过每次浏览量的聚合重新计算评分即可获得评分。
  • Philip 您的代码不会计算平均值。平均值始终为 0。我写的和我之前评论中写的完全一样。这就是我得到的结果:[ { _id: '0747532699', average: 0 } ]。 0747532699 是我的产品 ID
  • 显然我无法引用 Comments.Rating,因为它在另一个集合中。有什么解决办法吗?
  • @HiradRoshandel 引用而不是嵌入在 MongoDB 中总是存在问题。毕竟,它不是关系数据库。但是,当您将另一个字段添加到引用它所适用的产品的评论文档中时,您可以查询评论集合并按产品对其进行分组。
猜你喜欢
  • 1970-01-01
  • 2015-08-27
  • 2014-11-20
  • 1970-01-01
  • 1970-01-01
  • 2015-04-28
  • 2016-12-19
  • 2012-01-17
  • 2012-04-29
相关资源
最近更新 更多