สร้างการแสดงข้อมูลใน Cloud Firestore

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

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

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

โซลูชัน: Cloud Functions ที่มี Realtime Database

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

ใช้ฐานข้อมูลเรียลไทม์เพื่อรายงานสถานะการเชื่อมต่อ จากนั้นใช้ Cloud Functions เพื่อ ทำสำเนาข้อมูลนั้นไปยัง Cloud Firestore

การใช้สถานะการใช้งานใน Realtime Database

ก่อนอื่น ให้พิจารณาว่าระบบสถานะแบบดั้งเดิมทำงานอย่างไรใน Realtime Database

เว็บ

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

ตัวอย่างนี้เป็นระบบสถานะของ Realtime Database ที่สมบูรณ์ โดยจะจัดการ การตัดการเชื่อมต่อหลายครั้ง การขัดข้อง และอื่นๆ

กำลังเชื่อมต่อกับ Cloud Firestore

หากต้องการใช้โซลูชันที่คล้ายกันใน Cloud Firestore ให้ใช้โค้ดฐานข้อมูลเรียลไทม์เดียวกัน จากนั้นใช้ Cloud Functions เพื่อให้ฐานข้อมูลเรียลไทม์และ Cloud Firestore ซิงค์กัน

หากยังไม่ได้เพิ่ม ให้เพิ่ม Realtime Database ลงในโปรเจ็กต์ และรวมโซลูชันสถานะที่ระบุไว้ข้างต้น

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

  1. ในเครื่องไปยังแคช Cloud Firestore ของอุปกรณ์ที่ออฟไลน์เพื่อให้แอป ทราบว่าออฟไลน์อยู่
  2. ทั่วโลก การใช้ Cloud Function เพื่อให้อุปกรณ์อื่นๆ ทั้งหมดที่เข้าถึง Cloud Firestore ทราบว่าอุปกรณ์นี้ออฟไลน์อยู่

ฟังก์ชันที่แนะนำในบทแนะนำนี้ไม่สามารถเรียกใช้ในแอปไคลเอ็นต์ ต้องนำไปใช้งานใน Cloud Functions for Firebase และต้องใช้ตรรกะฝั่งเซิร์ฟเวอร์ จาก Firebase Admin SDK ดูคำแนะนำแบบละเอียดได้ในเอกสารประกอบของ Cloud Functions

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

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

เมื่อติดตั้งใช้งานฟังก์ชันนี้แล้ว คุณจะมีระบบการตรวจหาบุคคลที่สมบูรณ์ซึ่งทำงานร่วมกับ 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 ของคุณนั้นปรับขนาดได้และมีประสิทธิภาพ แต่ก็มีข้อจำกัดบางประการ ดังนี้

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