Im trying to add a voting system where users can upvote or downvote one time similar to reddit, with the ability to change their vote. I can get it to allow either one up or downvote, but it wont allow to change the vote. Any ideas? TIA!
You have a lot of options available here, I’ll share a couple ways I’ve done in the past for a voting system (just know it’s not the only way to go about it):
- Unique database objects per vote:
Create a new data type “Vote” with fields: voter (User: who voted), vote_count (Number: 1, 0 or -1), post (Custom data type: post being voted on)
Your custom data type (Post) should have these fields: votes (list of Vote objects), vote_tally (Number: precalculated vote count that you display on each post, this way you’re not calculating votes every time the page is loaded or a post is viewed)
When a person goes to vote on a post you run a conditional check to see if they’ve voted (do a search for: Vote, where voter=Current User, Post=parent Group’s Post). If the search:count is 0, then a new Vote object is created in the database using current User as field ‘voter’, vote_count of 1 if they voted up, -1 if voted down. Then recalculate the Post vote_tally by either: A) doing a search for Votes belonging to that Post:vote_count:sum which will calculate all combinations of 1,0,-1 and result in a number you can store in the database under the Post’s vote_tally or B) take the Result of Step 1’s Vote:vote_count and add to the parent Group’s Post:vote_tally. This second option, although faster to perform, is less reliable since multiple people could be voting at the same time and the vote_tally calculation could be thrown off.
With the above method, you’ll be able to better track voters, vote counts, and know when those votes occurred (you could even track people’s device info to prevent spam votes in the future). There’s a simpler way that is more performant but lacks the tracking abilities:
- List of users who upvoted, list of users who downvoted:
Add these fields to your Post data type: upvoters (list of Users), downvoters (list of Users), vote_tally (Number)
Same as in option 1, when a person goes to vote run a conditional check on your workflow to find out if they’ve voted before. Parent Group’s Post:upvoters doesn’t contain Current User and Parent Group’s Post:downvoters doesn’t contain Current User. After the search is complete you can then add the Current User to the list of upvoters or add to list of downvoters, followed up by calculating a new vote_tally (+1 to the vote_tally if upvote or -1 if downvote OR Post:upvoters:count minus Post:downvoters:count). If you want to allow unvoting, just do the appropriate search on click: if a person wants to flip their vote around, remove them from one list and add to the other, followed up with a recalculation of the vote_tally.
I just went with method 1, that was so simple and works perfect, thanks a ton!!
anyway this can be dumbed down for a new user?
Yes. To simplify to one dimension, such as a “Like” for an object, the simplest approach is to create a field f_user_likes that is a List of Type “User”. When a user hits the “Like” icon, simply add that user to f_user_likes but only on the condition that the user doesn’t already exist in that list. The # of likes displayed on the page is then just the same field tallied (f_user_likes:count).
To get more complicated (such as upvote and downvote) you would just change the condition upon which you add the use the to the list field (f_user_upvotes and f_user_downvotes). The user should exist in neither list in order to be added to either list. The only addition to the simple model would be a workflow for each object being clicked (upvote or downvote) rather than just one workflow for the clicking the “Like” button.
Hopefully that helps.
Hope this helps some. I changed the workflow to: “Vote Icon is clicked and User HasVoted = ‘no’” and then in the flow below is a two step, first to increase the vote number, and then to change the User HasVoted = ‘yes’ Hope this helps.
I just learned this way that is easier: change the Question to have the field of “Voted” as a LIST of USERS and then just :count: the list of users.