[英]SwiftUI and Firestore - logic for reading multiple documents from different collections at startup
I'm using Firebase Firestore in my SwiftUI app project.我在我的 SwiftUI 应用程序项目中使用 Firebase Firestore。 At the start of the app, I want to read multiple documents from various collections.在应用程序启动时,我想从各种 collections 读取多个文档。
Let's say I have collection A (1 document), B (2 documents) and C (4 documents).假设我有集合 A(1 个文档)、B(2 个文档)和 C(4 个文档)。 The data in the documents from A and B determine which documents from C I have to read. A 和 B 的文档中的数据决定了我必须阅读 C 中的哪些文档。
Currently, I have a DatabaseHelper class which has a readCollection function for each collection (each of these readCollection functions call readDocument functions to create a listener for each required document).目前,我有一个 DatabaseHelper class,每个集合都有一个 readCollection function(这些 readCollection 函数中的每一个都调用 readDocument 函数来为每个必需的文档创建一个侦听器)。 Each readCollection function as well as each readDocument function has a completion handler.每个 readCollection function 以及每个 readDocument function 都有一个完成处理程序。 At the start of the app, I start with reading collection A. After completing the read, it then starts reading B, and so on:在应用程序启动时,我从阅读集合 A 开始。阅读完成后,它会开始阅读 B,依此类推:
func listen(completion: @escaping () -> ()) {
readA() {
readB() {
readC() {
completion()
}
}
}
}
My app is waiting for the listen function to complete before displaying any data.在显示任何数据之前,我的应用正在等待 listen function 完成。
This approach is 'kind of working', HOWEVER, it does not seem to be the optimal approach.这种方法“有点工作”,但是,它似乎不是最佳方法。 For example, if I read A, then I read both documents from B, the completion handler from B is called twice, which results in two calls for readC(), unless I count the document reads for B and only call the completion after the last read.例如,如果我读取 A,然后我从 B 读取两个文档,B 的完成处理程序被调用两次,这导致两次调用 readC(),除非我计算 B 的文档读取并且只在上次阅读。 THEN, the problem is, that only an update to the second document in B triggers the completion handler and reloads documents from C, but not an update to the first document in B.那么,问题是,只有更新 B 中的第二个文档才会触发完成处理程序并从 C 重新加载文档,但不会更新 B 中的第一个文档。
Surely, there has to be a better logic to load my data from the database at the start of my app, which handles each document update during runtime correctly and without unneccessary double-reads.当然,必须有一个更好的逻辑来在我的应用程序启动时从数据库加载我的数据,它在运行时正确处理每个文档更新并且没有不必要的重复读取。
Does anyone have a better approach?有没有人有更好的方法? Thanks谢谢
So here is a possible solution.所以这是一个可能的解决方案。 You'll have to modify it to your needs but as you provided little to no code for your issue it has to do.您必须根据需要修改它,但由于您几乎没有为您的问题提供任何代码,所以它必须这样做。
This is just a basic representation of a potential procedure of your problem.这只是您问题的潜在过程的基本表示。 It is oversimplified but should help you understand:它过于简单化,但应该可以帮助您理解:
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.