簡體   English   中英

SwiftUI 和 Firestore - 啟動時從不同 collections 讀取多個文檔的邏輯

[英]SwiftUI and Firestore - logic for reading multiple documents from different collections at startup

我在我的 SwiftUI 應用程序項目中使用 Firebase Firestore。 在應用程序啟動時,我想從各種 collections 讀取多個文檔。

假設我有集合 A(1 個文檔)、B(2 個文檔)和 C(4 個文檔)。 A 和 B 的文檔中的數據決定了我必須閱讀 C 中的哪些文檔。

目前,我有一個 DatabaseHelper class,每個集合都有一個 readCollection function(這些 readCollection 函數中的每一個都調用 readDocument 函數來為每個必需的文檔創建一個偵聽器)。 每個 readCollection function 以及每個 readDocument function 都有一個完成處理程序。 在應用程序啟動時,我從閱讀集合 A 開始。閱讀完成后,它會開始閱讀 B,依此類推:

func listen(completion: @escaping () -> ()) {
  readA() {
    readB() {
      readC() {
        completion()
      }
    }
  }
}

在顯示任何數據之前,我的應用正在等待 listen function 完成。

這種方法“有點工作”,但是,它似乎不是最佳方法。 例如,如果我讀取 A,然后我從 B 讀取兩個文檔,B 的完成處理程序被調用兩次,這導致兩次調用 readC(),除非我計算 B 的文檔讀取並且只在上次閱讀。 那么,問題是,只有更新 B 中的第二個文檔才會觸發完成處理程序並從 C 重新加載文檔,但不會更新 B 中的第一個文檔。

當然,必須有一個更好的邏輯來在我的應用程序啟動時從數據庫加載我的數據,它在運行時正確處理每個文檔更新並且沒有不必要的重復讀取。

有沒有人有更好的方法? 謝謝

所以這是一個可能的解決方案。 您必須根據需要修改它,但由於您幾乎沒有為您的問題提供任何代碼,所以它必須這樣做。

  1. 從 A 獲取數據
  2. 當該數據到達時,使用它來確定要從 B 獲取哪些數據。為此使用完成處理程序。 其他解決方案可以但不限於(Dispatcher 等)。
  3. 用B提供的數據確定從C得到什么數據。和Nr.2一樣的過程等待它。

這只是您問題的潛在過程的基本表示。 它過於簡單化,但應該可以幫助您理解:

class DatabaseHelper: ObservableObject {
    
    @Published var myDataA: Array<String> = []
    @Published var myDataB: Array<String> = []
    @Published var myDataC: Array<String> = []
    
    init() {
        self.getData(dataBaseACollectionName: "dataBase_A")
    }
    
    // Get A Data
    private func getData(dataBaseACollectionName: String) {
        self.dataBaseCollectionGetDocuments(collectionName: dataBaseACollectionName) { isSucceededA in
            if !isSucceededA.isEmpty {
                self.myDataA = isSucceededA
                
                // Get first "documentID from A to determine what in B I have to read
                self.getSpecificDocumentFromDataBase(collectionName: self.myDataA.first ?? "randomCollection", documentID: self.myDataA.first ?? "randomDocument") { isSucceededB in
                    if !isSucceededB.isEmpty {
                        self.myDataB = isSucceededB
                        
                        // Get first "documentID from B to determine what in C I have to read
                        self.getSpecificDocumentFromDataBase(collectionName: self.myDataB.first ?? "randomCollection", documentID: self.myDataB.first ?? "randomDocument") { isSucceededC in
                            if !isSucceededC.isEmpty {
                                self.myDataC = isSucceededC
                                // done
                            }
                        } // C
                        
                    }
                } // B
                
            } // A
        }
    }
    
    // I made just one wrapper function for the DB call as all myData Arrays are from the same type (containing Strings)
    private func dataBaseCollectionGetDocuments(collectionName: String ,completing: @escaping (Array<String>) -> Void) {
        
        if !collectionName.isEmpty {
            var dataArray: Array<String> = []
            let group = DispatchGroup()
            group.enter() // initial enter
            
            Firestore.firestore().collection(collectionName).getDocuments() { (documents, error) in
                if error != nil {
                    print("Error getting amount of recipes in last seen")
                } else {
                    for doc in documents!.documents {
                        group.enter()
                        dataArray.append(doc.documentID) // Just appending ID as it is a String
                        group.leave()
                    }
                }
                group.leave() // Initial leave
            }
            
            group.notify(queue: DispatchQueue.global(qos: .background)) {
                completing(dataArray)
            }
        }
        
    }
    
    // For Specific documents
    private func getSpecificDocumentFromDataBase(collectionName: String, documentID: String ,completing: @escaping (Array<String>) -> Void) {
        
        if !collectionName.isEmpty && !documentID.isEmpty {
            var dataArray: Array<String> = []
            let group = DispatchGroup()
            group.enter() // initial enter
            
            let docRef = Firestore.firestore().collection(collectionName).document(documentID)
            docRef.getDocument() { (document, error) in
                group.enter()
                if error != nil {
                    print("Error getting amount of recipes in last seen")
                } else {
                    dataArray.append(document!.documentID) // Just appending ID as it is a String
                    group.leave()
                }
                group.leave() // Initial leave
            }
            
            group.notify(queue: DispatchQueue.global(qos: .background)) {
                completing(dataArray)
            }
        }
        
    }
    
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM