We\'re using MongoDB and I\'m figuring out a schema for storing Ratings.
from
I would do it a bit different: Have a User class and a Rating class and aggregate the number of ratings and rating average.
This is a bit of pseudo code, but the meaning should be obvious.
{
_id:ObjectId(…),
rating: Integer,
rater: User._id
rated: User._id
date: ISODate()
}
In order to do the aggregation efficiently, you should at least create an index over rated
:
db.ratings.ensureIndex({rated:1})
Now, you can decide between to approaches: either, you calculate the number of ratings and the average let's say once an hour and store it in an collection, let's say rate_averages
, or you calculate those values on demand.
db.ratings.aggregate(
// Aggregation
[{
$order: {
_id: "$rated",
ratings: { $sum:1 },
average: { $avg: "$rating" }
},
{$out:'rate_averages'}
]
)
A document in the rate_averages
collection will then look like this:
{
_id:User._id,
ratings: Integer,
average: Float
}
and is easily queryable for the individual user's values, as _id
is indexed automatically.
You'd use the same rating and almost the same aggregation query, except that we add a $match
stage so we only work with the values for the user we want to know the stats for and leave out the $out
stage and have the document to be returned directly:
db.ratings.aggregate([
{
$match:{ rated: <_id of the user we want the values for> },
},
{
$order: {
_id: "$rated",
ratings: { $sum:1 },
average: { $avg: "$rating" }
}
])
which would return a single document as shown for the user in question.
With this approach and a proper data model, you can even do such things as "How many ratings were given by a specific user on a given date?" or "What are the most active raters/the most rated?" quite easily.
Please read the aggregation framework docs for further details. You might find the data modeling docs useful, too.