Firestore listener for sub collections











up vote
1
down vote

favorite












I have my Firestore setup in the following way:



Channels [collection] ----> channelID ---> Messages [collection] --->
messageID



How would I add snapshotListener to sub collection 'Messages' ?



  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)
}
}


This didn't work for me










share|improve this question
























  • Why you say it didn't work? Do you have an error?
    – Alex Mamo
    Nov 9 at 14:16










  • When I add a new message, this listener is not called
    – OuSS
    Nov 9 at 14:18










  • In this case, please add more code.
    – Alex Mamo
    Nov 9 at 14:19










  • I updated the post
    – OuSS
    Nov 9 at 14:22















up vote
1
down vote

favorite












I have my Firestore setup in the following way:



Channels [collection] ----> channelID ---> Messages [collection] --->
messageID



How would I add snapshotListener to sub collection 'Messages' ?



  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)
}
}


This didn't work for me










share|improve this question
























  • Why you say it didn't work? Do you have an error?
    – Alex Mamo
    Nov 9 at 14:16










  • When I add a new message, this listener is not called
    – OuSS
    Nov 9 at 14:18










  • In this case, please add more code.
    – Alex Mamo
    Nov 9 at 14:19










  • I updated the post
    – OuSS
    Nov 9 at 14:22













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I have my Firestore setup in the following way:



Channels [collection] ----> channelID ---> Messages [collection] --->
messageID



How would I add snapshotListener to sub collection 'Messages' ?



  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)
}
}


This didn't work for me










share|improve this question















I have my Firestore setup in the following way:



Channels [collection] ----> channelID ---> Messages [collection] --->
messageID



How would I add snapshotListener to sub collection 'Messages' ?



  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)
}
}


This didn't work for me







ios swift firebase google-cloud-firestore






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 9 at 14:21

























asked Nov 9 at 14:14









OuSS

204113




204113












  • Why you say it didn't work? Do you have an error?
    – Alex Mamo
    Nov 9 at 14:16










  • When I add a new message, this listener is not called
    – OuSS
    Nov 9 at 14:18










  • In this case, please add more code.
    – Alex Mamo
    Nov 9 at 14:19










  • I updated the post
    – OuSS
    Nov 9 at 14:22


















  • Why you say it didn't work? Do you have an error?
    – Alex Mamo
    Nov 9 at 14:16










  • When I add a new message, this listener is not called
    – OuSS
    Nov 9 at 14:18










  • In this case, please add more code.
    – Alex Mamo
    Nov 9 at 14:19










  • I updated the post
    – OuSS
    Nov 9 at 14:22
















Why you say it didn't work? Do you have an error?
– Alex Mamo
Nov 9 at 14:16




Why you say it didn't work? Do you have an error?
– Alex Mamo
Nov 9 at 14:16












When I add a new message, this listener is not called
– OuSS
Nov 9 at 14:18




When I add a new message, this listener is not called
– OuSS
Nov 9 at 14:18












In this case, please add more code.
– Alex Mamo
Nov 9 at 14:19




In this case, please add more code.
– Alex Mamo
Nov 9 at 14:19












I updated the post
– OuSS
Nov 9 at 14:22




I updated the post
– OuSS
Nov 9 at 14:22












3 Answers
3






active

oldest

votes

















up vote
1
down vote













You can't have a single listener receive updates from an unknown number of subcollection. There are no "wildcard" operators for listeners on collections. You have to choose a specific collection or query and attach a listener to that.






