Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Xây dựng sự hiện diện trong Cloud Firestore

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Tùy thuộc vào loại ứng dụng bạn đang xây dựng, bạn có thể thấy hữu ích khi phát hiện người dùng hoặc thiết bị nào của mình đang trực tuyến - hay còn được gọi là phát hiện "sự hiện diện".

Ví dụ: nếu bạn đang xây dựng một ứng dụng như mạng xã hội hoặc triển khai một nhóm thiết bị IoT, bạn có thể sử dụng thông tin này để hiển thị danh sách bạn bè đang trực tuyến và trò chuyện miễn phí hoặc sắp xếp các thiết bị IoT của bạn theo "lần xem cuối cùng . "

Cloud Firestore nguyên bản không hỗ trợ sự hiện diện, nhưng bạn có thể tận dụng các sản phẩm Firebase khác để xây dựng hệ thống hiện diện.

Giải pháp: Chức năng đám mây với cơ sở dữ liệu thời gian thực

Để kết nối Cloud Firestore với tính năng hiện diện gốc của Cơ sở dữ liệu thời gian thực của Firebase, hãy sử dụng Chức năng đám mây.

Sử dụng Cơ sở dữ liệu thời gian thực để báo cáo trạng thái kết nối, sau đó sử dụng Chức năng đám mây để phản chiếu dữ liệu đó vào Cloud Firestore.

Sử dụng sự hiện diện trong Cơ sở dữ liệu thời gian thực

Trước tiên, hãy xem xét cách thức hoạt động của hệ thống hiện diện truyền thống trong Cơ sở dữ liệu thời gian thực.

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

Ví dụ này là một hệ thống hiện diện Cơ sở dữ liệu thời gian thực hoàn chỉnh. Nó xử lý nhiều lần ngắt kết nối, sự cố, v.v.

Kết nối với Cloud Firestore

Để triển khai giải pháp tương tự trong Cloud Firestore, hãy sử dụng cùng một mã Cơ sở dữ liệu thời gian thực, sau đó sử dụng Chức năng đám mây để đồng bộ hóa Cơ sở dữ liệu thời gian thực và Cloud Firestore.

Nếu bạn chưa có, hãy thêm Cơ sở dữ liệu thời gian thực vào dự án của bạn và bao gồm giải pháp hiện diện ở trên.

Tiếp theo, bạn sẽ đồng bộ hóa trạng thái hiện diện với Cloud Firestore thông qua các phương pháp sau:

  1. Tại địa phương, vào bộ nhớ cache Cloud Firestore của thiết bị ngoại tuyến để ứng dụng biết rằng nó đang ngoại tuyến.
  2. Trên toàn cầu, sử dụng Chức năng đám mây để tất cả các thiết bị khác truy cập Cloud Firestore biết thiết bị cụ thể này đang ngoại tuyến.

Cập nhật bộ nhớ cache cục bộ của Cloud Firestore

Hãy cùng xem những thay đổi cần thiết để hoàn thành vấn đề đầu tiên - cập nhật bộ nhớ cache cục bộ của 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);
    });
});

Với những thay đổi này, chúng tôi hiện đã đảm bảo rằng trạng thái Cloud Firestore cục bộ sẽ luôn phản ánh trạng thái trực tuyến / ngoại tuyến của thiết bị. Điều này có nghĩa là bạn có thể nghe tài liệu /status/{uid} và sử dụng dữ liệu để thay đổi giao diện người dùng của mình nhằm phản ánh trạng thái kết nối.

Web

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

Cập nhật Cloud Firestore trên toàn cầu

Mặc dù ứng dụng của chúng tôi báo cáo chính xác sự hiện diện trực tuyến cho chính nó, trạng thái này sẽ không chính xác trong các ứng dụng Cloud Firestore khác vì ghi trạng thái "ngoại tuyến" của chúng tôi chỉ là cục bộ và sẽ không được đồng bộ hóa khi kết nối được khôi phục. Để chống lại điều này, chúng tôi sẽ sử dụng Chức năng đám mây theo dõi status/{uid} trong Cơ sở dữ liệu thời gian thực. Khi giá trị Cơ sở dữ liệu thời gian thực thay đổi, giá trị sẽ đồng bộ với Cloud Firestore để tất cả trạng thái của người dùng đều chính xác.

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

Sau khi triển khai chức năng này, bạn sẽ có một hệ thống hiện diện hoàn chỉnh chạy với Cloud Firestore. Dưới đây là ví dụ về giám sát bất kỳ người dùng nào trực tuyến hoặc ngoại tuyến bằng cách sử dụng truy vấn 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);
                // ...
            }
        });
    });

Hạn chế

Sử dụng Cơ sở dữ liệu thời gian thực để thêm sự hiện diện vào ứng dụng Cloud Firestore của bạn có thể mở rộng và hiệu quả nhưng có một số hạn chế:

  • Debouncing - khi lắng nghe các thay đổi theo thời gian thực trong Cloud Firestore, giải pháp này có thể kích hoạt nhiều thay đổi. Nếu những thay đổi này kích hoạt nhiều sự kiện hơn bạn muốn, hãy gỡ bỏ các sự kiện Cloud Firestore theo cách thủ công.
  • Khả năng kết nối - việc triển khai này đo lường kết nối với Cơ sở dữ liệu thời gian thực, không phải với Cloud Firestore. Nếu trạng thái kết nối đến mỗi cơ sở dữ liệu không giống nhau, giải pháp này có thể báo cáo trạng thái hiện diện không chính xác.
  • Android - trên Android, Cơ sở dữ liệu thời gian thực ngắt kết nối khỏi chương trình phụ trợ sau 60 giây không hoạt động. Không hoạt động có nghĩa là không có người nghe đang mở hoặc hoạt động đang chờ xử lý. Để giữ cho kết nối luôn mở, chúng tôi khuyên bạn nên thêm trình xử lý sự kiện giá trị vào một đường dẫn bên cạnh .info/connected . Ví dụ: bạn có thể thực hiện FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() khi bắt đầu mỗi phiên. Để biết thêm thông tin, hãy xem Phát hiện trạng thái kết nối .