Sampath
Sampath

Reputation: 65978

Detect changes in Firestore db node within client side code

Could you tell me how to detect changes in Firestore db node within client side code (.ts file)? I know how to do that using cloud functions. But how can I do that within client side code?

Firestore Node: projects/{id}/transactions/

My requirement is this: I need to upgrade provider's(i.e. projectProvider) shared property value if there is any change on above node. How can I do that?

As an example:

onWrite event is perfectly fit on my use case. But how can I implement it inside client .ts file?

This is a node.js implementation of cloud function. How can I do such implementation on client .ts file?

// Listen for any change on document `marie` in collection `users`
exports.myFunctionName = functions.firestore
    .document('users/marie').onWrite((change, context) => {
      // ... Your code here
    });

Note: I use angularfire2 with my ionic 3 app.

Upvotes: 1

Views: 2128

Answers (2)

Tom
Tom

Reputation: 16276

My Solution

Step 1. In firestore, make a notification doc for whatever information you want to notify the client side. Something like this:

db.collection('notifications').doc('transactionHappened').set({/*your transaction details*/});

Step 2. Register to your notification doc and listen to it, e.g. when you are writing to a transaction doc, also write your latest transaction info into the transactionHappened doc:

const yourHandler = data=>{/*handle your notification details here*/};
db.collection('notifications').doc('transactionHappened').onSnapshot(yourHandler);

Step 3. Now onSnapshot is registered, but if your app was disconnected it doesn't catch any notifications during that period. Let's handle it.

const reconnectHandler =()=>{/*you were offline, so read whatever you need from firestore to cath up with the latest data*/};
const disconnectHandler =()=>{/*display something on your screen to indicate it is offline*/};
const monitorNetwork=()=> {
    let status = true;
    const timeout = ()=> setTimeout(()=>{
        if(status !== navigator.onLine) {
            status = navigator.onLine;
            console.log(`Network is ${status? 'up 🠕':'down 🠗'}`);
            if (status) { //if network is flipped to online
                reconnectHandler();
            } else {//just went offline
                disconnectHandler();
            }
        }
        timeout();
    }, 1000);
    timeout();
}

The little function above will create a heartbeat for you every 1 second to monitor your network status.

Upvotes: 0

Jason Berryman
Jason Berryman

Reputation: 4908

A partial solution

The following code will allow you to listen to a single collection. There is currently no way to listen to sub-collections across multiple project documents. The best solution to this would be to de-normalise your data model, so that you have a collection called projectTransactions and filter client queries with a projectId field and enforce access with security rules.

The code uses the docChanges method, which allows you to view only changes made to the collection without having to go through each document. This approach is discussed in the "View changes between snapshots" section of the documentation when it says

It is often useful to see the actual changes to query results between query snapshots, instead of simply using the entire query snapshot.

const firebase = require('firebase');
require("firebase/firestore");

// Initialize Firebase
let config = {
  apiKey: "*** Your API key ***",
  authDomain: "*** Your Auth domain ***",
  databaseURL: "*** Your database URL ***",
  projectId: "*** Your project ID ***",
  messagingSenderId: "*** Your Messaging Sender ID ***"
};
firebase.initializeApp(config);

let email = '[email protected]';
let password = 'myExamplePassword';

firebase.auth().signInWithEmailAndPassword(email, password)
  .catch(error => {
    console.log(error);
  });

firebase.auth().onAuthStateChanged((user) => {
  if (user) {
    console.log('I am logged in');

    // Initialise Firestore
    const firestore = firebase.firestore();
    const settings = {timestampsInSnapshots: true};
    firestore.settings(settings);

    return firestore
    .collection('projectTransactions')
    .onSnapshot((querySnapshot) => {
      console.log('Listening to the projectTransactions collection');
      querySnapshot.docChanges().forEach((change) => {

        // A new transaction has been added
        if (change.type === 'added') {
          console.log(`A new transaction has been added with ID: ${change.doc.id}`);
        }

        // A transaction has been deleted
        if (change.type === 'removed') {
            console.log(`A transaction has been removed with ID: ${change.doc.id}`);
        }

      });
    });

  } else {
    // User is signed out.
    // ...
  }
});

Upvotes: 1

Related Questions