The system itself is pretty easy to understand but tricky to implement. Moreover, security reasons made me think how to do that.
I was thinking to make the function work in frontend firebase scripts simply doing everything there as checking if there is already like/dislike posted by this user and remove/add/switch if user clicked. The problem lies in security of this method: can't user create a new function which won't check if the like was posted?
And if that's possible, how should this system work? Right now my logic:
Clicked like:
locally activate/deactivate like button and remove dislike active class if on
check docs for this user/doc like
`1`? -> remove this doc from collection
`0`? -> switch to `1`, because `0` is dislike
`undefined`? -> create doc with `vote: 1`
change (+1/-1 or +2/-2) the value of post votes fields
Same for dislike. But this sounds really complicated as for such a small feature. Maybe it is possible to wave additional collection with user/votes without losing that level of security? Or using http-triggers may help with this somehow? This feature would be much easier on some PHP-like languages, so I am freaking out right now.
post_id
user_id
To store the likes/dislikes, you create a collection called feelings
which uses post_id
+':'+user_id
as it's document id (this makes it easy to look up).
Documents in feelings
have a single field called state
that stores -1
for dislike, 1
for like.
As you mention, you can simply set or overwrite this value to whatever the user desires. If they decide to remove their 'feeling' and neither like or dislike, issue a delete command (this is cheaper than doing a write to set state to 0).
Use Cloud Functions to listen to the feelings
collection and update the post documents like/dislike count based on how this state changes (or gets created/deleted).
Security Rules can enforce only allow states of -1
and 1
, and if you're using Firebase Auth, you can trivially enforce only allowing the user matching user_id
from being able to change state.
You now have a system with the following properties:
Using the same Cloud Functions event you register to update counts, you can also use this to add or remove from a list of user ids in both a like and dislike array. This would allow you to list out users who liked or disliked a post without have to query for each individual document in the feelings
collection
Also remember that Cloud Functions has is a small chance it gets triggered more than once for a single event. If you want the counts to be guaranteed to be accurate, either make the code idempotent, or just have a manually triggered 'recount' process you can trigger if you or a user detects the counts seem off by one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With