在 Firebase iOS SDK 中,每次删除孩子时都会触发 .childAdded。我怎样才能阻止这个?

Posted

技术标签:

【中文标题】在 Firebase iOS SDK 中,每次删除孩子时都会触发 .childAdded。我怎样才能阻止这个?【英文标题】:In Firebase iOS SDK, .childAdded is triggered every time a child is deleted. How can I stop this? 【发布时间】:2016-09-28 01:40:31 【问题描述】:

我将一些数据存储在我的 Firebase 数据库中一个名为“通知”的节点下。当我将事件观察者添加到“通知”并将事件类型设置为“.childAdded”时,每次将子项添加到“通知”节点以及每次从“通知”节点中删除子项时都会调用完成处理程序.首先,我不明白为什么会发生这种情况,因为没有添加任何内容,只是删除了。有什么办法可以避免这种情况吗?

如果我无法避免每次删除子项时执行 .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 
)

【问题讨论】:

你能在哪里解决这个问题?我也面临同样的问题。 不,我不是。如果我没记错的话,我联系了 firebase 团队,并被告知该产品是故意以这种方式工作的。那是几年前的事了,所以如果您今天尝试与他们联系,您可能会有更好的运气。抱歉,我无法提供更多帮助。 @LukeIrvin 看到我的回答。 【参考方案1】:

Firebase 查询类似于数据视图。在您的情况下,该视图将始终显示基础集合中的最后一项。

说这是你的收藏:

item1
item2

有了这些数据,您的查询最初会为item2 触发 child_added。

现在假设您添加了一个项目:

item1
item2
item3

由于item3 现在是集合中的最后一项,查询将为item3 触发 child_added。

现在你删除item3

item1
item2

由于item2 现在再次成为查询中的最后一项,它将为item2 触发 child_added。

【讨论】:

非常感谢弗兰克的回复。有一件事我还不清楚,有没有办法检测到该事件实际上是一个子删除事件,而不是一个 .childAdded 事件?我不想下载所有通知项,我只想跟踪添加新通知项的时间。问题是,如果我取出限制为 last 1 的查询,则关闭将为通知下的每个孩子执行,然后开始观察新的孩子。通知可能包含成百上千的孩子,我不想不必要地下载数据。 没有特定的事件可以帮助您。 Firebase 同步状态,您似乎对同步操作更感兴趣。在这种情况下,将实际操作存储在数据库中可能会更好。例如:如果有人删除了一个孩子,然后又将其添加回来,当您的客户端在隧道中时,当它重新上线时,它不会收到事件。 @ParthTamane 你能解释一下为什么不吗?或者给出一个替代答案来解决你在这个问题中看到的问题? @FrankvanPuffelen 是的,让我添加一个链接。我觉得这不是正确的答案,因为它不会解决他在删除时触发运行的问题。 添加了一个答案,灵感来自您的答案:P【参考方案2】:

有趣的是,我从 Frank 为 JS Firebase SDK 编写的替代答案中找到了处理此问题的正确方法:child_added gets triggered after remove。我使用了一种方法,将他的答案从 cmets 修改为他的答案。特别是加藤对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"]
,

【讨论】:

以上是关于在 Firebase iOS SDK 中,每次删除孩子时都会触发 .childAdded。我怎样才能阻止这个?的主要内容,如果未能解决你的问题,请参考以下文章

无法在 iOS 中连接 firebase crashlytics

Firebase SDK 与 Facebook SDK 冲突

从托盘中删除 Firebase 通知(Android、Unity SDK)

iOS Swift Firebase SDK 导入问题

在 iOS 应用中升级 SDK 后 Firebase Crashlytics 不显示日志

使用私有Google存储的Firebase iOS SDK身份验证