Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

בנה נוכחות ב-Cloud Firestore

קל לארגן דפים בעזרת אוספים אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.

בהתאם לסוג האפליקציה שאתה בונה, ייתכן שיהיה שימושי לזהות אילו מהמשתמשים או המכשירים שלך מחוברים באופן פעיל - הידוע גם כזיהוי "נוכחות".

לדוגמה, אם אתה בונה אפליקציה כמו רשת חברתית או פורס צי של מכשירי IoT, תוכל להשתמש במידע זה כדי להציג רשימה של חברים מקוונים וחופשיים לצ'אט, או למיין את מכשירי ה-IoT שלך לפי "נראה לאחרונה" ."

Cloud Firestore לא תומך בנוכחות באופן מקורי, אבל אתה יכול למנף מוצרים אחרים של Firebase כדי לבנות מערכת נוכחות.

פתרון: פונקציות ענן עם מסד נתונים בזמן אמת

כדי לחבר את Cloud Firestore לתכונת הנוכחות המקורית של Firebase Realtime Database, השתמש ב-Cloud Functions.

השתמש במסד נתונים בזמן אמת כדי לדווח על מצב חיבור, ולאחר מכן השתמש בפונקציות הענן כדי לשקף את הנתונים האלה לתוך Cloud Firestore.

שימוש בנוכחות במסד נתונים בזמן אמת

ראשית, שקול כיצד פועלת מערכת נוכחות מסורתית במסד נתונים בזמן אמת.

אינטרנט

// Fetch the current user's ID from Firebase Authentication.
var uid = firebase.auth().currentUser.uid;

// Create a reference to this user's specific status node.
// This is where we will store data about being online/offline.
var userStatusDatabaseRef = firebase.database().ref('/status/' + uid);

// We'll create two constants which we will write to 
// the Realtime database when this device is offline
// or online.
var isOfflineForDatabase = {
    state: 'offline',
    last_changed: firebase.database.ServerValue.TIMESTAMP,
};

var isOnlineForDatabase = {
    state: 'online',
    last_changed: firebase.database.ServerValue.TIMESTAMP,
};

// Create a reference to the special '.info/connected' path in 
// Realtime Database. This path returns `true` when connected
// and `false` when disconnected.
firebase.database().ref('.info/connected').on('value', function(snapshot) {
    // If we're not currently connected, don't do anything.
    if (snapshot.val() == false) {
        return;
    };

    // If we are currently connected, then use the 'onDisconnect()' 
    // method to add a set which will only trigger once this 
    // client has disconnected by closing the app, 
    // losing internet, or any other means.
    userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function() {
        // The promise returned from .onDisconnect().set() will
        // resolve as soon as the server acknowledges the onDisconnect() 
        // request, NOT once we've actually disconnected:
        // https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect

        // We can now safely set ourselves as 'online' knowing that the
        // server will mark us as offline once we lose connection.
        userStatusDatabaseRef.set(isOnlineForDatabase);
    });
});

דוגמה זו היא מערכת נוכחות של מסד נתונים בזמן אמת. הוא מטפל במספר ניתוקים, קריסות וכן הלאה.

מתחבר ל-Cloud Firestore

כדי ליישם פתרון דומה ב-Cloud Firestore, השתמש באותו קוד של מסד נתונים בזמן אמת, ולאחר מכן השתמש בפונקציות הענן כדי לשמור על סנכרון של מסד נתונים של Realtime ו-Cloud Firestore.

אם עדיין לא עשית זאת, הוסף את מסד נתונים בזמן אמת לפרויקט שלך וכלול את פתרון הנוכחות לעיל.

לאחר מכן תסנכרן את מצב הנוכחות עם Cloud Firestore באמצעות השיטות הבאות:

  1. באופן מקומי, למטמון Cloud Firestore של המכשיר הלא מקוון, כך שהאפליקציה תדע שהוא במצב לא מקוון.
  2. באופן גלובלי, שימוש בפונקציית ענן כך שכל המכשירים האחרים שניגשים ל-Cloud Firestore יודעים שהמכשיר הספציפי הזה לא מקוון.

עדכון המטמון המקומי של Cloud Firestore

בואו נסתכל על השינויים הנדרשים כדי למלא את הבעיה הראשונה - עדכון המטמון המקומי של Cloud Firestore.

אינטרנט

// ...
var userStatusFirestoreRef = firebase.firestore().doc('/status/' + uid);

// Firestore uses a different server timestamp value, so we'll 
// create two more constants for Firestore state.
var isOfflineForFirestore = {
    state: 'offline',
    last_changed: firebase.firestore.FieldValue.serverTimestamp(),
};

var isOnlineForFirestore = {
    state: 'online',
    last_changed: firebase.firestore.FieldValue.serverTimestamp(),
};

