Manspof
Manspof

Reputation: 357

minimize time operation in firebase/firestore

I build react native app with firebase & firestore. what I'm looking to do is, when user open app, to insert/update his status to 'online' (kind of presence system), when user close app, his status 'offline'. I did it with firebase.database.onDisconnect(), it works fine. this is the function

    async signupAnonymous() {
    const user = await firebase.auth().signInAnonymouslyAndRetrieveData();
    this.uid = firebase.auth().currentUser.uid

    this.userStatusDatabaseRef = firebase.database().ref(`UserStatus/${this.uid}`);
    this.userStatusFirestoreRef = firebase.firestore().doc(`UserStatus/${this.uid}`);

    firebase.database().ref('.info/connected').on('value', async connected => {
        if (connected.val() === false) {
            // this.userStatusFirestoreRef.set({ state: 'offline', last_changed: firebase.firestore.FieldValue.serverTimestamp()},{merge:true});
            return;
        }

        await firebase.database().ref(`UserStatus/${this.uid}`).onDisconnect().set({ state: 'offline', last_changed: firebase.firestore.FieldValue.serverTimestamp() },{merge:true});
        this.userStatusDatabaseRef.set({ state: 'online', last_changed: firebase.firestore.FieldValue.serverTimestamp() },{merge:true});
        // this.userStatusFirestoreRef.set({ state: 'online',last_changed: firebase.firestore.FieldValue.serverTimestamp() },{merge:true});
    });
}

after that, I did trigger to insert data into firestore(because I want to work with firestore), this is the function(works fine, BUT it takes 3-4 sec)

    module.exports.onUserStatusChanged = functions.database
  .ref('/UserStatus/{uid}').onUpdate((change,context) => {
    const eventStatus = change.after.val();


    const userStatusFirestoreRef = firestore.doc(`UserStatus/${context.params.uid}`);


return change.after.ref.once("value").then((statusSnapshot) => {
  return statusSnapshot.val();
}).then((status) => {
  console.log(status, eventStatus);
  if (status.last_changed > eventStatus.last_changed) return status;

  eventStatus.last_changed = new Date(eventStatus.last_changed);

  //return userStatusFirestoreRef.set(eventStatus);
  return userStatusFirestoreRef.set(eventStatus,{merge:true});
    });
  });

then after that, I want to calculate the online users in app, so I did trigger when write new data to node of firestore so it calculate the size of online users by query.(it works fine but takes 4-7 sec)

module.exports.countOnlineUsers = functions.firestore.document('/UserStatus/{uid}').onWrite((change,context) => {

console.log('userStatus')
const userOnlineCounterRef = firestore.doc('Counters/onlineUsersCounter');

const docRef = firestore.collection('UserStatus').where('state','==','online').get().then(e=>{
    let count = e.size;
    console.log('count',count)
    return userOnlineCounterRef.update({count})
})
return Promise.resolve({success:'added'})



  })

then into my react native app I get the count of online users

 this.unsubscribe = firebase.firestore().doc(`Counters/onlineUsersCounter`).onSnapshot(doc=>{
        console.log('count',doc.data().count)
    })

All the operations takes about 12 sec. it's too much for me, it's online app

my firebase structure counters UserStatus what I'm doing wrong? maybe there is unnecessary function or something?

My final goals:

  1. minimize time operation.
  2. get online users count (with listener-each change, it will update in app)
  3. update user status.

if there are other way to do that, I would love to know.

Upvotes: 0

Views: 757

Answers (1)

Matt O'Tousa
Matt O'Tousa

Reputation: 515

Cloud Functions go into a 'cold start' mode, where they take some time to boot up. This is the only reason I can think of that it would take that long. Stack Overflow: Firebase Cloud Functions Is Very Slow

But your cloud function only needs to write to Firestore on log out to catch the case where your user closes the app. You can write to it directly on log in from your client with auth().onAuthStateChange().

You could also just always read who is logged in or out directly from the realtime database and use Firestore for the rest of your data.

You can rearrange your data so that instead of a 'UserStatus' collection you have an 'OnlineUsers' collection containing only online users, kept in sync by deleting the documents on log out. Then it won't take a query operation to get them. The query's impact on your performance is likely minimal, but this would perform better with a large number of users.

The documentation also has a guide that may be useful: Firebase Docs: Build Presence in Cloud Firestore

Upvotes: 2

Related Questions