【问题标题】:Firestore listener for sub collections子集合的 Firestore 监听器
【发布时间】:2023-04-10 02:49:01
【问题描述】:

我通过以下方式设置 Firestore:

Channels [collection] ----> channelID ---> Messages [collection] ---> 消息ID

如何将 snapshotListener 添加到子集合“消息”?

  Firestore.firestore().collection("Channels").document().collection("Messages").addSnapshotListener { (querySnapshot, error) in
        guard let snapshot = querySnapshot else {
            print("Error listening for channel updates: \(error?.localizedDescription ?? "No error")")
            return
        }

        snapshot.documentChanges.forEach { change in 
           print(change)
        }
    }

这对我不起作用

【问题讨论】:

  • 为什么你说它不起作用?你有错误吗?
  • 添加新消息时,不会调用此监听器
  • 在这种情况下,请添加更多代码。
  • 我更新了帖子

标签: ios swift firebase google-cloud-firestore


【解决方案1】:

我想是因为有了

Firestore.firestore().collection("Channels").document().collection("Messages")

您没有定义正确的CollectionReference,因为您没有识别“Channels”集合的文档。

你应该这样做:

Firestore.firestore().collection("Channels").document(channelID).collection("Messages")

【讨论】:

  • 这不是我想要的,使用你的代码我只会收听一个 id == channelID 的频道,但我想收听所有频道
  • 更新:见 Doug 的回答。你想要的是不可能的。如果您收听Firestore.firestore().collection("Channels"),该文档说“每次查询结果更改时(即添加、删除或修改 document 时),快照处理程序都会收到一个新的查询快照” .
  • 好的,所以我认为最好的解决方案是将消息移动为根集合并在消息内部添加字段 channelID
  • 是的,这将是一个解决方案。
【解决方案2】:

您不能让单个侦听器接收来自未知数量的子集合的更新。集合上的侦听器没有“通配符”运算符。您必须选择一个特定的集合或查询并为其附加一个侦听器。

