1
votes

I am using firestore along with iglistkit to display data on collection view. I am trying to understand why my snapshot listener gets called twice with the same object.

issue summary: On Viewdidload I call the fetchUserFriends() method and receive the documents that I am expecting from the querySnapshot but for some unknown reason, method body gets called twice, without any changes being made to the data.

The problematic code is in below:

 func fetchUserFriends() {
        guard let currentUserId = currentUser?.uid else { return }
        db.collection("friends").whereField(FriendState.isRelationshipActive, isEqualTo: true).whereField("members", arrayContains: currentUserId).order(by: "createdAt", descending: true).addSnapshotListener { [weak self] (querySnapshot, error) in

            if(error != nil) {
                print("error \(String(describing: error?.localizedDescription))")
            }

            guard let querySnapshot =  querySnapshot else { return }

            for document in querySnapshot.documents {
                let friendRelation = UserRelation.init(document: document)
                if(self?.friendsRelations != nil) {
                    self?.friendsRelations?.append(friendRelation)
                } else {
                    self?.friendsRelations = [friendRelation]
                }
            }
            self?.adapter.reloadData(completion: nil)
        }
    }

Based on my debugging, what happens is that:

  1. fetchUserFriends() gets called
  2. goes through guard let querySnapshot = querySnapshot else { return } and adds the data to friendRelations array
  3. self?.adapter.reloadData(completion: nil)
  4. then the line below runs Then this code runs

  5. and goes back to the 2nd step again with the same object which in this case fails due to iglistkit duplicate identifier.

Thanks for the help.

1
The question is a bit unclear - we need to understand the FireStore structure. Can you include that in the question? Also, you're adding a listener to every node being read. I would guess you may want to use getDocuments instead. Note that your .orderBy isn't going to work as is. .order(by requires one of the where clauses to contain the same field as your ordering by. You are probably better off (in this case) removing the .order(by and sorting in code or explore composite indexing as well.Jay

1 Answers

0
votes

I'm running in the same issue here. Strangely enough I have different listeners, one for each document. One triggers once. The other one twice. I've found a way to stop it from triggering twice.

 if !snapshot.metadata.hasPendingWrites { // filters the local snapshot
    let myobj = Myobj(document: snapshot)
    completion(myobj)
 }

The explanation is that it is tracking the local and the server-side changes and this will filter to get the server-side confirmation only. Now, the reason why this is triggering the local snapshot for ONLY ONE of the equally setup listeners remains a mystery to me. Hope it can help someone.