1

I am writing a web app on google app engine with python. I am using jinja2 as a templating engine.

I currently have it set up so that users can upvote and downvote posts but right now they can vote on them as many times as they would like. I simply have the vote record in a database and then calculate it right after that. How can I efficiently prevent users from casting multiple votes?

clifgray
  • 4,313
  • 11
  • 67
  • 116

2 Answers2

2

I suggest making a toggleVote method, which accepts the key of the item you want to toggle the vote on, and the key of the user making the vote.

I'd also suggest adding a table to record the votes, basically containing two fields:

"keyOfUserVoting", "keyOfItemBeingVotedOn"

That way you can simply do a very query where the keys match, and if an item exists, then you know the user voted on that item. (Query where keyOfUserVoting = 'param1' and keyOfItemVoted='param2', if result != None, then it means the user voted)

For the toggleVote() method the case could be very simple:

toggleVote(keyOfUserVoting, keyOfItemToVoteOn):
    if (queryResultExists):
        // delete this record from the 'votes' table
    else:
        // add record to the 'votes' table

That way you'll never have to worry about keeping track on an individual basis of how many times the user has voted or not.

Also this way, if you want to find out how many votes are on an item, you can do another query to quickly count where keyOfItemToVoteOn = paramKeyOfItem. Again, with GAE, this will be very fast.

In this setup, you can also quickly tell how many times a user has voted on one item (count where userKey = value and where itemKey = value), or how many times a user has voted in the entire system (count where userKey = value)...

Lastly, for best reliability, you can wrap the updates in the toggleVote() method in a transaction, especially if you'll be doing other things on the user or item being voted on.

Hope this helps.

Cuga
  • 17,668
  • 31
  • 111
  • 166
  • "quickly" and "count" are opposites. – Nick Johnson Jul 20 '12 at 06:29
  • GAE datastore queries happen in linear time, and the 'count()' function "is faster by a constant factor than actually retrieving all of the results". However, yes, to quickly get a count of the number of votes, the OP can increment/decrement a 'voteCount' on the item which is then retrieved anytime a fast voteCount is needed -- the increment/decrement operation is part of what would belong in the transaction I mention in the answer. – Cuga Jul 20 '12 at 17:57
1

Store the voting user with the vote, and check for an existing vote by the current user, using your database.

You can perform the check either before you serve the page (and so disable your voting buttons), or when you get the vote attempt (and show some kind of message). You should probably write code to handle both scenarios if the voting really matters to you.

Marcin
  • 48,559
  • 18
  • 128
  • 201
  • I was initially thinking a simple if statement would work but what if I have 10,000 votes? (clearly not there yet) wouldn't it be somewhat inefficient to check all of the votes for the user? or is that not as CPU expensive as I am thinking – clifgray Jul 19 '12 at 17:09
  • @clifgray You should be using the query functionality of your database to do this efficiently. – Marcin Jul 19 '12 at 17:11
  • ah okay that makes more sense. thanks that should be simple enough to implement. – clifgray Jul 19 '12 at 17:12