13

In my Firebase database, I need two write to two locations at once. I have rules for both locations that ensure that a user can't write there without simultaneously writing to the other location.

The write to one of these locations needs to be an increment/decrement. Of course, that has to be done via a transaction, otherwise I can't guarantee that the user isn't overwriting some other user's simultaneous increment/decrement update to that same node.

The problem is, I can't find any documentation on combining multi-location updates with transactions. Is this just impossible to do?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
NudeCanalTroll
  • 2,266
  • 2
  • 19
  • 43

2 Answers2

9

No. Transactions function on a single node.

That means that if you want to run a multi-location transaction, you will essentially have to run that transaction at the "lowest level shared node" in the tree. That is hardly ever a good idea.

The alternative would be to secure your multi-location write using server-side security rules. For an example of this, see Is the way the Firebase database quickstart handles counts secure?, which essentially builds a compare-and-set operation using security rules.

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • why is a transaction at the lowest node "hardly ever a good idea"? – Ally Jr Nov 23 '17 at 08:48
  • 2
    Since this question is about updating multiple locations with one call, this means the "lowest level shared node" is likely higher in the JSON tree than of a single entity. This means that there is much more chance of resource contention, which reduces scalability of transactions. – Frank van Puffelen Nov 23 '17 at 15:41
  • Oh yeah. Thanks for the response. This makes sense. – Ally Jr Nov 24 '17 at 11:49
2

It is now possible to combine multi-path updates with transactions with the introduction of ServerValue.increment()

Example:

Map<String, Object> postLikeUpdate = new HashMap<>();
postLikeUpdate.put("postLikedBy/" + postId + "/" + userId, true);
postLikeUpdate.put("likesCount/" + postId, ServerValue.increment(1));
FirebaseDatabase.getInstance().getReference().updateChildren(postLikeUpdate);

Link to release notes

drishit96
  • 327
  • 1
  • 2
  • 18
  • what to do if the value that i need to increment is a type of String? ServerValue.increment() method does not work for this situation. Is there an alternative? – gxslash Sep 14 '20 at 02:33
  • Are you trying to increment an integer saved as a string? If yes, I suggest that you store it as an integer instead of string. It will make your work a lot easier. – drishit96 Sep 14 '20 at 17:05
  • Yes, my question was exactly that. The problem is that the value has already stored as a string in the database before. Now, i need to update database but it is really troublesome. – gxslash Sep 14 '20 at 18:25
  • I think it will be better to use a normal transaction for the string field and write a cloud function to update the integer field whenever the string is updated. Also, use multi-path updates to update the integer field in your new update. Later, you can phase out the string field completely. – drishit96 Sep 15 '20 at 05:16