首页 > 解决方案 > 在 Firebase 实时数据库中观察同一节点的多个子节点

问题描述

我使用 Firebase 实时数据库将用户的 uid 解析为临时 peerId。每个用户在上线时创建此 peerId,并在下线之前将其设置为 null。因此,如果用户的 uid 在 /peerIdByUid/ 中找到,则用户在线。

这是我的数据的样子:

/peerIdByUid/$uid = $peerId

每个用户都是一个节点,其 uid 为键,peerId 为值。

每个用户都有朋友,需要知道他们是否在线、离线等。

我需要为每个参考创建一个观察者吗?

例子:

//for each friend
firebase.database().ref('/peerIdByUid/' + friendUserId).on('value').then(function(snapshot) {
  //display friend online/offline
});

有没有更优雅的解决方案,我只用一个观察者观察用户的朋友?

而且我不想做一些昂贵的事情,比如:

firebase.database().ref('/peerIdByUid').on("value")...

因为这会将所有用户的数据下载到客户端,可能会让我破产。

我在想类似的东西

const refsToFriends = ['/peerIdByUid/firend1', '/peerIdByUid/friend2', ...];
firebase.database().observe(refToFriend).on('value').then(...);

另一方面,根据这个答案:Firebase 观察者实际上做了什么?这是没有意义的,我可以根据每个朋友的参考创建一个观察者。

我还考虑在每个用户的好友列表中写入 peerIds。但这会使所需的空间和流量乘以每个朋友的数量。并且 peerId 变化非常频繁。所以我想把它放在一个地方。

标签: javascriptfirebasefirebase-realtime-database

解决方案


我与观察者一起观察每个朋友 peerId,但将每个观察者存储到字典中以防止一个人有多个观察者。我还发现了这个:在 JavaScript 中启用离线功能

onDisconnectonDisconnect()当客户端与数据库断开连接时触发操作。如果浏览器崩溃,卸载事件(我使用的)不会被触发,但onDisconnect()会触发。

注册 peerId 并在断开连接时将其删除:

//this function registers the peerId to the uid and saves the current timstamp
//it also deletes the peerId and timestamp on disconnect
async registerPeerId(uid: string, peerId: string) {
    const peerIdRef = firebase.database.ref(`peerIdByUid/${uid}`);
    await peerIdRef.set({
        peerId,
        timestamp: db.ServerValue.TIMESTAMP
    });
    peerIdRef.onDisconnect().set(null);
}

听朋友在线和离线:

//global dictionary to store observer for friends
const friendListeners: Dictionary<Function> = {}; 
// some function to that is called on initalization of app
async function loadFriends(){
  const friends = await findFriends(); //load friends
  await Promise.all(friends.map(async (f: Friend) => {
    listenToFriend(f);
    // other stuff: e.g. connecting to friend
  });
}

function listenToFriend(friend: Friend) {
  //check if an observer exists
  if(!(friend.uid in friendListeners)) {
    friendListeners[friend.uid] = firebase.database
                                  .ref(`peerIdByUid/${friend.uid}`)
                                  .on("value", (snapshot: db.DataSnapshot) => {
      if (snapshot.exists()) {
        let {peerId} = snapshot.val();
        //this stores the new peerId into a global store that can be checked fast and cheap
        upsertPeerId(friend.uid, peerId);
      } else {
        // sets peerId to null to show that user is offline
        upsertPeerId(friend.uid, null);
      }
    });
  }
}

推荐阅读