How would you go about a real time liking a post functionality?

I want to have a posts type. This type has a field called likes. If a user clicks in the ui to like a post then a mutation should be send to dgraph to increase the likes of that post by 1. Users should only be able to like a post once. Likes would be of type Int. After a post is liked a subscription should be send out to people having that post on the screen so I can have the likes update in real time.

It is currently not clear how to do the functionality described above without getting into race conditions. This is because it looks like with the update mutations you can only set or remove fields but not increase them. This means that the client has to decide what to set as the new value of likes as you can’t say increase whatever the current value is now with x.

So what I want to do would look like something as the following

  1. Query to get user data.
  2. Check if user has liked the post already
  3. If not, query for the post data. (this data is probably already with the client)
  4. Read the current amount of likes
  5. Increase the value by 1
  6. Send a update mutation to set this new value of likes
  7. Add the post to the users liked_post field (This would be of type [Post])
  8. The ui is updated with a subscription

Some of this data may or may not be already with the client before a like happens but there is still the risk of a race condition.
For instance what if people like at the same time. If the like of the one user has not reached the other user then the like of the first user will be overwritten because the like of the second user is based on old data.

Even if I would do a lambda function then that function would still need to first query the likes that the post already has to then send back a +1 version of that. If someone else happens to like at the same time then the lambda function executing for that user could happen to query the current amount of likes in a post before the other lambda function finished the update mutation and then there is a again a like not counted.

How would I make this system without a race condition? Is there something like an increase update mutation that I have missed.

Dgraph metadata

dgraph version

I am using slash

This is a use case for a custom mutation backed by a Lambda that does this with DQL. Using DQL, you can read a value and perform a math operation and set the value all in a single transaction using upserts. The auto generated API aides with all simple CRUD operations, but what you are describing is business logic.

For this functionality, it might be easier to add an edge from the post to users who like the post. Then when a user likes a post it is a simple mutation to set the user on the edge. If it is already there no action will be taken. When a user unlikes a post it is a simple mutation to remove themselves from the like edge. . You can still query and subscribe to the count of the aggregate edge on this as well.

Thanks @verneleem in the end I also went with this solution.

1 Like

The graph way would be to create an edge called “votes” that is defined by two nodes: User and Post. And this edge holds some data also, so for a particular link you could have either a weight value that increases, or create one edge per vote (and just need some metadata to the edge like date of creation)

The problem with this approach is that even if it is the natural one (and the point behind Graphs…) , edges with data are second class citizens in both graphql and the graphql part of dgraph.