mongodb - 用户评分模式 - 键/值数据库

标签 mongodb database-schema

我们正在使用 MongoDB,我正在寻找一种用于存储评级的架构。

  • 评分的值为 1-5。
  • 我想存储其他值,例如 fromUser

这很好,但我的主要问题是设置它,以便重新计算平均值尽可能高效。


解决方案 1 - 单独的评级等级

首先想到的是创建一个单独的Ratings类并存储指向 Ratings 的指针数组在 User类(class)。我第二次猜测的原因是我们必须查询所有 Ratings每次新的对象Rating进来,以便我们可以重新计算平均值

...

解决方案 2 - 用户类中的字典

第二个想法是将字典存储在 User 中。直接存储这些 Ratings 的类对象。这将比解决方案 1 更轻量级,但我们将重写整个 Ratings每次更新时每个用户的历史记录。这似乎很危险。

...

解决方案 3 - 用户类中具有单独平均值的单独评级类

我们有 Ratings 的混合选项在他们自己的类中,以及指向他们的指针数组,但是,我们在用户类中保留了两个值 - ratingsAveratingsCount .这样,当设置新的评级时,我们会保存该对象,但我们可以重新计算 ratingsAve很容易。


解决方案 3 对我来说听起来最好,但我只是想知道我们是否需要通过重新查询评级历史来重置 ratingsAve 来包括定期校准。只是为了确保一切正常。

我可能想多了,但我不擅长创建数据库架构,这似乎是一个标准架构问题,我应该知道如何实现。

哪个是确保一致性和重新计算效率的最佳选择?

最佳答案

首先,“用户类中的字典”不是一个好主意。为什么?添加额外的速率对象需要向数组推送一个新项目,这意味着旧项目将被删除,这种插入就是所谓的“移动文档”。移动文档很慢,而且 MongoDB 不擅长重用空白空间,因此大量移动文档会导致大量空数据文件(《MongoDB The Definitive Guide》一书中的一些文字)。

那么正确的解决方案是什么:假设您有一个名为 Blogs 的集合,并希望为您的博客文章实现评级解决方案,并另外跟踪每个基于用户的评级操作。

博客文档的架构如下:

{
   _id : ....,
   title: ....,
   ....
   rateCount : 0,
   rateValue : 0,
   rateAverage: 0
}

您需要具有此文档架构的另一个集合(Rates):

{
    _id: ....,
    userId: ....,
    postId:....,
    value: ..., //1 to 5
    date:....   
}

你需要为它定义一个合适的索引:

db.Rates.ensureIndex({userId : 1, postId : 1})//非常有用。如果您想检查用户之前是否对帖子进行过评分,这将导致更快的搜索操作

当用户想要评分时,首先您需要检查用户是否对帖子进行评分。假设用户是 'user1',那么查询将是

var ratedBefore = db.Rates.find({userId : 'user1', postId : 'post1'}).count()

并且基于 ratedBefore,如果 !ratedBefore 则插入新的 rate-document 到 Rates 集合并更新博客状态,否则,用户不允许评分

if(!ratedBefore)
{
    var postId = 'post1'; // this id sould be passed before by client driver
    var userId = 'user1'; // this id sould be passed before by client driver
    var rateValue = 1; // to 5
    var rate = 
    {       
       userId: userId,
       postId: postId,
       value: rateValue,
       date:new Date()  
    };

    db.Rates.insert(rate);
    db.Blog.update({"_id" : postId}, {$inc : {'rateCount' : 1, 'rateValue' : rateValue}});
}

那么 rateAverage 会发生什么? 我强烈建议在客户端根据 rateCountrateValue 计算它,使用 mongoquery 更新 rateAverage 很容易>,但你不应该这样做。为什么?简单的答案是:对于客户来说,处理这类工作是一项非常容易的工作,并且对每个博客文档进行平均需要进行不必要的更新操作。

平均查询将被计算为:

var blog = db.Blog.findOne({"_id" : "post1"});
var avg = blog.rateValue / blog.rateCount;
print(avg);

通过这种方法,您将获得 mongodb 的最大性能,并且您可以根据用户、帖子和日期跟踪每个速率。

关于mongodb - 用户评分模式 - 键/值数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26914380/

相关文章:

mongodb - 动态限制 MongoDB 中的文档

sql - 在数据建模中,术语 'cardinality' 与 'relation' 有何不同?

postgresql - PostgreSQL 中的模式是物理对象吗?

mysql - 网球场预订系统的数据库表

mysql - 带有非识别键的表

database-design - 学费处理数据库设计

javascript - Dropping Collection后,保存第一条记录时重新创建了Collection,但为什么它的索引没有?

ruby-on-rails - 将数据引入 MongoDB 导致 "stack level too deep"

java - 如何使用 Java 从 MongoDB 中的所有文档中获取相同键的值?

MongoDB 按名称对数组中的项目进行计数