为啥添加单个文档时,Firestore 侦听器会返回 .add 两次?

Posted

技术标签:

【中文标题】为啥添加单个文档时,Firestore 侦听器会返回 .add 两次?【英文标题】:Why is a firestore listener returning .added twice when a single document is added?为什么添加单个文档时,Firestore 侦听器会返回 .add 两次? 【发布时间】:2017-12-12 01:22:27 【问题描述】:

我正在使用谷歌地图,我的用户可以在地图上添加地图标记。 地图标记存储在 Firestore 中。 我有一个监听数据库的监听器。 每个用户只能提交一个地图标记 - 因此数据库中每个用户只有一个文档。但他们可以修改标记的 lat 和 lng。

我的 Firestore 设置为:

root
  - submittedMarkers (collection)
          - fireauthID_1 (document)
                - field 1 (lat): 
                - field 2 (lng):
          - fireauthID_2 (document)
                - field 1 (lat):
                - field 2 (lng): 

// MapController.swift

override func viewWillAppear(_ animated: Bool)
    listener = db.collection("submittedMarkers").addSnapshotListener  querySnapshot, error in
        guard let snapshot = querySnapshot else 
            print("Error fetching snapshots: \(error!)")
            return
        
        snapshot.documentChanges.forEach  diff in   
            if (diff.type == .added)
                print("added")
            
            if(diff.type == .modified) 
                print("modified the document in firestore")
            
        
    

目前为了调试,我在 firestore 中只有一个用户,submittedMarkers 下只有一个文档 -> fireauthId

当我的应用加载当前存在的单个标记时,将与单个打印语句“添加”一起添加到地图中。这样就行了。

这是我遇到的问题。

当一个新用户注册并获得一个 fireauth id 时,他们可以从AddMarkerController 添加一个标记。当他们提交标记时,我使用 unwind segue 让他们回到MapController。 (我不会在任何阶段将监听器与MapController 分离)。

// 添加标记控制器

docref = db.collection("submittedMarkers").document(currentUserId)
docref?.setData([
    "latitude": latitude,
    "longitude": longitude,
    "date_time": date!,
    "distance": dist, 
    "speed": speed
], options: SetOptions.merge())  err in
    if let err = err 
        print("Error writing document: \(err)")
     else 

    

但我发现,当他们回到MapController 时,if (diff.type == .added) 会执行两次,并且 print(" added") 会发生两次,即使 currentuser fireauth id 只是在集合下添加了一次submittedMarkers

当我打印出 diff.document.ID 时,我得到了已经在 firestore 中的用户和刚刚添加新文档的当前用户的 fireauth id。

我怀疑我不太明白监听器是如何工作的。我以为if(diff = .added) 会监听submittedMarkers 集合,并且只会在添加新文档时触发一次。

我不确定问题是否是:

    我离开MapController时没有分离监听器 -> AddMarkerController? 听众在viewWillAppear而不是viewDidLoad,但从阅读firebase博客来看,它应该在viewWillAppear 无论是 snapshot.documentChanges.forEach 在每次发生变化时循环整个快照

【问题讨论】:

【参考方案1】:

第一个added 是在您调用setData() 时立即触发的本地事件。第二个added是服务器写入数据后的确认事件。

请参阅文档中的events for local changes 部分。

另一个原因可能是您未能取消注册观察者。如果您在 viewWillAppear 中注册了您的观察者,请在 viewWillDisappearviewDidDisappear 中取消注册。如果你不这样做,你最终会为同一个事件有多个观察者,因此会有多个调用。

【讨论】:

嗨@Frank。我仍然有同样的行为。我以第二个用户身份登录我的应用程序。 firestore 中的单个标记已正确加载,并且 diff = . added 被触发一次。但是,每次我从 MapController 转到另一个控制器并返回时,viewWillAppear 都会像往常一样执行,但我发现自己又回到了 diff == .add 中,每次都再次加载服务器数据。我在原始帖子的末尾进行了更新,并提供了更多信息。我想知道我的听众是否在每次我回到 viewWillAppear 时都重新注册。谢谢。 啊,可能是这样。我必须承认我没有阅读 all 您问题中的代码+描述(通常:少即是多)。如果您在viewWillAppear 中注册您的观察者,请在ViewWillDisappearviewDidDisappear 中取消注册。如果你不这样做,你最终会为同一个事件有多个观察者,因此会有多个调用。

以上是关于为啥添加单个文档时,Firestore 侦听器会返回 .add 两次?的主要内容,如果未能解决你的问题,请参考以下文章

添加新文档时,kotlin firestore 未更新我的 android 应用程序

TypeError:无法读取 null 的属性“Symbol(dartx._get)”(在 Flutter 中添加 Firestore 侦听器时)

为啥 Firebase 数据库(Firestore)不添加文档

只收听云 Firestore 集合的添加内容?

在 React Native 中添加新消息时,Firestore 侦听器从分页中删除消息

为整个应用程序引用一个类的单个实例(Firebase)