【问题标题】:Swift Loading data from Firebase Collection and Subcollection Loop从 Firebase 集合和子集合循环中快速加载数据
【发布时间】:2021-01-21 23:05:18
【问题描述】:

这是我的 TableRepository.swift 文件的快照。注释掉“//”的部分是我真正遇到困难的地方。任何具有挖掘嵌套循环以查询子集合的经验的人。

理想情况下,尝试将数据存储在还具有列表子集合的表数组中。

现在我可以让它连接并返回“x”作为父集合。但似乎无法加载子集合。干杯看看这个。

import Foundation
import FirebaseFirestore
import FirebaseFirestoreSwift

// MODEL
struct Table: Codable, Identifiable {
    @DocumentID var id: String? = UUID().uuidString
    var title: String
    var sequencing: String
}

struct Row: Codable, Identifiable {
    @DocumentID var id: String?
    var rangeBegin: Int
    var rangeEnd: Int
    var rowContent: String
}

struct TableBuild {
    var table: Table
    var rows: [Row]
}

// TABLE REPOSITORY LOAD
class TableRepository: ObservableObject {
    let db = Firestore.firestore()
    
    @Published var tables = [Table]()
    @Published var rows = [Row]()
    
    init() {
        loadData()
    }

    func loadData() {
        db.collection("tablesTest").addSnapshotListener { (querySnapshot, error) in
            if let querySnapshot = querySnapshot {
                self.tables = querySnapshot.documents.compactMap { document in
                    do {
                        if let x = try document.data(as: Table.self) {
                            print("--- TABLE ---")
                            print(x)
                            
//                            self.db.collection("tablesTest").document(x.id!).collection("rows").addSnapshotListener { (queryRowSnapshot, error) in
//                                if let queryRowSnapshot = queryRowSnapshot {
//                                    self.rows = queryRowSnapshot.documents.compactMap { document in
//                                        do {
//                                            let y = try document.data(as: Row.self)
//                                        }
//                                        catch {
//                                            print(error)
//                                        }
//                                        return nil
//                                    }
//                                }
//                            }
//                            var tabild = [TableBuild]()
//                            tabild.append(TableBuild(table: x, rows: y))
//                            return tabild
                            
                            return x
                        }
                        
                    }
                    catch {
                        print(error)
                    }
                    return nil
                }
            }
        }
    }
}

编辑/添加:

目标类似于存储/更新数据,与 Peter Friese 的 https://github.com/peterfriese/MakeItSo/blob/master/final/MakeItSo/MakeItSo/Repositories/TaskRepository.swift 非常相似——但是,需要将数据存储到类似结构的对象中增加了复杂性,即 1) 具有自己的值的表(标题、meta 等)和 2)一系列行,每一行都有自己的值(内容、序列等)——很可能跨设备实时同步数据。

理想情况下,数据将存储在本地/以这种方式应用...

[Table 1]
- table title
- table other
- - [Row 1]
- - - row 1 content
- - - row 1 other
- - [Row 2]
- - - row 2 content
- - - row 2 other
- - [Row ...]
[Table 2]
- ...

这是我的快照

【问题讨论】:

  • 这个函数db.collection("tablesTest"). 加载该集合中的所有文档。为什么在它们已经加载时再次加载它们self.db.collection("tablesTest")?例如第一次加载它们时,您已经获得了 querySnapshot 中的所有文档。您能否更清楚地描述您在这些文档中需要哪些数据?此外,包括您的 Firestore 结构的图像也可以帮助我们理解问题。另外,请注意 var tabild = [TableBuild]() 将在前面的闭包中的代码之前执行,因此 y 可能为零
  • @Jay 感谢您的回复。我的理解是子集合必须与它们的父级完全分开处理,因此是额外的。我在这里添加了更多细节和 Firebase 设置的屏幕截图。
  • 我代表您添加了图像。链接会随着时间的推移而中断,如果发生这种情况,我们将不知道结构是什么样的。此外,获得同一页面的好主意:Firestore 没有行、列或表。有集合、文档和字段,它们的行为和结构不同。您的数据在 Firestore 中的存储方式取决于您对其运行的查询。您能否根据问题中的图像清楚地说明您希望在您的 tablesTest 集合中获得哪些数据?例如我想遍历tablesTest中的每个文档并打印标题
  • @Jay 可以理解,这里可能存在一些混淆......这个应用程序在这些表中使用“表”和“行”。我知道 FS 使用的格式为... collections.documents.subcollection.documents... 最终,这就是我试图弄清楚的最佳方式,即如何最好地循环并将这些子集合文档取出并放入表变量中。该表将存在于一组表中。
  • 明白。请澄清您要获取的数据 - 这是困难的部分。在代码中获取这些数据并对其进行按摩是很容易的部分。

标签: swift firebase google-cloud-firestore swiftui


【解决方案1】:

您似乎正试图从父集合返回文档中的整个子集合。如果是这样,您将不需要使用addSnapshotListener,因为这只会获取一个文档,而是getDocuments()。您的查询需要更改为类似于以下内容的内容。

db.collection("tablesTest").document(x.id!).collection("rows").getDocuments() { (querySnapshot, err) in
    if let err = err {
        print("Error getting documents: \(err)")
    } else {
        for document in querySnapshot!.documents {
            print("\(document.documentID) => \(document.data())")
        }
    }
}

虽然此代码未经测试,但我相信这对您来说是一个很好的起点,因为它展示了如何从集合中获取所有文档,基于官方文章 here。之后,您只需将其调整为您的代码,以便它按照您的意愿显示在表格中。您还可以通过查看官方教程here 获取有关如何在 Firestore 上使用子集合的更多信息。

【讨论】:

  • 谢谢@gso_gabriel,这已经很有帮助了。会试一试的。
【解决方案2】:

根据 cmets,OP 希望在 tablesTest 中获取每个文档并访问 sequencingtitle 字段。此外,他们希望访问每个文档的 rows 子集合,以获取其 rowContent 属性。

这是执行此操作的代码

func readTables() {
    let tablesCollection = self.db.collection("tablesTest")
    tablesCollection.getDocuments(completion: { snapshot, error in
        if let err = error {
            print(err.localizedDescription)
            return
        }
        
        guard let docs = snapshot?.documents else { return }
        
        for doc in docs {
            let seq = doc.get("sequencing") as? String ?? "No sequence"
            let title = doc.get("title") as? String ?? "No title"
            //print(seq, title) dont put this here
            tablesCollection.document(doc.documentID).collection("rows").getDocuments(completion: { rowSnap, error in
                if let err = error {
                    print(err.localizedDescription)
                    return
                }
                
                guard let rowDocs = rowSnap?.documents else { return }
                print(seq, title)
                for row in rowDocs {
                    let rowId = row.documentID
                    let content = row.get("rowContent") as? String ?? "No row content"
                    print("  ",rowId, content)
                }
            })
            
        }
    })
}

...以及两个表的输出。第一个表的 rows 子集合中有两行,第二个表的 rows 集合中有一行。

no sequence big table
   row_0 some content
   row_1 more content
sequential Another Table
   row_0 some content

需要注意的一点:Firestore 是异步的,因此打印是在内部 Firestore 闭包内完成的,以确保在返回数据时变量“保持在一起”。否则,如果 print(seq, title) 移出该闭包,则打印顺序将关闭,具体取决于从服务器返回数据的速度。

【讨论】:

    猜你喜欢
    • 2016-10-12
    • 2019-03-27
    • 1970-01-01
    • 2010-11-24
    • 2020-02-14
    • 2019-05-28
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    相关资源
    最近更新 更多