Best method for storing user votes/ratings in mongodb

I have a star rating feature in my meteor app. I need to limit it to one vote per user per object. I need to display the average rating per object and also allow users to change their vote.

In mysql I could create a new table with 3 columns (objectID, userID, rating). In mongodb I’m not sure of the best method for storing that data. Let’s say that an object receives thousands of votes and one of the users wants to change their vote from 3 stars to 5 stars. If the data is stored in an array then I would have to loop through every entry until I found the correct user id and then change the corresponding property.

If I’m trying to calculate the average rating for each object then I’d have to loop through the votes array for each object and sum all ratings. If there are 50 objects on a page, each with a rating, and each having hundreds to thousands of votes each… There just doesn’t seem to be an efficient way to store the data in a non-relational db.

What’s the most effective and efficient way to store a user rating and calculate an average rating?

{
objectID: 1,
votes: [{userID: 1, rating: 5}, {userID: 2, rating: 3}]
}

Would it make more sense to do something like this? How can I count the total number of properties in the votes object?

{
objectID: 1,
votes: {uid1: 5, uid2: 3}
}

Seems like you’re going to do a lot with the votes, things like aggregation, average and whatnot.

Maybe its best to go for a new collection and set up foreign keys for userID, objectID aside from the unique voting properties

votes collection 

{
	userId: "123",
	objectId: "abc",
	rating: 5
}

That makes perfect sense. I just discovered the $avg operator. When used on a new votes collection it seems the logical choice for storing and calculating ratings. Thanks!

votes.aggregate(
   [
     {
       $group:
         {
           _id: "$objectId",
           avgRating: { $avg: "$rating" }
         }
     }
   ]
)
1 Like