页面加载后仅获取新的 "child added"

Get only new "child added" after page load

我在网站的右上角有 facebook 风格的通知。我在那里显示 最多 5 个最新通知。我用 child_added 进行初始拉动,并且在相同的 firebaseRef child_added 之后监听新通知。

现在我想在收到新通知和少量新通知时播放声音。
我唯一想不通的是如何区分什么时候是新通知,什么时候已经看到,a.k.a 页面重新加载?除了制作一些新的 属性 read 之外还有其他方法吗?

我环顾四周,发现了 2012 年的一些旧答案以及建议 limitToLast(1),这对我的情况没有帮助。

编辑:

这个@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
根据 doc
我已经尝试了多个其他版本 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.

在文档中我没有看到 startAt 除了元素位置被传递(整数)而不是 firebase 时间戳对象之外的任何东西,这就是为什么这样的错误。

只有 below 编译,只是有 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 个现有密钥,然后再将我收到的最后一个密钥传递给 startAtnotifRef.orderByKey().startAt(lastKey) 不能在 notifRef.limitToLast(5).once("value" 之外,因为根据文档,最后查询 once 因此传递给 startAtlastKey js 变量将始终为 null。
还需要有 count 变量,因为 startAt 是包容性的,但因为它已经存在,所以我需要忽略第一个。
此外,当有超过 5 个通知时使用此解决方案,当收到 once 查询通知时,我只在最后一次使用 checkNotifications 查询我的后端。否则在 child_added 上它会在每次页面加载时执行多达 5 次。

如果有什么可以优化的,请告诉

一个解决方案是让您的本地客户端通过 ref.limitToLast(5).on('child_added', ...) 收听最近 5 条最新通知,然后仅在每个通知上的某个时间戳字段为 时才将它们呈现给用户 比机器上的本地时间戳更新。

当从其他客户端写入这些通知时,您可以包含通过 Firebase.ServerValue.TIMESTAMP 指定的时间戳字段,这将使用服务器的 Unix 时间戳概念。然后,该数据的读者可以将该时间戳与他们的本地时钟进行比较,以做出上述决定。