Firebase transaction () - how is a function when added to a list?

This is a rather complicated question, but I will try to explain it as simple and concise as I can ...

I use Firebase to create a multiplayer online game. I keep a list of all the rounds in the game. At the end of the round, each user is provided with a β€œStart” button, which they press when they are ready to start the next round. This round starts when at least 50% of the users clicked "Start."

I have a Firebase gameRef link for the game, a roundListRef link that represents a list of rounds, and a roundRef link that represents the current round.

I hooked up the child_added to roundListRef so that when I add a new round, it becomes all the current round:

 roundListRef.on('child_added', function(childSnapshot, prevChildName) { roundRef = childSnapshot.ref(); }); 

I can track newRoundVotes and activePlayers and easily count on 50%. If 50% is reached, a new round is added that fires every child_added event, and a new round starts from there ...

 gameRef.child('newRoundVotes').on('value', function(snapshot) { var newRoundVotes = snapshot.val(); gameRef.child('activePlayers').once('value', function(snapshot) { var activePlayers = snapshot.val(); if (newDriveVotes / activePlayers >= 0.5) addNewRound(); }); }); 

My questions are: how can I add that only one new round has been added and that all are in the same round?

For example, let's say that 10 players and 4 have already voted to launch the next round. If the 6th player votes before his child_added event is fired by the 5th player, then a round will also be added for the 6th player.

The problem is similar to .set() vs .transaction() , but not quite the same (in my opinion).

Anyone have a solution?

+4
source share
2 answers

I think that you will most likely solve this with a transaction if the names of the rounds are known in advance. For instance. if you just use / round / 0, / round / 1, / round / 2, etc.

Then you may have the code:

 function addNewRound() { var currentRound = Number(roundRef.name()); var nextRound = currentRound + 1; // Use a transaction to try to create the next round. roundRefList.child(nextRound).transaction(function(newRoundValue) { if (newRoundValue == null) { // create new round. return { /* whatever should be stored for the round. */ }; } else { // somebody else already created it. Do nothing. } }); } 

Does this work for your scenario?

+6
source

You can change your thinking a bit and use the round counter as a place to track concurrency.

 currentRound = 0; currentRoundRef.on('value', function(snapshot) { currentRound = snapshot.val(); roundRef = roundListRef.child(currentRound); }); function addNewRound() { currentRoundRef.transaction( function(current_value) { if( current_value !== currentRound ) { // the round timer has been updated by someone else return; } else { return currentRound + 1; } }, function(success) { // called after our transaction succeeds or fails if( success ) { roundListRef.child(currentRound+1).set(...); } }); } 
+1
source

All Articles