Firebase Transactions

Tools used:
Backend: Firebase -- Version: 7.7.0
Frontend: @ionic/angular -- Version: 4.7.1

Today you’ll learn how to use a Firebase feature called transactions. It is a way to update data to ensure there’s no corruption when being updated by multiple users.

For example, let’s say Mary downloads an app to manage guest registration to an event, but she soon realizes that she needs some help at the front door, there are way too many guests and if she is the only one registering them it is going to take too long.

So she asks Kate, Mark, and John for help, they download the app, log in with Mary’s password (Yeah, it could be a better idea to make it multi-tenant :P ), and they start registering users too.

Let’s say the ticket to the event is $15, and whenever a new user is registered it updates the current revenue by $15.

What happens if Mark and Kate both register new users, when Mark’s click reads the revenue it was $300 so his app took those $300, added the $15 ticket price and the new revenue should be $315 right? Wrong!

It turns out that Kate registered someone else a millisecond earlier, so the revenue already was at $315 and Mark set it to $315 again, you see the problem here right?

This is where transactions come in. They update the data safely. The update function takes the current state of the data as an argument and returns the new desired state you would like to write.

If another client writes to the location before you store your new value, your update function is called again with the new current value, and then Firestore retries your write operation.

We would write a transaction like this:

addGuest(guestName, eventId, eventPrice) {
  return firebase.firestore().collection('eventList').doc(eventId)
    .collection('guestList')
    .add({ guestName })
    .then((newGuest) => {
      return firebase.firestore().runTransaction(transaction => {
        return transaction.get(firebase.firestore().collection('eventList').doc(eventId)).then(eventDoc => {
          const newRevenue = eventDoc.data().revenue + 15;
          return transaction
            .update(firebase.firestore().collection('eventList').doc(eventId), { revenue: newRevenue });
        });
      });
    });
}

The transaction takes the current state of the event and updates the revenue property for it, and then it returns the new value making sure it is correct.