skip to Main Content

I have a 2 players game. The structure of the document is this:

{
 status: string,
 create_by: string,
 players: [
  {
   id: string,
   time: int
  },
  {
   id: string,
   time: int
  } 
 ]
}

To create the session I do this:

Future<String> createGameSession() async {
    final user = AuthProvider().getUser();
    final sessionRef = await _firestore.collection('game_sessions').add({
      'created_by': user.uid,
      'status': 'open',
      'players': [
        {
          'id': user.uid,
        }
      ],
    });
    gameSessionId = sessionRef.id;
    return sessionRef.id;
  }

And when second player joins:

Future<void> addPlayerGameSession() async {
    final user = AuthProvider().getUser();
    await _firestore.collection('game_sessions').doc(gameSessionId).update({
      'status': 'closed',
      'players': FieldValue.arrayUnion([
        {
          'id': user.uid,
        }
      ]),
    });
  }

In the UI, users can stop a timer so when this happens, I need to update document. Here is where I have the problem of not being able to update just the document I need. I have to update the entire array as documentation mentions:

enter image description here
more info: https://www.reddit.com/r/Firebase/comments/15xeiac/how_to_update_an_item_in_an_array_with_firebase/

I could face a situation where both users stop the timer almost at the same time, and last one, would update the entire array with non updated timer from the other player, before getting it from database and some information can be overwritten.

arrayUnion adds a new element to the array, but doesn’t update the one we have.

How could I do this?

2

Answers


  1. Use a transaction to prevent two clients from overwriting each others’ updates. Your transaction will simply read the document to update, them make changes to it (by updating the array field, or anything else you want). If two clients end up trying to run a transaction at the same time, one of them will be forced to automatically re-run your transaction handler to help you ensure that no data is lost.

    Login or Signup to reply.
  2. I highly recommend this video on Firestore Arrays vs Subcollections:

    Maps, Arrays and Subcollections, Oh My! | Get to know Cloud Firestore #4

    In short, the way that they work, you will always have this race condition sort of problem. The best approach for your use case is probably to just use a subcollection instead of an array. Arrays are really intended to be static objects like flags, and not a collection of dynamic data. You could use a transaction, but you may still have concurrency issues.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search