4

I have a comments screen with a list of comments and a textbox at the bottom. I have two ways of saving the comment with the updated comments count:

1) Using set()

ref.child(commentsList).child(commentKey).set(true);
ref.child(commentsCount).set(++count);

2) Using update()

allCommentKeysArray[newCommentsKey] == true
var data = {
        commentscount: ++count,
        commentslist: { ...allCommentKeysArray}
    }
ref.child(path).update(data);

Now, for the offline situation, that is when the client gets disconnected from the internet, if I add multiple comments while being offline, here is what happens in both cases:

The set() works fine. All the comments which user added while being offline gets saved to firebase database when the client is back to online mode.

But update() does not seem to work when offline. When client return to online mode, the 'counts' values is not correct and only one key is added to 'commentsList' node in the firebase database.

I want to use update() instead of set() but update() does not seem to work for offline mode. So, should I stick with the set() as I need to achieve offline functionality, or is there any better way?

Murtuza
  • 308
  • 2
  • 14
  • 2
    The only safe way to increment a counter is with a transaction, and transactions only work when online. You're better of making a safe write to the database that indicates the count should be increased, then use Cloud Functions to process that on the backend safely. – Doug Stevenson May 27 '18 at 12:51
  • I was using transaction previously but I want to take advantage of Firebase's offline mode. So, first I fetch the current counts using 'value'(once) and then update the count. – Murtuza May 27 '18 at 12:56

1 Answers1

3

The update() method technically works fine. It just doesn't do what you want it to do. :-)

What happens in an offline scenario now is:

  1. The offline client adds a comment
  2. The offline client updates its own comment count
  3. The client comes back online
  4. The client sends its new comment and its own comment count to the server

The problem with this is that another client might also have added a comment before #4, and your client has never update the comment count correctly.

There are many ways to deal with this, but many of them rapidly become quite complex. The simplest two by far are:

  1. Using a transaction to both add the comment and the count (as Doug suggested in his comment). This is the simplest solution, but it won't work while the client is offline.
  2. Using Cloud Functions to increment the counter, as shown in the functions-samples repo. But since Cloud Functions run on Google's servers, this too won't work offline.
  3. Use Firebase's server-side security rules to validate that the update the client sends is only allowed if the change in commentscount matches the change(s) in the actual comments for the operation. This is quite involved, but has the advantage that it'll work when the client is offline. In the scenario above, the result would be that the server rejects the write, and your client can then retry from step 2 (after updating the comment count with the correct value from the server). If you'd like to investigate this path, it is similar to what I demonstrated in my answer here: https://stackoverflow.com/a/37956590
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks @Frank! So If I stick with 'set'(as I need offline feature), would that cause any problem or be against any of firebase best practises? The set() seems to be working fine right now. – Murtuza May 27 '18 at 15:56
  • 1
    Your actual number of comments and the counter will get out of sync if multiple users post around the same time, a scenario made significantly more likely when they're offline. – Frank van Puffelen May 27 '18 at 17:08