'Listen for documents just when actually added to collection - swift
I have a collection on Firestore and I listen for changes like this:
func createMatchesListener(){
let db = Firestore.firestore()
guard let currentUid = Auth.auth().currentUser?.uid else { return }
matchesListener = db.collection("Matches").document(currentUid).collection("Matches").addSnapshotListener({ snapshot, error in
if let error = error{
print(error.localizedDescription)
return
}
snapshot?.documentChanges.forEach({ change in
if change.type == .added{
// do things
}
})
})
}
I only want to listen for documents that are actually added to that collection. In fact, the problem is that whenever I invoke this function I receive all the documents of the collection as added documents and then I also receive documents added later.
How can I listen just for actually added later documents, ignoring the ones already present in the collection? Searching online I didn't find any solution to this issue.
EDIT: This is the way I tried to solve the problem:
func createMatchesListener(){
guard let currentUid = Auth.auth().currentUser?.uid else { return }
getUidsAlreadyMade { uidsAlreadyMade in
matchesListener = db.collection("Matches").document(currentUid).collection("Matches").addSnapshotListener({ snapshot, error in
if let error = error{
print(error.localizedDescription)
return
}
snapshot?.documentChanges.forEach({ change in
if change.type == .added{
let data = change.document.data()
let userId = data["uid"] as? String ?? ""
if uidsAlreadyMade.contains(userId) == false{
//means the uid is newly created in the collection, do stuff accordingly
arrayOfUidsAlreadyMade.append(currentUid)
}
}
if change.type == .removed{
// if the document has been removed, remove also the id from the array of uids
let data = change.document.data()
let currentUid = data["uid"] as? String ?? ""
arrayOfUidsAlreadyMade.removeAll { $0 == currentUid }
}
})
})
}
}
func getUidsAlreadyMade(completion: @escaping ([String]) -> Void){
guard let currentUid = Auth.auth().currentUser?.uid else { return }
db.collection("Matches").document(currentUid).collection("Matches").getDocuments { snapshot, error in
if let error = error{
print(error.localizedDescription)
return
}
arrayOfUidsAlreadyMade.removeAll()
snapshot?.documents.forEach({ doc in
let dict = doc.data()
let userId = dict["uid"] as? String ?? ""
arrayOfUidsAlreadyMade.append(userId)
})
completion(arrayOfUidsAlreadyMade)
}
}
Solution 1:[1]
You can store an array with the ID of the documents that you already have stored in the device. That way, all that you need to do before doing things is checking that document's id is not in your array
Solution 2:[2]
There's no way of preventing Firestore from returning the initial snapshot of documents when a document listener is added, so just use a boolean to keep track of the initial snapshot and ignore it.
var listenerDidInit = false
func createMatchesListener(){
let db = Firestore.firestore()
guard let currentUid = Auth.auth().currentUser?.uid else { return }
matchesListener = db.collection("Matches").document(currentUid).collection("Matches").addSnapshotListener({ snapshot, error in
if let error = error{
print(error.localizedDescription)
return
}
if listenerDidInit {
snapshot?.documentChanges.forEach({ change in
if change.type == .added{
// do things
}
})
} else {
listenerDidInit = true
}
})
}
Solution 3:[3]
A simple solution is to include a timestamp in your Firestore documents.
Suppose your documents store Tasks, for example
documentId
task: "get dinner"
timestamp: 20211123
and suppose your app doesn't care about past tasks, only new ones.
When the tasks are read, update the timestamp as to when that occurred.
Then each time after that you want to read only 'new data' specify that in your listener, keeping track of when the last read timestamp was:
db.collection("task").whereField("timestamp", isGreaterThan: lastReadTimeStamp).addSnapshotListener...
The above will only read in tasks that occured after the prior timestamp and add a Listener (reading in all of the new tasks so you can populate the UI).
Solution 4:[4]
private var listener: ListenerRegistration?
self.listener = db.collection("Matches") // matchesListener
listener!.remove()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Pastre |
Solution 2 | fake girlfriends |
Solution 3 | Jay |
Solution 4 | Henry Ecker |