Firebase SwiftUI和Firestore—用于在启动时从不同集合读取多个文档的逻辑
我正在我的SwiftUI应用程序项目中使用Firebase Firestore。在应用程序开始时,我想从各种集合中读取多个文档 假设我有集合A(1个文档)、B(2个文档)和C(4个文档)。来自A和B的文档中的数据决定了我必须读取来自C的哪些文档 目前,我有一个DatabaseHelper类,它对每个集合都有一个readCollection函数(每个readCollection函数调用readDocument函数为每个所需的文档创建一个侦听器)。每个readCollection函数以及每个readDocument函数都有一个完成处理程序。在应用程序开始时,我从读取集合A开始。完成读取后,它开始读取集合B,依此类推:Firebase SwiftUI和Firestore—用于在启动时从不同集合读取多个文档的逻辑,firebase,google-cloud-firestore,swiftui,logic,read-data,Firebase,Google Cloud Firestore,Swiftui,Logic,Read Data,我正在我的SwiftUI应用程序项目中使用Firebase Firestore。在应用程序开始时,我想从各种集合中读取多个文档 假设我有集合A(1个文档)、B(2个文档)和C(4个文档)。来自A和B的文档中的数据决定了我必须读取来自C的哪些文档 目前,我有一个DatabaseHelper类,它对每个集合都有一个readCollection函数(每个readCollection函数调用readDocument函数为每个所需的文档创建一个侦听器)。每个readCollection函数以及每个read
func listen(completion: @escaping () -> ()) {
readA() {
readB() {
readC() {
completion()
}
}
}
}
我的应用程序正在等待侦听功能完成,然后再显示任何数据
这种方法是“可行的”,但是,它似乎不是最佳方法。例如,如果我读取了A,然后从B读取了两个文档,则会调用B中的完成处理程序两次,这会导致对readC()的两次调用,除非我计算文档读取次数并仅在最后一次读取之后调用完成处理程序。然后,问题是,只有对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)
}
}
}
}
类数据库助手:ObserveObject{
@已发布的变量myDataA:Array=[]
@已发布的var myDataB:Array=[]
@已发布的变量myDataC:Array=[]
init(){
getData(dataBaseACollectionName:“dataBase_A”)
}
//获取数据
private func getData(数据库集合名称:字符串){
self.dataBaseCollectionGetDocuments(collectionName:dataBaseACollectionName){issucceedada in
如果!isSucceededA.isEmpty{
self.myDataA=issucceedada
//从A获取第一个“documentID”,以确定我必须阅读B中的内容
self.getSpecificDocumentFromDataBase(collectionName:self.myDataA.first??“randomCollection”,documentID:self.myDataA.first??“randomDocument”){IssucceedDB in
如果!IssucceedDB.isEmpty{
self.myDataB=issucceeddb
//从B获取第一个“documentID”,以确定我必须阅读C中的内容
self.getSpecificDocumentFromDataBase(collectionName:self.myDataB.first??“randomCollection”,documentID:self.myDataB.first??“randomDocument”){IssucceedDC in
如果!IssucceedDC.isEmpty{
self.myDataC=issucceeddc
//完成
}
}//C
}
}//B
}//A
}
}
//我只为DB调用创建了一个包装函数,因为所有myData数组都来自同一类型(包含字符串)
private func dataBaseCollectionGetDocuments(collectionName:String,完成:@escaping(数组)->Void){
if!collectionName.isEmpty{
var dataArray:Array=[]
let group=DispatchGroup()
group.enter()//初始输入
中的Firestore.Firestore().collection(collectionName).getDocuments(){(文档,错误)
如果错误!=nil{
打印(“获取上次查看的配方数量时出错”)
}否则{
用于文档中的文档。文档{
group.enter()
dataArray.append(doc.documentID)//只需追加ID,因为它是一个字符串
小组请假()
}
}
group.leave()//首次休假
}
通知组(队列:DispatchQueue.global(qos:.后台)){
完成(数据阵列)
}
}
}
//具体文件
private func getSpecificDocumentFromDataBase(collectionName:String,documentID:String,completing:@escaping(数组)->Void){
if!collectionName.isEmpty&!documentID.isEmpty{
var dataArray:Array=[]
let group=DispatchGroup()
group.enter()//初始输入
让docRef=Firestore.Firestore().collection(collectionName).document(documentID)
docRef.getDocument(){(文档,错误)位于
group.enter()
如果错误!=nil{
打印(“获取上次查看的配方数量时出错”)
}否则{
dataArray.append(document!.documentID)//只需将ID作为字符串追加即可
小组请假()
}
group.leave()//首次休假
}
通知组(队列:DispatchQueue.global(qos:.后台))