Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

สร้างสถานะใน Cloud Firestore

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

ขึ้นอยู่กับประเภทของแอปที่คุณกำลังสร้าง คุณอาจพบว่ามีประโยชน์ในการตรวจสอบว่าผู้ใช้หรืออุปกรณ์ใดของคุณกำลังออนไลน์อยู่ หรือที่เรียกว่าการตรวจจับ "การแสดงตน"

ตัวอย่างเช่น หากคุณกำลังสร้างแอป เช่น โซเชียลเน็ตเวิร์ก หรือปรับใช้กลุ่มอุปกรณ์ IoT คุณสามารถใช้ข้อมูลนี้เพื่อแสดงรายการเพื่อนที่ออนไลน์และแชทได้ฟรี หรือจัดเรียงอุปกรณ์ IoT ของคุณตาม "ดูล่าสุด" ."

Cloud Firestore ไม่รองรับการแสดงตนโดยกำเนิด แต่คุณสามารถใช้ประโยชน์จากผลิตภัณฑ์ Firebase อื่นๆ เพื่อสร้างระบบการแสดงตนได้

วิธีแก้ไข: ฟังก์ชันคลาวด์พร้อมฐานข้อมูลแบบเรียลไทม์

หากต้องการเชื่อมต่อ Cloud Firestore กับฟีเจอร์การแสดงตนดั้งเดิมของฐานข้อมูล Firebase Realtime ให้ใช้ Cloud Functions

ใช้ฐานข้อมูลเรียลไทม์เพื่อรายงานสถานะการเชื่อมต่อ จากนั้นใช้ 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 Database เดียวกัน จากนั้นใช้ Cloud Functions เพื่อให้ Realtime Database และ Cloud Firestore ซิงค์กัน

หากคุณยังไม่ได้ดำเนินการ ให้เพิ่ม ฐานข้อมูลเรียลไทม์ ในโครงการของคุณและรวมโซลูชันการแสดงตนด้านบน

ถัดไป คุณจะซิงโครไนซ์สถานะการแสดงตนกับ Cloud Firestore โดยใช้วิธีการต่อไปนี้:

  1. ภายในเครื่องไปยังแคช Cloud Firestore ของอุปกรณ์ออฟไลน์เพื่อให้แอปรู้ว่าออฟไลน์อยู่
  2. ทั่วโลกโดยใช้ Cloud Function เพื่อให้อุปกรณ์อื่นๆ ทั้งหมดที่เข้าถึง 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} และใช้ข้อมูลเพื่อเปลี่ยน UI ของคุณเพื่อสะท้อนสถานะการเชื่อมต่อ

เว็บ

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

กำลังอัปเดต Cloud Firestore ทั่วโลก

แม้ว่าแอปพลิเคชันของเราจะรายงานสถานะออนไลน์ของตัวเองอย่างถูกต้อง แต่สถานะนี้จะไม่ถูกต้องในแอป Cloud Firestore อื่นๆ เนื่องจากการเขียนสถานะ "ออฟไลน์" ของเราอยู่ในเครื่องเท่านั้น และจะไม่ซิงค์เมื่อมีการกู้คืนการเชื่อมต่อ เพื่อตอบโต้ เราจะใช้ Cloud Function ซึ่งคอยดู status/{uid} เส้นทางใน Realtime Database เมื่อค่า 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);
                // ...
            }
        });
    });

ข้อจำกัด

การใช้ Realtime Database เพื่อเพิ่มสถานะให้กับแอพ Cloud Firestore ของคุณนั้นสามารถปรับขนาดได้และมีประสิทธิภาพ แต่มีข้อจำกัดบางประการ:

  • Debouncing - เมื่อรับฟังการเปลี่ยนแปลงแบบเรียลไทม์ใน Cloud Firestore โซลูชันนี้มีแนวโน้มที่จะทริกเกอร์การเปลี่ยนแปลงหลายรายการ หากการเปลี่ยนแปลงเหล่านี้ทริกเกอร์เหตุการณ์มากกว่าที่คุณต้องการ ให้ดีบักเหตุการณ์ Cloud Firestore ด้วยตนเอง
  • การ เชื่อม ต่อ - การใช้งานนี้จะวัดการเชื่อมต่อกับฐานข้อมูลเรียลไทม์ ไม่ใช่ Cloud Firestore ถ้าสถานะการเชื่อมต่อกับแต่ละฐานข้อมูลไม่เหมือนกัน โซลูชันนี้อาจรายงานสถานะการแสดงตนที่ไม่ถูกต้อง
  • Android - บน Android ฐานข้อมูลเรียลไทม์จะยกเลิกการเชื่อมต่อจากแบ็กเอนด์หลังจากไม่มีการใช้งาน 60 วินาที การไม่ใช้งานหมายความว่าไม่มีผู้ฟังที่เปิดอยู่หรือการดำเนินการที่รอดำเนินการ เพื่อให้การเชื่อมต่อเปิดอยู่เสมอ เราขอแนะนำให้คุณเพิ่มตัวฟังเหตุการณ์มูลค่าให้กับเส้นทางนอกเหนือจาก .info/connected ตัวอย่างเช่น คุณสามารถทำ FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() ที่จุดเริ่มต้นของแต่ละเซสชัน สำหรับข้อมูลเพิ่มเติม โปรดดูที่ การตรวจจับสถานะการเชื่อม ต่อ