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

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

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

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

โซลูชัน: Cloud Functions กับ Realtime Database

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

ใช้ Realtime Database เพื่อรายงานสถานะการเชื่อมต่อ แล้วใช้ 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 ให้ใช้โค้ด Realtime Database เดียวกัน แล้วใช้ Cloud Functions เพื่อให้ Realtime Database และ 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 Function ที่ตรวจสอบเส้นทาง status/{uid} ใน Realtime Database เพื่อแก้ไขปัญหานี้ เมื่อค่า 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 ที่เปิดอยู่หรือการดำเนินการที่รอดำเนินการ เราขอแนะนำให้คุณเพิ่ม Listener เหตุการณ์ค่าลงในเส้นทางอื่นนอกเหนือจาก .info/connected เพื่อให้การเชื่อมต่อเปิดอยู่ ตัวอย่างเช่น คุณสามารถทำ FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() เมื่อเริ่มต้นแต่ละเซสชัน ดูข้อมูลเพิ่มเติมได้ที่ การตรวจหาสถานะการเชื่อมต่อ