I am currently dealing with pagination with addSnapshotListener in Firebase's firestore and it appears there's no easy way to implement Snapshot with pagination.
Original premise: I started the implementation with addSnapshotListener as follows:
db.collectionGroup("images")
.order(by: "createdTime")
.whereField("featured", isEqualTo: true)
.addSnapshotListener { querySnapshot, _ in
if let querySnapshot = querySnapshot {
vm.featuredImages = querySnapshot.documents.compactMap { document in
do {
let image = try document.data(as: ImageModel.self)
print("DEBUG FEATURED IMAGE: \(String(describing: image))")
return image
} catch {
print("DEBUG FEATURED IMAGE ERROR \(String(describing: error))")
}
return nil
}
}
}
And all goes well. The data is fetched into the ViewModel and any new changes are automatically notified via Firestore’s library and the local model gets updated.
Now add pagination: I’ve read the official documentation as well as all the stackoverflow threads. It appears there is no easy to maintain a addSnapshotListener with a new page.
(A) One naive approach when a new page is requested would be to
- Keep track of the old listener, and then unregisters the old one
- Register a new snapshotListener now with a new page (10 -> 20 elements)
- Repopulate the local model
This seems to work ok on the surface however with the one big problem is that you would be re-fetching the first 10 when you request for page 2. And the fetches become exponential as you add pages!
(B) Another solution mentioned in Firebase’s official youtube is
- Keep the old listener, but keep adding a new listener per new page
- On first fetch, it’s easy, you would just dump the new data into the old local model
- But when things update, it’s a lot of manual work. You would have to either diff the new data vs the old local model or somehow find a way to coordinate all the listeners and merging them into a new modal .
I imagine querySnapshot is the standard way of keep data in sync with apps. I imagine every app is going to need pagination. What is the correct solution?