Ikuti semua informasi yang diumumkan di Firebase Summit, dan pelajari bagaimana Firebase dapat membantu Anda mempercepat pengembangan aplikasi dan menjalankan aplikasi dengan percaya diri. Pelajari Lebih Lanjut

Bangun kehadiran di Cloud Firestore

Bergantung pada jenis aplikasi yang Anda buat, Anda mungkin merasa berguna untuk mendeteksi pengguna atau perangkat mana yang aktif online — atau dikenal sebagai mendeteksi "keberadaan".

Misalnya, jika Anda membuat aplikasi seperti jejaring sosial atau menggunakan armada perangkat IoT, Anda dapat menggunakan informasi ini untuk menampilkan daftar teman yang online dan bebas mengobrol, atau mengurutkan perangkat IoT Anda berdasarkan "terakhir terlihat ."

Cloud Firestore tidak secara native mendukung kehadiran, tetapi Anda dapat memanfaatkan produk Firebase lainnya untuk membangun sistem kehadiran.

Solusi: Cloud Functions dengan Realtime Database

Untuk menghubungkan Cloud Firestore ke fitur kehadiran asli Firebase Realtime Database, gunakan Cloud Functions.

Gunakan Realtime Database untuk melaporkan status koneksi, lalu gunakan Cloud Functions untuk mencerminkan data tersebut ke Cloud Firestore.

Menggunakan kehadiran di Realtime Database

Pertama, pertimbangkan cara kerja sistem kehadiran tradisional di Realtime Database.

Web

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

Contoh ini adalah sistem presensi Realtime Database yang lengkap. Ini menangani beberapa pemutusan, crash dan sebagainya.

Menghubungkan ke Cloud Firestore

Untuk mengimplementasikan solusi serupa di Cloud Firestore, gunakan kode Realtime Database yang sama, lalu gunakan Cloud Functions untuk menjaga sinkronisasi antara Realtime Database dan Cloud Firestore.

Jika Anda belum melakukannya, tambahkan Realtime Database ke proyek Anda dan sertakan solusi kehadiran di atas.

Selanjutnya Anda akan menyinkronkan status kehadiran ke Cloud Firestore melalui metode berikut:

  1. Secara lokal, ke cache Cloud Firestore perangkat offline sehingga aplikasi mengetahui bahwa itu offline.
  2. Secara global, menggunakan Cloud Function agar semua perangkat lain yang mengakses Cloud Firestore mengetahui bahwa perangkat khusus ini sedang offline.

Memperbarui cache lokal Cloud Firestore

Mari kita lihat perubahan yang diperlukan untuk memenuhi masalah pertama - memperbarui cache lokal Cloud Firestore.

Web

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

Dengan perubahan ini, kami sekarang memastikan bahwa status Cloud Firestore lokal akan selalu mencerminkan status perangkat online/offline. Ini berarti Anda dapat mendengarkan dokumen /status/{uid} dan menggunakan data tersebut untuk mengubah UI agar mencerminkan status koneksi.

Web

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

Memperbarui Cloud Firestore secara global

Meskipun aplikasi kami dengan benar melaporkan kehadiran online ke dirinya sendiri, status ini belum akan akurat di aplikasi Cloud Firestore lainnya karena status "offline" kami menulis hanya lokal dan tidak akan disinkronkan saat koneksi dipulihkan. Untuk mengatasi ini, kami akan menggunakan Cloud Function yang mengawasi jalur status/{uid} di Realtime Database. Saat nilai Realtime Database berubah, nilai tersebut akan disinkronkan ke Cloud Firestore sehingga semua status pengguna sudah benar.

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

Setelah Anda menerapkan fungsi ini, Anda akan memiliki sistem kehadiran lengkap yang berjalan dengan Cloud Firestore. Di bawah ini adalah contoh pemantauan untuk setiap pengguna yang online atau offline menggunakan kueri where() .

Web

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

Keterbatasan

Menggunakan Realtime Database untuk menambahkan kehadiran ke aplikasi Cloud Firestore Anda dapat diskalakan dan efektif tetapi memiliki beberapa keterbatasan:

  • Debouncing - saat mendengarkan perubahan waktu nyata di Cloud Firestore, solusi ini kemungkinan akan memicu beberapa perubahan. Jika perubahan ini memicu lebih banyak peristiwa daripada yang Anda inginkan, debounce peristiwa Cloud Firestore secara manual.
  • Konektivitas - implementasi ini mengukur konektivitas ke Realtime Database, bukan ke Cloud Firestore. Jika status koneksi ke setiap database tidak sama, solusi ini mungkin melaporkan status kehadiran yang salah.
  • Android - di Android, Realtime Database terputus dari backend setelah 60 detik tidak aktif. Tidak aktif berarti tidak ada pendengar yang terbuka atau operasi yang tertunda. Untuk menjaga koneksi tetap terbuka, kami menyarankan Anda menambahkan event listener nilai ke jalur selain .info/connected . Misalnya Anda bisa melakukan FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() di awal setiap sesi. Untuk informasi lebih lanjut, lihat Mendeteksi Status Koneksi .