Evan
Evan

Reputation: 880

Sending push notification on firestore document field change

I have a Flutter app that lets users rent items from eachother with Firestore RTDB. In my rental document, I have a field status that determines the status of the rental (think of it like shipping an item, where items can have status of 'ordered', 'shipped', 'delivered' etc). My status variable is a number between 0 and 5, and each number represents a different phase. When the status variable changes, I want to notify the other user in the rental with a push notification. But I don't know which of the following methods is best.

  1. The first way is to use a cloud function that triggers every time the rental document is updated. But I only check for the status field. It would look something like this:

    exports.notify = functions.firestore.document('rentals/{rentalId}')
    .onUpdate(async (snapshot, context) => {
        const oldSnap = snapshot.before.data(); // previous document        
        const newSnap = snapshot.after.data(); // current document       
    
        // status changes from 0 to 1
        if (oldSnap.status === 0 && newSnap.status === 1) {
            // do something
        }
    })
    

    The one downside I can think of is I would have to do another read to get the device push token of the other user. Also, for every rental document update this cloud function will trigger, and ultimately may not even need to execute in the first place

  2. The other way would be to have a notifications collection that stores notifications, and have a cloud function that triggers when a new notification document is added. Then, on the client side, when the user taps a button, update the status in the rental as well as create a new notification document.

    Firestore.instance
        .collection('rentals')
        .document(rentalId)
        .updateData({'status': newStatus});
    
    Firestore.instance.collection('notifications').add({
      'title': title,
      'body': body,
      'pushToken': <TOKEN HERE>,
    });
    

    In comparison to method 1, this does an extra write instead of a read.

Which method is better?

Upvotes: 4

Views: 3207

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598668

Both approaches can technically work and are valid. Which one you choose is depending on the use-case, and (given that both can work here) on personal preference. That's why I'll simply highlight a few key differences below, and explain when I personally choose to use which one.

The first approach you describe is treating your database like a state machine, where each state and state transition has specific meaning. You then use Cloud Functions to trigger code in the state transition.

The second approach treats the database as a queue, where the presence of data indicates what needs to happen. So Cloud Functions then triggers on the simple presence of the document.

I typically use a queue based approach for production work, since it makes it very easy to see how much work is left to be done. Anything in your notifications collection is a notification that needs to be sent.

In the state-transition data model it is much harder to see this information easily. In fact, you'll need to add extra fields to the document in order to be able to get this list of "pending notifications". For example: rentals with a pending notification are rentals where the timestamp that the status changed from 0 to 1 (a field you'll need to add, e.g. status_1_timestamp) is smaller than the timestamp the last notification was sent (a field like notification_timestamp).

But I sometimes use the state transition approach too. Usually when I want to transform the existing document, or because it's just a cool use-case to show (as in most cases the Firebase/Firestore SDKs would not expose both the old and new state).

I'd probably pick the queue based approach here, but as said before: that's a personal preference for me based on the reasoning above. If those reasons don't apply to you, or you have different reasons, that can be fine too.

Upvotes: 4

Related Questions