繁体   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