[英]What is the most efficient way to get all documents from multiple sub-collections of multiple sub-collections in Firestore?
[英]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 中的第一个文档。
当然,必须有一个更好的逻辑来在我的应用程序启动时从数据库加载我的数据,它在运行时正确处理每个文档更新并且没有不必要的重复读取。
有没有人有更好的方法? 谢谢
所以这是一个可能的解决方案。 您必须根据需要修改它,但由于您几乎没有为您的问题提供任何代码,所以它必须这样做。
这只是您问题的潜在过程的基本表示。 它过于简单化,但应该可以帮助您理解:
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.