1

I want to create an app using MongoDB (NoSQL database) that allows people to vote on posts (simillar to Reddit). What's the recommended way to store votes for the users?

Probably the database structure will have to quickly respond to queries like:

Write:

  • User X votes (up or down) post A.

Read:

  • Has user X already voted for post A?
  • How many votes (up-down) does post A have?
  • Get posts ordered by vote count (top posts)

I was thinking about saving all the votes in the User document, so each user has a list of votes with the structure { voteID, postID, value }, where value can be 1 for upvote and -1 for downvote.

I read that this is fine because usually posts might have hundred of thousands of votes, but each user will usually have fewer votes than that, so votes are better distributed across the documents.

I was also thinking about caching the votes count per post, so have like a hook, each time a vote is added/removed the count for that specific document is also updated. One issue I see with this is if you ban/delete a user which has 10k votes, you will have to do 10k update operations on the posts to update the vote count.

What is the recommended way to store votes/likes in a NoSQL database?

2

If you store the votes only in the User object then when you display a page you’ll have to query every user object to see how many votes each post has if you’re trying to sort by total votes.

If it were me, I’d probably store the votes in the post object or in their own collection. Probably start out with the former until I decide it can’t work for some reason.

In the post object, I’d make a vote schema include things like date added, user id, value. I say value rather than up or down vote because it would let me set it to 1, 0, or -1 if I want. While maybe not necessary for your use case, it would make it easier to track that a user once voted on a thing and then changed their vote later (eg canceling an upvote). It would also let me assign other values to a vote if I want (eg a user could commit reputation points to a vote).

Doing it this way also let’s me see quickly what the total votes for each post are, as well I can search only the displayed votes to see if the current user votes on a given thing and what that users vote was.

As a side note, the team that wrote the Discourse platform have done some extensive commentary on voting and have a strong dislike for downvotes for a number of reasons. Might be worth thinking about as well.

  • Thank you for your answer! Unfortuantely I actually need downvotes, as users have to know if a post is actually bad. Also, I think that if the votes are stored for the user I don't actually have to make a query each time to count the votes for a specific posts if the vote count is "cached" for each post as mentioned in my question. I don't know if storing the votes separately really fits the NoSQL methodologies, storing them separately tends to be more a RDMS style. – Cristy Oct 21 '17 at 12:24
  • 1
    Yeah the downvoted point was just a side note. My main point is store the votes with the posts. You'll need it more frequently in that form and will improve query performance. What usually matters more to a given user is what they build reputation with, so you'd store reputation events with the user. Also, to your point on RDBMS style. The main question to ask about a thing is what context it makes the most sense in, almost like you would for Class design. If it makes sense in both places, then you can put it in both, but if it contains extra info that apply to neither you'd make a new coll – Paul Oct 21 '17 at 18:24
  • Another reason you might store separately the votes is if you need to keep a history of them independent of either the person or the post. For example, if a Post gets deleted, does my vote on it still count for my reputation? If a user is deleted, does their vote still affect the Post's score? – Paul Oct 21 '17 at 18:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.