【问题标题】:Swift: Firestore sub collections, custom objects and listenersSwift:Firestore 子集合、自定义对象和监听器
【发布时间】:2019-02-18 15:55:01
【问题描述】:

我有一个模型模式,如下图所示。

在 UI 中,我试图获取所有 Countries 和相关数据。我已经创建了各自的结构,我的想法是使用链接Custom_Objects 中显示的自定义对象方法。现在我遇到的问题是subcollections 不会出现在querysnapshot 中(我只得到字段),因此我无法进行直接对象映射(因为我必须查询和检索子集合来制作对象完全的)。例如:Country 结构具有States 作为属性之一,并且没有状态Country 无法创建对象,States 进一步具有省份。现在我正在做递归循环来构建我感觉不太好的整个结构。

所以我的问题是,处理此类数据的最佳方法是什么(假设没有标准化空间并且我们无法避免子集合)?

另外,如果我想收到有关州、省或城镇的任何更改的通知,我是否需要分别向每个集合添加侦听器或添加到根目录就足够了?

这是当前的代码快照

    db.collection("countries").getDocuments { (QuerySnapshot, error) in
    if let error = error {
        print("\(error.localizedDescription)")
    }else{
        var docCount = QuerySnapshot!.documents.count
        for document in QuerySnapshot!.documents {
            self.fetchStatesForDoc(document: document, completion: { (nodes) in
                var data = document.data()
                data["states"] = nodes
                let country = Country(dictionary: data)
                self.countryList.append(country!)
                print(self.sectionList)
                docCount = docCount - 1
                if docCount == 0{
                    DispatchQueue.main.async {
                        self.countryCollection.reloadData()
                    }
                }
            })
        }
    }
}
}
func fetchStatesForDoc(document: DocumentSnapshot, completion:@escaping ([State])-> Void){

    var states = [State]()
    document.reference.collection("states").getDocuments(completion: { (QuerySnapshot, error) in
        if let error = error {
            print("\(error.localizedDescription)")
        }else{
            var docCount = QuerySnapshot!.documents.count
            for document in QuerySnapshot!.documents {
                //print("\(document.documentID) => \(document.data())")
                var data = document.data()
                self.fetchProvincesForDoc(document: document, completion: { (provinces) in
                    data["Provinces"] = provinces
                    let state = State(dictionary: data)
                    states.append(state!)
                    docCount = docCount - 1
                    if docCount == 0{
                        completion(state)
                    }
                })
            }
        }
    })
}
func fetchProvincesForDoc(document: DocumentSnapshot, completion:@escaping ([Province])-> Void){

    var provinces = [Province]()
    document.reference.collection("provinces").getDocuments(completion: { (QuerySnapshot, error) in
        if let error = error {
            print("\(error.localizedDescription)")
        }else{
            var docCount = QuerySnapshot!.documents.count
            for document in QuerySnapshot!.documents {
                //print("\(document.documentID) => \(document.data())")
                var data = document.data()
                self.fetchTownsForDoc(document: document, completion: { (towns) in
                    data["towns"] = provinces
                    let province = Province(dictionary: data)
                    provinces.append(province!)
                    docCount = docCount - 1
                    if docCount == 0{
                        completion(province)
                    }
                })
            }
        }
    })
}
func fetchTownssForDoc(document: DocumentSnapshot, completion:@escaping ([Towns])-> Void) {

    var towns = [Towns]()
    document.reference.collection("towns").getDocuments(completion: { (QuerySnapshot, error) in
        if let error = error {
            print("\(error.localizedDescription)")
        }else{
            for document in QuerySnapshot!.documents {
                //print("\(document.documentID) => \(document.data())")
            }
            towns = QuerySnapshot!.documents.compactMap({Towns(dictionary: $0.data())})
            completion(towns)
        }
    })
}

【问题讨论】:

    标签: ios swift google-cloud-firestore


    【解决方案1】:

    现在我遇到的问题是子集合不会出现在查询快照中(我只得到字段)

    没错,这就是 Cloud Firestore 查询的工作原理。这些查询被命名为浅表,这意味着它们只从运行查询的集合中获取项目。无法在单个查询中从顶级集合和子集合中获取文档。 Firestore 不支持一次性跨不同集合进行查询。单个查询只能使用单个集合中文档的属性。这就是为什么 ypu 看不到 querysnapshot 对象中的子集合,因此您可以进行直接对象映射。

    处理这类数据的最佳方法是什么(前提是没有标准化空间并且我们无法避免子集合)?

    在这种情况下,您应该查询数据库两次,一次获取集合中的对象,第二次获取子集合中的所有对象。

    还有另一种称为非规范化的做法,它是 Firebase 的常见做法。这种技术也意味着查询数据库两次。如果您是 NoQSL 数据库的新手,我建议您观看此视频,Denormalization is normal with the Firebase Database 以便更好地理解。它适用于 Firebase 实时数据库,但同样的规则适用于 Cloud Firestore。

    另外,当您复制数据时,需要牢记一件事。与添加数据的方式相同,您需要对其进行维护。换句话说,如果你想更新/删除一个项目,你需要在它存在的每个地方都这样做。

    因此,在这种情况下,您可以通过创建一个顶级集合来对数据进行非规范化,您应该在其中添加子集合中存在的所有对象。由您决定哪种做法更适合您。

    【讨论】:

    • 感谢您的回复....使用我当前的解决方案,我能够获取子集合和东西并能够创建对象....但是我正在为每个集合进行递归循环自下而上,即城镇 --> 省 --> 州 --> 国家...一旦循环结束,您将获得一个国家和儿童列表...但我不确定这是否是最好的方式
    • 只要您对每个单独的集合/子集合有单独的查询并且您有想要的结果,那么您应该继续这样做。
    • 然后是监听器..如何监听这些数据的变化?
    • 如果你想收听实时更新,那么你应该使用addSnapshotListener
    • 是的,我知道,但将其添加到每个文档中?我可以将侦听器添加到根集合并在其树下的任何内容发生更改时通知吗?
    猜你喜欢
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 2014-02-02
    • 2021-03-06
    • 1970-01-01
    • 1970-01-01
    • 2020-05-18
    相关资源
    最近更新 更多