Bauen Sie Präsenz im Cloud Firestore auf

Abhängig von der Art der App, die Sie erstellen, kann es hilfreich sein, zu erkennen, welche Ihrer Benutzer oder Geräte aktiv online sind – auch bekannt als „Anwesenheitserkennung“.

Wenn Sie beispielsweise eine App wie ein soziales Netzwerk erstellen oder eine Flotte von IoT-Geräten bereitstellen, können Sie diese Informationen verwenden, um eine Liste von Freunden anzuzeigen, die online sind und kostenlos chatten können, oder Ihre IoT-Geräte nach „zuletzt gesehen“ zu sortieren ."

Cloud Firestore unterstützt Präsenz nicht nativ, Sie können jedoch andere Firebase-Produkte nutzen, um ein Präsenzsystem aufzubauen.

Lösung: Cloud-Funktionen mit Echtzeitdatenbank

Um Cloud Firestore mit der nativen Präsenzfunktion der Firebase Realtime Database zu verbinden, verwenden Sie Cloud Functions.

Verwenden Sie Realtime Database, um den Verbindungsstatus zu melden, und verwenden Sie dann Cloud Functions, um diese Daten in Cloud Firestore zu spiegeln.

Präsenz in der Echtzeitdatenbank nutzen

Überlegen Sie zunächst, wie ein herkömmliches Präsenzsystem in der Echtzeitdatenbank funktioniert.

Netz

// 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);
    });
});

Dieses Beispiel ist ein vollständiges Echtzeitdatenbank-Präsenzsystem. Es bewältigt mehrere Verbindungsabbrüche, Abstürze usw.

Verbindung zum Cloud Firestore herstellen

Um eine ähnliche Lösung in Cloud Firestore zu implementieren, verwenden Sie denselben Realtime Database-Code und verwenden Sie dann Cloud Functions, um Realtime Database und Cloud Firestore synchron zu halten.

Wenn Sie dies noch nicht getan haben, fügen Sie Realtime Database zu Ihrem Projekt hinzu und beziehen Sie die oben genannte Präsenzlösung ein.

Als Nächstes synchronisieren Sie den Anwesenheitsstatus mithilfe der folgenden Methoden mit Cloud Firestore:

  1. Lokal, im Cloud Firestore-Cache des Offline-Geräts, damit die App weiß, dass es offline ist.
  2. Global wird eine Cloud-Funktion verwendet, sodass alle anderen Geräte, die auf Cloud Firestore zugreifen, wissen, dass dieses bestimmte Gerät offline ist.

Aktualisieren des lokalen Caches von Cloud Firestore

Werfen wir einen Blick auf die Änderungen, die erforderlich sind, um das erste Problem zu lösen – die Aktualisierung des lokalen Caches von Cloud Firestore.

Netz

// ...
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);
    });
});

Mit diesen Änderungen haben wir nun sichergestellt, dass der lokale Cloud Firestore-Status immer den Online-/Offline-Status des Geräts widerspiegelt. Das bedeutet, dass Sie sich das Dokument /status/{uid} anhören und die Daten verwenden können, um Ihre Benutzeroberfläche so zu ändern, dass sie den Verbindungsstatus widerspiegelt.

Netz

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

Cloud Firestore global aktualisieren

Obwohl unsere Anwendung die Online-Präsenz korrekt an sich selbst meldet, ist dieser Status in anderen Cloud Firestore-Apps noch nicht korrekt, da unser „Offline“-Statusschreiben nur lokal erfolgt und nicht synchronisiert wird, wenn eine Verbindung wiederhergestellt wird. Um dem entgegenzuwirken, verwenden wir eine Cloud-Funktion, die den status/{uid} -Pfad in der Echtzeitdatenbank überwacht. Wenn sich der Wert der Echtzeitdatenbank ändert, wird der Wert mit Cloud Firestore synchronisiert, sodass der Status aller Benutzer korrekt ist.

Node.js

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);
                // ...
            }
        });
    });

Sobald Sie diese Funktion bereitstellen, verfügen Sie über ein vollständiges Präsenzsystem, das mit Cloud Firestore ausgeführt wird. Nachfolgend finden Sie ein Beispiel für die Überwachung aller Benutzer, die mithilfe einer where() Abfrage online oder offline gehen.

Netz

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);
                // ...
            }
        });
    });

Einschränkungen

Die Verwendung von Realtime Database zum Hinzufügen von Präsenz zu Ihrer Cloud Firestore-App ist skalierbar und effektiv, weist jedoch einige Einschränkungen auf:

  • Entprellen – Beim Abhören von Echtzeitänderungen in Cloud Firestore löst diese Lösung wahrscheinlich mehrere Änderungen aus. Wenn diese Änderungen mehr Ereignisse auslösen, als Sie möchten, entprellen Sie die Cloud Firestore-Ereignisse manuell.
  • Konnektivität – diese Implementierung misst die Konnektivität zur Echtzeitdatenbank, nicht zum Cloud Firestore. Wenn der Verbindungsstatus zu jeder Datenbank nicht derselbe ist, meldet diese Lösung möglicherweise einen falschen Anwesenheitsstatus.
  • Android – unter Android trennt die Echtzeitdatenbank nach 60 Sekunden Inaktivität die Verbindung zum Backend. Inaktivität bedeutet, dass keine offenen Listener oder ausstehenden Vorgänge vorhanden sind. Um die Verbindung offen zu halten, empfehlen wir Ihnen, einem Pfad außer .info/connected einen Wertereignis-Listener hinzuzufügen. Sie könnten beispielsweise FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() zu Beginn jeder Sitzung ausführen. Weitere Informationen finden Sie unter Verbindungsstatus erkennen .