我将一些数据存储在名为"的通知"在我的Firebase数据库中。当我将事件观察者添加到"通知"并将事件类型设置为" .childAdded"每次将子项添加到"通知"时,都会调用完成处理程序。每次从"通知"中删除子项时,节点AND节点。首先,我不明白为什么会这样,因为没有添加任何内容,只是删除了。有没有办法避免这种情况?
如果我不能在每次删除子项时都避免执行.childAdded块,那么是否有人检测到它实际上是子被删除事件而不是子事件添加事件?如果事件被删除,我想从函数中提前返回。以下是我的参考代码:
//Event observer for notifications
notificationsReference.queryLimited(toLast: 1).observe(.childAdded, with: {
(snapshot) in
//Do some stuff here only on .childAdded
//If the event was child deleted, do nothing
})
答案 0 :(得分:8)
Firebase查询就像是对数据的查看。在您的情况下,视图将始终显示基础集合中的最后一项。
说这是你的收藏:
item1
item2
使用此数据,您的查询最初会针对item2
触发child_added。
现在说你添加一个项目:
item1
item2
item3
由于item3
现在是集合中的最后一项,因此查询将触发item3
的child_added。
现在删除item3
:
item1
item2
由于item2
现在又是查询中的最后一项,因此会触发item2
的child_added。
答案 1 :(得分:0)
有趣的是,我从 Frank 为 JS Firebase SDK 编写的替代答案中找到了处理此问题的正确方法:child_added gets triggered after remove。我使用了一种方法,将他的答案从评论修改为他的答案。特别是加藤对how to discard initial data in a Firebase DB的回答。
本质上,在两个答案中,您的子对象中都需要有一个时间戳(或其他一些数字递增的值),以帮助您对子对象进行排序。然后,当您形成 firebase 查询时,您将设置一个条件,该条件读取此属性超过最小增加值的值。这样,如果值被删除,它们不会受到影响,因为它们的排序键将小于传递的键。
对应的 Swift 代码如下所示:
let databaseReference = Database.database().reference().child("messages")
let timeStampKeyInChildObject = "messageTimestamp"
databaseReference
.queryOrdered(byChild: timeStampKeyInChildObject)
.queryStarting(atValue: NSDate().timeIntervalSince1970)
.observe(.childAdded)
{ (snapshot) in
...
}
就我而言,子对象是具有名为 messageTimestamp
的字段的聊天消息。当我在 firebase 中存储消息时,时间戳是使用 NSDate().timeIntervalSince1970
设置的。因此我将此值传递给 queryStarting(atValue:)
。
每次更新数据库时(在这种情况下子删除/添加/修改),只有当删除/添加/修改子的时间戳大于或等于 NSDate().timeIntervalSince1970
(其值不断增加)。这只会发生在当前添加的孩子身上。任何较旧的(尤其是已删除的)将具有较小的时间戳,并且不会被我们的查询考虑在内。因此解决了删除导致 .childAdded
触发器运行的问题。
我选择使用 NSDate().timeIntervalSince1970
而不是 Firebase.ServerValue.TIMESTAMP
的 JS 等价物,我认为它是 Firebase.ServerValue.timestamp()
,因为它返回 [AnyHashable : Any]
。而且我不知道如何解码。
此外,为了提高性能,将此添加到您的 Firebase RealtimeDB 规则中。这将在数据库端而不是在客户端(下载数据后)进行排序。
"messages": {
".indexOn": ["messageTimestamp"]
},