0

I am trying to avoid unnecessary reads on my FireStore database by filtering my SnapshotListener with lastDatesCheck: A date value which I update and store inside my app (UserDefaults) each time when I successfully fired the query.

In my FireStore-documents I have a lastModified field which I compare lastDatesCheck with.

I am trying to get unchanged data from cache and only changes from server.

Do I have to use Swifts CoreData to save my old datesArray, or can I get the cache plus the updates out of the same FireStore-Snapshot?

This is my code which produces an empty datesArray from 2nd app-start on, because the listener doesn't find anything anymore fitting to the lastDatesCheck-filter. This makes sense, but how do I fill my datesArray from cache now?

@AppStorage("lastDatesCheck") var lastDatesCheck: Date = Date(timeIntervalSinceNow: -365 * 24 * 60 * 60)
@Published var datesArray: [DateModel] = []

struct DateModel: Identifiable, Hashable {    
   var id: Int
   var documentId: String
   var startDate: Date
   var endDate: Date?
   var title: String
   var homepage: String?
}

func listen(completion: @escaping () -> Void) {
    
    let db = Firestore.firestore()
    
    listenerDates = db.collection("dates")
        .whereField("lastModified", isGreaterThanOrEqualTo: lastDatesCheck)
        .addSnapshotListener { (snapshot, error) in
            
            guard let snapshot = snapshot else {
                print(error!.localizedDescription)
                DispatchQueue.main.async {
                    completion()
                    return
                }
                return
            }
            
            snapshot.documentChanges.forEach { diff in
                if (diff.type == .added) {
                    print("New Data: \(diff.document.data())")
                }
                if (diff.type == .modified) {
                    print("Modified Data: \(diff.document.data())")
                }
                if (diff.type == .removed) {
                    print("Removed Data: \(diff.document.data())")
                }
            }
            
            let source = snapshot.metadata.isFromCache ? "local cache" : "server"
            print("Metadata: Data fetched from \(source)")
            
            self.datesArray.removeAll()
            
            for document in snapshot.documents {
                if let title = document.get("title") as? String {
                    if let startDate = document.get("startDate") as? Timestamp {
                        let startDatefromDb = startDate.dateValue()
                        let endDate: Timestamp? = document.get("endDate") as? Timestamp ?? nil
                        let homepage: String? = document.get("homepage") as? String ?? nil
                        let endDatefromDb: Date? = endDate?.dateValue()
                        let currentIndex = self.datesArray.last?.id
                        
                        let newDate = DateModel(id: (currentIndex ?? -1)+1, documentId: document.documentID, startDate: startDatefromDb, endDate: endDatefromDb, title: title, homepage: homepage)
                        
                        self.datesArray.append(newDate)
                    }
                }
            }
            DispatchQueue.main.async {
                self.lastDatesCheck = Date()
                completion()
                return
            }
        }
}
Kuhlemann
  • 3,066
  • 3
  • 14
  • 41
  • As per this [post](https://stackoverflow.com/a/47160462/8791788), it seems like you can cache and update in the same snaphot. Also please check this [post](https://stackoverflow.com/a/47225851/8791788) which might help you. – Nibrass H Mar 17 '21 at 20:21
  • Technically this works if I don‘t use the ’whereField‘ parameter. But the listener will then have to read the whole collection to find updates which produces a lot of reads which I try to avoid. https://stackoverflow.com/questions/61780840/understanding-firebase-snapshot-listener-pricing-in-android – Kuhlemann Mar 17 '21 at 21:51

0 Answers0