Mike
Mike

Reputation: 1331

Why is a firestore listener returning .added twice when a single document is added?

I'm using google maps and my users can add a map marker to the map. The map markers are stored in firestore. I have a listener that listens in to the database. Each user can only submit one map marker - so there is only one document for each user in the database. But they can modify the lat and lng of their marker.

My firestore is set out as:

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

At the moment for debugging I only have one user in firestore and one document under submittedMarkers -> {fireauthId}.

When my app loads the single marker that currently exists is added to the map along with a single print statement "added". So that works.

Here is the problem I've encountered.

When a new user registers and gets a fireauth id they can then go and add a marker from the AddMarkerController. When they submit the marker i use an unwind segue to get them back to the MapController. (I don't detach the listener at any stage from the MapController).

// AddMarkerController

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 {

    }
}

But what I have found is that when they have come back to the MapController the if (diff.type == .added) is executed twice and print("added") happens twice even though the currentuser fireauth id is added just the once under the collection submittedMarkers.

And when I print out the diff.document.ID i'm getting both the fireauth id of the user who was already in firestore and the current user who just added a new document.

I suspect I don't quite get then how the listener works. I thought if(diff = .added) would listen to the submittedMarkers collection and only fire once when a new document is added.

I wasn't sure if the issue is:

  1. I don't detach the listener when I leave the MapController -> AddMarkerController?
  2. The listener is in viewWillAppear and not viewDidLoad but from reading the firebase blog it should be in viewWillAppear
  3. Whether it's the snapshot.documentChanges.forEach which is looping through the entire snapshot each time something changes

Upvotes: 1

Views: 7739

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598847

The first added is the local event that is fired as soon as you call setData(). The second added is the acknowledged event after the server has written the data.

See the events for local changes section in the documentation.

Another reason might be that you fail to unregister your observer. If you register your observer in viewWillAppear, unregister it in viewWillDisappear or viewDidDisappear . If you don't, you'll end up with multiple observers for the same event and thus with multiple invocations.

Upvotes: 4

Related Questions