0

I followed the tutorial pretty closely and am testing a "like" feature with a transaction. However, when I test it with 2 devices, the count doesn't seem to hold up well.

The error is when I click the like-button on both devices, there are times that the counter goes up by two, but that are times that the counter goes up then down making it increase by 0 (when in fact there were two like buttons). Similar problem when there is two un-liking buttons pressed at the same time.

Unliking both buttons (at the same time) could also cause the counters to increase by two instead... when it should be decreasing it by two.

var liked; // global variable to check if button has been liked

document.getElementById("like-button").onclick = function () {
        console.log("click");
        database.ref("brands/" + brand + "/" + dealId).transaction(function(post) {
            console.log("post:" , post);
            if (post) {
              if (post.likes && liked) {
                post.likes--;
                liked = false;
              } 
              else {
                post.likes++;
                liked = true;
              }
            }
            return post;
          });
    }

Wondering what is the problem here given I followed this transaction pretty closely. https://firebase.google.com/docs/database/web/read-and-write

Edit: JSON I have

Brand3
  Brand3ID  
    impressions:  0
    likes:  16
    views:  0

Update: I noticed that the post logs 3 times when i click the button simultaneously on 2 devices - which could possibly explain the failure in handling the global flag, but am still unable to resolve why. Usually post should only log twice, one null and one when it detects the post (Firebase realtime database transaction handler gets called twice most of the time)

Max
  • 834
  • 8
  • 19
  • The code you shared looks fine at first glance. How are you observing the problem? – Frank van Puffelen Jun 10 '20 at 04:02
  • I'm viewing the changes of the likes count in my realtime database and clicking the like button on two different devices – Max Jun 10 '20 at 04:04
  • I do notice a problem - after clicking on both devices (a couple of times), the global `liked` flag seems to mess up even for one device - a "like" causes a decrease in the count – Max Jun 10 '20 at 04:09
  • Could it be the `liked` global flag wasn't handled when the transaction failed? – Max Jun 10 '20 at 04:10
  • It's hard to say what's going wrong, as the code looks fine. Can you: 1) edit your question to include the JSON at `/brands/$brand/$dealId` (as text, no screenshots). You can get this by clicking the "Export JSON" link in the overflow menu (⠇) on your [Firebase Database console](https://console.firebase.google.com/project/_/database/data). 2) see if you can set up a minimal reproduction of the problem on a site like jsbin? – Frank van Puffelen Jun 10 '20 at 04:13
  • I have added the JSON that im writing to – Max Jun 10 '20 at 05:01
  • I added an update describing how `post` gets logged 3 times instead of 2, on a simultaneous click of the button on 2 devices - thereby switching my `liked` flag as true-false-true, and messing up the count. Any intuition on this? – Max Jun 10 '20 at 05:22

1 Answers1

1

I believe I found the answer.

I've learnt that firebase transaction will run multiple times until successful (references: https://firebase.google.com/docs/database/web/read-and-write, Firebase transactions in NodeJS always running 3 times?), hence my liked flag was always changing depending on the number of times the transaction ran.

I fixed it by extracting the flag out so that it is not dependent on the number of transactions ran.

var liked; // global variable
    document.getElementById("like-button").onclick = function () {
        if (liked){
            database.ref("brands/" + brand + "/" + dealId).transaction(function(post) {
                if (post) {
                  if (post.likes) {
                    post.likes--;
                  } 
                }
                console.log("post:" , post);
                console.log("liked: ", liked);
                return post;
              });
              liked = false;
        }
        else{ // not liked
            database.ref("brands/" + brand + "/" + dealId).transaction(function(post) {
                if (post) {
                  if (post.likes) {
                    post.likes++;
                  } 
                }
                console.log("post:" , post);
                console.log("liked: ", liked);
                return post;
              });
              liked = true;
        }
    }

Feel free to let me know if there's a more elegant way.

Max
  • 834
  • 8
  • 19