share|improve this answer




























    up vote
    0
    down vote













    I think it is because with



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


    you are not defining a correct CollectionReference since you don't identify the document of the "Channels" collection.



    You should do:



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





    share|improve this answer





















    • This is not what i want, with your code i will just listen to one channel that have id == channelID but me i want to listen to all Channels
      – OuSS
      Nov 9 at 14:42












    • Update: see Doug's answer. What you want is not possible. If you listen to Firestore.firestore().collection("Channels") the doc says that "the snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified)".
      – Renaud Tarnec
      Nov 9 at 14:47












    • Ok so i think the best solution it to move Messages to be a root collection and inside message add field channelID
      – OuSS
      Nov 9 at 14:48










    • Yes, that would be a solution.
      – Renaud Tarnec
      Nov 9 at 14:54


















    up vote
    0
    down vote













    As Doug pointed out in his correct answer, you cannot have a single listener receive updates from an unknown (number of or unspecified) subcollection.



    However, if you can determine those subcollection names, then the answer is pretty straightforward.



    The idea is to read the child nodes of Channels, which will be channel_0, channel_1 etc and use those document id's to build references to the nodes you are interested in listening to.



    So given this struture (which matches the structure in the question):



    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"


    Here's the code that adds listeners to each channel, and responds to events within that channels messages notifying in console the message id, msg text and the channel the event occurred in.



    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)")
    }
    }
    }
    }
    })
    }


    When first run the output will show, as expected, each child node. From then on it will output any addititions, modifications or deletions.



     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


    the code needs some additional error checking as well for some of the optionals but it should provide a solution.






    share|improve this answer





















      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














       

      draft saved


      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53227376%2ffirestore-listener-for-sub-collections%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      1
      down vote













      You can't have a single listener receive updates from an unknown number of subcollection. There are no "wildcard" operators for listeners on collections. You have to choose a specific collection or query and attach a listener to that.






      share|improve this answer

























        up vote
        1
        down vote













        You can't have a single listener receive updates from an unknown number of subcollection. There are no "wildcard" operators for listeners on collections. You have to choose a specific collection or query and attach a listener to that.






        share|improve this answer























          up vote
          1
          down vote










          up vote
          1
          down vote









          You can't have a single listener receive updates from an unknown number of subcollection. There are no "wildcard" operators for listeners on collections. You have to choose a specific collection or query and attach a listener to that.






          share|improve this answer












          You can't have a single listener receive updates from an unknown number of subcollection. There are no "wildcard" operators for listeners on collections. You have to choose a specific collection or query and attach a listener to that.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 9 at 14:48









          Doug Stevenson

          65.7k77997




          65.7k77997
























              up vote
              0
              down vote













              I think it is because with



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


              you are not defining a correct CollectionReference since you don't identify the document of the "Channels" collection.



              You should do:



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





              share|improve this answer





















              • This is not what i want, with your code i will just listen to one channel that have id == channelID but me i want to listen to all Channels
                – OuSS
                Nov 9 at 14:42












              • Update: see Doug's answer. What you want is not possible. If you listen to Firestore.firestore().collection("Channels") the doc says that "the snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified)".
                – Renaud Tarnec
                Nov 9 at 14:47












              • Ok so i think the best solution it to move Messages to be a root collection and inside message add field channelID
                – OuSS
                Nov 9 at 14:48










              • Yes, that would be a solution.
                – Renaud Tarnec
                Nov 9 at 14:54















              up vote
              0
              down vote













              I think it is because with



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


              you are not defining a correct CollectionReference since you don't identify the document of the "Channels" collection.



              You should do:



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





              share|improve this answer





















              • This is not what i want, with your code i will just listen to one channel that have id == channelID but me i want to listen to all Channels
                – OuSS
                Nov 9 at 14:42












              • Update: see Doug's answer. What you want is not possible. If you listen to Firestore.firestore().collection("Channels") the doc says that "the snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified)".
                – Renaud Tarnec
                Nov 9 at 14:47












              • Ok so i think the best solution it to move Messages to be a root collection and inside message add field channelID
                – OuSS
                Nov 9 at 14:48










              • Yes, that would be a solution.
                – Renaud Tarnec
                Nov 9 at 14:54













              up vote
              0
              down vote










              up vote
              0
              down vote









              I think it is because with



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


              you are not defining a correct CollectionReference since you don't identify the document of the "Channels" collection.



              You should do:



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





              share|improve this answer












              I think it is because with



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


              you are not defining a correct CollectionReference since you don't identify the document of the "Channels" collection.



              You should do:



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






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Nov 9 at 14:39









              Renaud Tarnec

              9,07121431




              9,07121431












              • This is not what i want, with your code i will just listen to one channel that have id == channelID but me i want to listen to all Channels
                – OuSS
                Nov 9 at 14:42












              • Update: see Doug's answer. What you want is not possible. If you listen to Firestore.firestore().collection("Channels") the doc says that "the snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified)".
                – Renaud Tarnec
                Nov 9 at 14:47












              • Ok so i think the best solution it to move Messages to be a root collection and inside message add field channelID
                – OuSS
                Nov 9 at 14:48










              • Yes, that would be a solution.
                – Renaud Tarnec
                Nov 9 at 14:54


















              • This is not what i want, with your code i will just listen to one channel that have id == channelID but me i want to listen to all Channels
                – OuSS
                Nov 9 at 14:42












              • Update: see Doug's answer. What you want is not possible. If you listen to Firestore.firestore().collection("Channels") the doc says that "the snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified)".
                – Renaud Tarnec
                Nov 9 at 14:47












              • Ok so i think the best solution it to move Messages to be a root collection and inside message add field channelID
                – OuSS
                Nov 9 at 14:48










              • Yes, that would be a solution.
                – Renaud Tarnec
                Nov 9 at 14:54
















              This is not what i want, with your code i will just listen to one channel that have id == channelID but me i want to listen to all Channels
              – OuSS
              Nov 9 at 14:42






              This is not what i want, with your code i will just listen to one channel that have id == channelID but me i want to listen to all Channels
              – OuSS
              Nov 9 at 14:42














              Update: see Doug's answer. What you want is not possible. If you listen to Firestore.firestore().collection("Channels") the doc says that "the snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified)".
              – Renaud Tarnec
              Nov 9 at 14:47






              Update: see Doug's answer. What you want is not possible. If you listen to Firestore.firestore().collection("Channels") the doc says that "the snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified)".
              – Renaud Tarnec
              Nov 9 at 14:47














              Ok so i think the best solution it to move Messages to be a root collection and inside message add field channelID
              – OuSS
              Nov 9 at 14:48




              Ok so i think the best solution it to move Messages to be a root collection and inside message add field channelID
              – OuSS
              Nov 9 at 14:48












              Yes, that would be a solution.
              – Renaud Tarnec
              Nov 9 at 14:54




              Yes, that would be a solution.
              – Renaud Tarnec
              Nov 9 at 14:54










              up vote
              0
              down vote













              As Doug pointed out in his correct answer, you cannot have a single listener receive updates from an unknown (number of or unspecified) subcollection.



              However, if you can determine those subcollection names, then the answer is pretty straightforward.



              The idea is to read the child nodes of Channels, which will be channel_0, channel_1 etc and use those document id's to build references to the nodes you are interested in listening to.



              So given this struture (which matches the structure in the question):



              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"


              Here's the code that adds listeners to each channel, and responds to events within that channels messages notifying in console the message id, msg text and the channel the event occurred in.



              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)")
              }
              }
              }
              }
              })
              }


              When first run the output will show, as expected, each child node. From then on it will output any addititions, modifications or deletions.



               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


              the code needs some additional error checking as well for some of the optionals but it should provide a solution.






              share|improve this answer

























                up vote
                0
                down vote













                As Doug pointed out in his correct answer, you cannot have a single listener receive updates from an unknown (number of or unspecified) subcollection.



                However, if you can determine those subcollection names, then the answer is pretty straightforward.



                The idea is to read the child nodes of Channels, which will be channel_0, channel_1 etc and use those document id's to build references to the nodes you are interested in listening to.



                So given this struture (which matches the structure in the question):



                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"


                Here's the code that adds listeners to each channel, and responds to events within that channels messages notifying in console the message id, msg text and the channel the event occurred in.



                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)")
                }
                }
                }
                }
                })
                }


                When first run the output will show, as expected, each child node. From then on it will output any addititions, modifications or deletions.



                 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


                the code needs some additional error checking as well for some of the optionals but it should provide a solution.






                share|improve this answer























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  As Doug pointed out in his correct answer, you cannot have a single listener receive updates from an unknown (number of or unspecified) subcollection.



                  However, if you can determine those subcollection names, then the answer is pretty straightforward.



                  The idea is to read the child nodes of Channels, which will be channel_0, channel_1 etc and use those document id's to build references to the nodes you are interested in listening to.



                  So given this struture (which matches the structure in the question):



                  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"


                  Here's the code that adds listeners to each channel, and responds to events within that channels messages notifying in console the message id, msg text and the channel the event occurred in.



                  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)")
                  }
                  }
                  }
                  }
                  })
                  }


                  When first run the output will show, as expected, each child node. From then on it will output any addititions, modifications or deletions.



                   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


                  the code needs some additional error checking as well for some of the optionals but it should provide a solution.






                  share|improve this answer












                  As Doug pointed out in his correct answer, you cannot have a single listener receive updates from an unknown (number of or unspecified) subcollection.



                  However, if you can determine those subcollection names, then the answer is pretty straightforward.



                  The idea is to read the child nodes of Channels, which will be channel_0, channel_1 etc and use those document id's to build references to the nodes you are interested in listening to.



                  So given this struture (which matches the structure in the question):



                  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"


                  Here's the code that adds listeners to each channel, and responds to events within that channels messages notifying in console the message id, msg text and the channel the event occurred in.



                  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)")
                  }
                  }
                  }
                  }
                  })
                  }


                  When first run the output will show, as expected, each child node. From then on it will output any addititions, modifications or deletions.



                   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


                  the code needs some additional error checking as well for some of the optionals but it should provide a solution.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 11 at 15:39









                  Jay

                  18k42848




                  18k42848






























                       

                      draft saved


                      draft discarded



















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53227376%2ffirestore-listener-for-sub-collections%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Full-time equivalent

                      さくらももこ

                      13 indicted, 8 arrested in Calif. drug cartel investigation