【讨论】:

    【解决方案3】:

    正如 Doug 在他的正确答案中指出的那样,您不能让单个侦听器接收来自未知(数量或未指定)子集合的更新。

    但是,如果您可以确定这些子集合名称,那么答案就很简单了。

    这个想法是读取 Channels 的子节点,它们将是 channel_0、channel_1 等,并使用这些文档 id 来构建对您有兴趣收听的节点的引用。

    因此,鉴于这种结构(与问题中的结构相匹配):

    Channels
      channel_0
        Messages
          message_0
            msg: "chan 0 msg 0"
          message_1
            msg: "chan 0 msg 1"
          message_2
            msg: "chan 0 msg 2"
      channel_1
        Messages
          message_0
            msg: "chan 1 msg 0"
          message_1
            msg: "chan 1 msg 1"
    

    这是为每个通道添加侦听器并响应该通道消息中的事件的代码,该消息在控制台中通知消息 ID、消息文本和事件发生的通道。

    func addChannelCollectionObserver() {
        let channelsRef = self.db.collection("Channels")
        channelsRef.getDocuments(completion: { snapshot, error in
    
            guard let documents = snapshot?.documents else {
                print("Collection was empty")
                return
            }
    
            for doc in documents {
                let docID = doc.documentID
                let eachChannelRef = channelsRef.document(docID)
                let messagesRef = eachChannelRef.collection("Messages")
    
                messagesRef.addSnapshotListener { querySnapshot, error in
    
                    querySnapshot?.documentChanges.forEach { diff in
                        if diff.type == .added {
                            let doc = diff.document
                            let msgId = doc.documentID
                            let channelId = messagesRef.parent!.documentID
                            let msg = doc.get("msg") as? String ?? "no message"
                            print(" added msgId: \(msgId) with msg: \(msg) in channel: \(channelId)")
                        }
    
                        if diff.type == .modified {
                            let doc = diff.document
                            let msgId = doc.documentID
                            let msg = doc.get("msg") as? String ?? "no message"
                            print(" modified msgId: \(msgId) with msg: \(msg)")
                        }
    
                        if diff.type == .removed {
                            let doc = diff.document
                            let msgId = doc.documentID
                            let msg = doc.get("msg") as? String ?? "no message"
                            print(" removed msgId: \(msgId) with msg: \(msg)")
                        }
                    }
                }
            }
        })
    }
    

    首次运行时,输出将按预期显示每个子节点。从那时起,它将输出任何添加、修改或删除。

     added msgId: message_0 with msg: chan 0 msg 0 in channel: channel_0
     added msgId: message_1 with msg: chan 0 msg 1 in channel: channel_0
     added msgId: message_2 with msg: chan 0 msg 2 in channel: channel_0
     added msgId: message_0 with msg: chan 1 msg 0 in channel: channel_1
     added msgId: message_1 with msg: chan 1 msg 1 in channel: channel_1
    

    代码还需要对某些选项进行一些额外的错误检查,但它应该提供解决方案。

    【讨论】:

    • @anoop4real 性能非常好,不能说它是“建议的”,但是它确实有效并提供了预期的结果。一般来说 - 这是一个建议的解决方案,所以我会试一试。
    • 感谢您的回复,我遇到了一个疯狂的情况,我在这里发布了它..groups.google.com/forum/#!topic/google-cloud-firestore-discuss/… ...您可以看看,看看您是否可以提出任何建议?
    • 此解决方案不可扩展,这样您只能启动 100 个侦听器。您应该使用 Collection-group-query firebase.google.com/docs/firestore/query-data/…
    • @akhil 我们有成千上万的听众在使用它,没有任何问题。为什么认为有100个限制?是的集合组,但在 2018 年(发布时),该功能没有得到很好的开发。
    【解决方案4】:

    为此使用collection group query,监听所有同名的集合

        db.collectionGroup("Messages"). docRef.addSnapshotListener(new EventListener<DocumentSnapshot>() {
      @Override
      public void onEvent(@Nullable DocumentSnapshot snapshot,
                          @Nullable FirestoreException e) {
        if (snapshot != null && snapshot.exists()) {
          System.out.println("Current data: " + snapshot.getData());
        } else {
          System.out.print("Current data: null");
        }
      }
    });
    

    【讨论】:

    • 这应该是公认的答案。谢谢。
    【解决方案5】:

    如果您想在后端订阅 Firstore 子集合更改,这里是来自 Firebase docs 的 NodeJS 示例:

    // Listen for changes in all documents in the 'users' collection and all subcollections
    exports.useMultipleWildcards = functions.firestore
        .document('users/{userId}/{messageCollectionId}/{messageId}')
        .onWrite((change, context) => {
          // If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
          // context.params.userId == "marie";
          // context.params.messageCollectionId == "incoming_messages";
          // context.params.messageId == "134";
          // ... and ...
          // change.after.data() == {body: "Hello"}
        });
    

    请注意,即使是子集合名称也可以与通配符 {messageCollectionId} 一起使用,即我们可以订阅用户集合的任何子集合

    根据问题Channels [collection] ----&gt; channelID ---&gt; Messages [collection] ---&gt; messageID代码可以是:

    exports.onMessagesSubcollectionChange = functions.firestore
        .document('Channels/{channelID}/Messages/{messageID}')
        .onWrite((change, context) => {
       // the rest code
       // context.params.channelID
       // and context.params.messageID will be fulfilled.
    }
    

    不确定客户端是否支持。

    【讨论】:

      猜你喜欢
      • 2021-03-06
      • 2021-03-10
      • 2021-10-05
      • 2020-05-18
      • 2020-03-17
      • 2020-10-27
      • 2019-10-24
      • 1970-01-01
      • 2022-01-19
      相关资源
      最近更新 更多