【发布时间】:2015-06-08 08:09:21
【问题描述】:
我在网站右上角有 Facebook 样式通知。我在那里显示最多 5 条最新通知。我使用child_added 进行初始拉动,并在相同的firebaseRef child_added 监听新通知之后。
现在我想在新通知和少量新通知上播放声音。
我唯一想不通的是如何区分什么时候是新通知,什么时候已经看到,也就是页面重新加载?除了制作一些新财产read,还有其他方法吗?
我环顾四周,发现了一些 2012 年的旧答案,其中包含对我的情况没有帮助的建议 limitToLast(1)。
编辑:
https://stackoverflow.com/a/27693310/633154 这个@Kato 回答建议只收听时间超过当前 Firebase 时间Firebase.ServerValue.TIMESTAMP 的新通知。这似乎是要走的路,但我正在使用 REST API 创建一个新通知,并且我自己将时间戳设置为我的服务器的 UTC。所以可能会有一些细微的不一致。应该没什么大不了的
编辑 2:
通过此查询,我在页面加载时最多可以正确收到 5 个最新通知,之后不会再收到新通知
notifRef.limitToLast(5).once("value", function(snapshot) {
snapshot.forEach(function(data) {
addNotifications(data.val());
});
});
在上面链接的其他 SO 线程中,@Kato 的答案不起作用,notifRef.orderBy is not a function。
我根据文档尝试了多个其他版本
https://www.firebase.com/docs/web/guide/retrieving-data.html#section-queries
我的结构是一样的
{
"messages": {
"$messageid": { // firebase generated key 'JqcEWLFJrl1eaed5naN'
"sender": "kato",
"message": "hello world"
"timestamp": 1433036536108 // Firebase.ServerValue.TIMESTAMP
}
}
}
这是我尝试做的以及我得到的错误:
var queryRef = notifRef.orderByKey().startAt(Firebase.ServerValue.TIMESTAMP);
错误:Query: When ordering by key, the argument passed to startAt(), endAt(),or equalTo() must be a string.
var queryRef = notifRef.orderByChild('timestamp').startAt(Firebase.ServerValue.TIMESTAMP);
错误:Query: First argument passed to startAt(), endAt(), or equalTo() cannot be an object.
在文档中,除了传递元素位置(整数)而不是 firebase 时间戳对象外,我还没有看到 startAt 的任何内容,这就是出现此类错误的原因。
只有下面的编译,只有 startAt 没有排序,但它没有发出任何新的通知!
var queryRef = notifRef.startAt(Firebase.ServerValue.TIMESTAMP);
queryRef.on('child_added', function(snap) {
console.log(snap.val());
addNotifications(snap.val());
// TODO clean up if more than 5 notifications
});
知道问题出在哪里吗?只收听比当前时间戳更新的通知的正确方法是什么?
编辑 3
这是我的最终解决方案
notifRef.limitToLast(5).once("value", function(snapshot) {
var lastKey = null; // at least 1 key is always present
var count = 0; // because startAt is inclusive, we have to ignore first child_added
snapshot.forEach(function(data) {
addNotifications(data.val());
lastKey = data.key();
});
checkNotifications();
notifRef.orderByKey().startAt(lastKey).on('child_added', function(snap) {
if (count > 0) {
console.log(snap.val());
addNotifications(snap.val());
// TODO clean up if more than 5 notifications
checkNotifications();
}
count++;
});
});
我不信任浏览器时间,因此必须先查询最后 5 个现有密钥,然后将我收到的最后一个密钥传递给 startAt。 notifRef.orderByKey().startAt(lastKey) 不能在 notifRef.limitToLast(5).once("value" 之外,因为根据文档,once 是最后查询的,因此传递给 startAt 的 lastKey js 变量将始终为空。
还需要有count 变量,因为startAt 包含在内,但因为它已经存在,我需要忽略第一个。
当有超过 5 个通知时,也使用此解决方案,当使用 once 查询收到通知时,我只在最后使用 checkNotifications 查询我的后端一次。否则在 child_added 上,每次页面加载最多会执行 5 次。
如果有什么可以优化的,请告诉
【问题讨论】:
-
@FrankvanPuffelen 谢谢,看到了,但正如 some1 提到的那样,
once('value'效率不高,因为我可能有数百个通知,并且会拉出所有通知,但我最初只需要最多 5 个最新的然后只听新的 -
最后一个代码 sn-p 不起作用,因为您还没有按时间戳排序。如果
ref指的是数据结构的根,则需要ref.child('messages').orderByChild('timestamp').startAt(Date.now()).once('child_added', function....。您希望将Date.now()替换为您上次检查的时间戳的位置。请注意,您的所有编辑和 cmets 都无助于使您的问题更清晰。如果您仍然遇到同样的问题,您通常会通过创建一个最小的小提琴来重现它并发布它来获得更好的响应。
标签: javascript firebase