firebase.database().ref('.info/connected').on('value', function(snapshot) {
    if (snapshot.val() == false) {
        // Instead of simply returning, we'll also set Firestore's state
        // to 'offline'. This ensures that our Firestore cache is aware
        // of the switch to 'offline.'
        userStatusFirestoreRef.set(isOfflineForFirestore);
        return;
    };

    userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function() {
        userStatusDatabaseRef.set(isOnlineForDatabase);

        // We'll also add Firestore set here for when we come online.
        userStatusFirestoreRef.set(isOnlineForFirestore);
    });
});

עם השינויים הללו, הבטחנו כעת שמצב Cloud Firestore המקומי ישקף תמיד את המצב המקוון/לא מקוון של המכשיר. משמעות הדבר היא שאתה יכול להאזין למסמך /status/{uid} ולהשתמש בנתונים כדי לשנות את ממשק המשתמש שלך כדי לשקף את סטטוס החיבור.

אינטרנט

userStatusFirestoreRef.onSnapshot(function(doc) {
    var isOnline = doc.data().state == 'online';
    // ... use isOnline
});

עדכון Cloud Firestore ברחבי העולם

למרות שהאפליקציה שלנו מדווחת לעצמה נכונה על נוכחות מקוונת, סטטוס זה עדיין לא יהיה מדויק באפליקציות אחרות של Cloud Firestore מכיוון שכתיבת הסטטוס "לא מקוון" שלנו היא מקומית בלבד ולא יסונכרן כאשר החיבור ישוחזר. כדי להתמודד עם זה, נשתמש בפונקציית ענן אשר צופה בנתיב status/{uid} במסד נתונים בזמן אמת. כאשר הערך של Realtime Database משתנה, הערך יסונכרן עם Cloud Firestore כך שכל הסטטוסים של המשתמשים יהיו נכונים.

Node.js

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

// Since this code will be running in the Cloud Functions environment
// we call initialize Firestore without any arguments because it
// detects authentication from the environment.
const firestore = admin.firestore();

// Create a new function which is triggered on changes to /status/{uid}
// Note: This is a Realtime Database trigger, *not* Firestore.
exports.onUserStatusChanged = functions.database.ref('/status/{uid}').onUpdate(
    async (change, context) => {
      // Get the data written to Realtime Database
      const eventStatus = change.after.val();

      // Then use other event data to create a reference to the
      // corresponding Firestore document.
      const userStatusFirestoreRef = firestore.doc(`status/${context.params.uid}`);

      // It is likely that the Realtime Database change that triggered
      // this event has already been overwritten by a fast change in
      // online / offline status, so we'll re-read the current data
      // and compare the timestamps.
      const statusSnapshot = await change.after.ref.once('value');
      const status = statusSnapshot.val();
      functions.logger.log(status, eventStatus);
      // If the current timestamp for this data is newer than
      // the data that triggered this event, we exit this function.
      if (status.last_changed > eventStatus.last_changed) {
        return null;
      }

      // Otherwise, we convert the last_changed field to a Date
      eventStatus.last_changed = new Date(eventStatus.last_changed);

      // ... and write it to Firestore.
      return userStatusFirestoreRef.set(eventStatus);
    });

לאחר שתפרוס פונקציה זו, תהיה לך מערכת נוכחות מלאה הפועלת עם Cloud Firestore. להלן דוגמה לניטור עבור כל המשתמשים שמגיעים לאינטרנט או יוצאים לא מקוונים באמצעות שאילתת where() .

אינטרנט

firebase.firestore().collection('status')
    .where('state', '==', 'online')
    .onSnapshot(function(snapshot) {
        snapshot.docChanges().forEach(function(change) {
            if (change.type === 'added') {
                var msg = 'User ' + change.doc.id + ' is online.';
                console.log(msg);
                // ...
            }
            if (change.type === 'removed') {
                var msg = 'User ' + change.doc.id + ' is offline.';
                console.log(msg);
                // ...
            }
        });
    });

מגבלות

השימוש במסד נתונים בזמן אמת כדי להוסיף נוכחות לאפליקציית Cloud Firestore שלך ​​ניתן להרחבה ויעיל, אך יש לו כמה מגבלות:

  • Debouncing - בעת האזנה לשינויים בזמן אמת ב-Cloud Firestore, סביר להניח שהפתרון הזה יפעיל שינויים מרובים. אם השינויים האלה מפעילים יותר אירועים ממה שאתה רוצה, בטל ידנית את אירועי Cloud Firestore.
  • קישוריות - יישום זה מודד קישוריות למסד נתונים בזמן אמת, לא ל-Cloud Firestore. אם מצב החיבור לכל מסד נתונים אינו זהה, פתרון זה עשוי לדווח על מצב נוכחות שגוי.
  • אנדרואיד - באנדרואיד, מסד הנתונים בזמן אמת מתנתק מהקצה האחורי לאחר 60 שניות של חוסר פעילות. חוסר פעילות פירושה ללא מאזינים פתוחים או פעולות ממתינות. כדי לשמור על החיבור פתוח, אנו ממליצים להוסיף מאזין אירועי ערך לנתיב מלבד .info/connected . לדוגמה, אתה יכול לעשות FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() בתחילת כל הפעלה. למידע נוסף, ראה זיהוי מצב חיבור .