javascript - 在 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 变化非常频繁。所以我想把它放在一个地方。
解决方案
我与观察者一起观察每个朋友 peerId,但将每个观察者存储到字典中以防止一个人有多个观察者。我还发现了这个:在 JavaScript 中启用离线功能
onDisconnect:
onDisconnect()
当客户端与数据库断开连接时触发操作。如果浏览器崩溃,卸载事件(我使用的)不会被触发,但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);
}
});
}
}
推荐阅读
- angular - 如何覆盖 cdk-mouse-focused 和 cdk-focused
- python - 在 Python 列中对对应的行值进行分组
- android - Facebook 广告仅在从 Play 商店下载的应用中显示
- angular - angular4多文件上传第二组文件清空
- java - 可重入锁的表现在哪里?
- php - 无法在 PHP 中将上传文件名保存到 SQL
- node.js - Nodejs:进行http请求调用并将结果更新到mongoDB
- c - 在 C 中强制转换函数指针返回类型
- javascript - create array from specific classes texts
- ios - Equivalent of glColorMask in Metal for a kernel program?