简体   繁体   中英

Do two Firestore listeners that overlap bill for the same document update?

I have two listeners both observing the same collection 'Tasks'.

  • One query retrieves tasks that are incomplete (completed == false)
  • The other query retrieves complete tasks within the last 24 hours (completed == true && completionDate > (Date - 24 hours))

Due to this logic the two listeners happen to overlap each other. If I update a task to complete. Both snapshot listeners will run. This is the same document however.

Q: Would I get charged TWICE for just updating one document? or will the listeners know that the same document has been updated once and will only be billed once?

class TaskData: ObservableObject {
    @Published var tasks: [Task] = []
    @Published var incompleteTasks: [Task] = []
    @Published var completedTasks: [Task] = []
    
    private var db = Firestore.firestore()
    private var incompleteTaskslistenerRegistration: ListenerRegistration?
    private var completedTasksListenerRegistration: ListenerRegistration?
    
    init() {
        subscribe()
        
        Publishers
            .CombineLatest($completedTasks, $incompleteTasks)
            .dropFirst()
            .map { $0 + $1 }
            .assign(to: &$tasks)
    }
    
    deinit {
        unsubscribe()
    }
    
    func subscribe() {
        guard let userId = Auth.auth().currentUser?.uid else { return }
                
        if incompleteTaskslistenerRegistration != nil || completedTasksListenerRegistration != nil {
            unsubscribe()
        }
        
        let completedTasksQuery = db.collection("tasks")
            .whereField("userId", isEqualTo: userId)
            .whereField("completed", isEqualTo: true)
            .whereField("completedDate", isGreaterThan: Date().advanced(by: -86400))
        
        completedTasksListenerRegistration = completedTasksQuery.addSnapshotListener { querySnapshot, error in
            guard let documents = querySnapshot?.documents else {
                print("No documents in 'tasks' collection")
                return
            }
            self.completedTasks = documents.compactMap { queryDocumentSnapshot in
                try? queryDocumentSnapshot.data(as: Task.self)
            }
        }
        
        let incompleteTasksQuery = db.collection("tasks")
            .whereField("userId", isEqualTo: userId)
            .whereField("completed", isEqualTo: false)
        
        incompleteTaskslistenerRegistration = incompleteTasksQuery.addSnapshotListener { querySnapshot, error in
            guard let documents = querySnapshot?.documents else {
                print("No documents in 'tasks' collection")
                return
            }
            self.incompleteTasks = documents.compactMap { queryDocumentSnapshot in
                try? queryDocumentSnapshot.data(as: Task.self)
            }
        }
    }
    
    func unsubscribe() {
        if incompleteTaskslistenerRegistration != nil {
            incompleteTaskslistenerRegistration?.remove()
            incompleteTaskslistenerRegistration = nil
        }
        if completedTasksListenerRegistration != nil {
            completedTasksListenerRegistration?.remove()
            completedTasksListenerRegistration = nil
        }
    }
}

Edit 1

I just want to clarify that the reason I have the query for retrieving completed tasks for the past 24 hours is so that users are able to uncheck or make changes in that period. It will then be no longer fetched. I don't want add a listener that fetches all the tasks ever made as that would start costing a lot and I don't want to implement pagination as I lose that real-time updating and pagination for listeners is rather strenuous.

Cloud Firestore charges you for the number of documents you read, write and delete , so you are charged for a read each time a document in the result is updated.

Since you have two active listeners that run the same document, the first listener will need to get or check the data from the server (document) while the second listener can read it from cache.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM