We\'re using MongoDB and I\'m figuring out a schema for storing Ratings.
from
First of all 'Dictionary in User Class' is not a good idea. why? Adding extra rate object requires pushing a new item to the array, which implies the old item will be removed, and this insertion is so called "moving a document". Moving documents is slow and MongoDB is not so great at reusing empty space, so moving documents around a lot can result in large swaths of empty data file (some text in 'MongoDB The Definitive Guide' book).
Then what is the correct solution: assume you have a collection named Blogs, and want to implement a rating solution for your blog posts, and additionally keep track of every user-based rate operation.
The schema for a blog document would be like:
{
_id : ....,
title: ....,
....
rateCount : 0,
rateValue : 0,
rateAverage: 0
}
You need another collection (Rates) with this document schema:
{
_id: ....,
userId: ....,
postId:....,
value: ..., //1 to 5
date:....
}
And you need to define a proper index for it:
db.Rates.ensureIndex({userId : 1, postId : 1})// very useful. it will result in a much faster search operation in case you want to check if a user has rated the post previously
When a user wants to rate, firstly you need to check whether the user has rated the post or not. assume the user is 'user1'
, the query then would be
var ratedBefore = db.Rates.find({userId : 'user1', postId : 'post1'}).count()
And based on ratedBefore
, if !ratedBefore
then insert new rate-document to Rates collection and update blog status, otherwise, user is not allowed to rate
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}});
}
Then what is gonna happen to rateAverage
?
I strongly recommend to calculate it based on rateCount
and rateValue
on client side, it is easy to update rateAverage
with mongoquery
, but you shouldn't do it. why? The simple answer is: this is a very easy job for client to handle these kind of works and putting average on every blog document needs an unnecessary update operation.
the average query would be calculated as:
var blog = db.Blog.findOne({"_id" : "post1"});
var avg = blog.rateValue / blog.rateCount;
print(avg);
With this approach you will get maximum performance with mongodb an you have track of every rate based by user, post and date.