【问题标题】:How to create array in array using collections and sub collections in Firestore?如何使用 Firestore 中的集合和子集合在数组中创建数组?
【发布时间】:2019-02-19 00:00:08
【问题描述】:

我需要创建一个包含Questions 数组的Categories 数组。

struct CategoryFB {
    var title: String
    var id: Int
    var questions: [QuestionsFB]

    var dictionary: [String : Any] {
        return ["title" : title, 
                "id" : id]
    }
}

extension CategoryFB {
    init?(dictionary: [String : Any], questions: [QuestionsFB]) {
        guard let title = dictionary["title"] as? String, let id = dictionary["id"] as? Int else { return nil }

        self.init(title: title, id: id, questions: questions)
    }
}

Firestore 具有以下结构

  1. 集合(“类别”)
  2. 文档(“some_id”)
  3. 集合(“问题”)

如何创建这样的数组?

array = [Category(title: "First", 
                  questions: [
                      Question("1"),
                      ...
                  ]), 
         ... ]

我的尝试是错误的:

db.collection("Categories").order(by: "id", descending: false).getDocuments {
    (querySnapshot, error) in
    if error != nil {
        print("Error when getting data \(String(describing: error?.localizedDescription))")
    } else {
        for document in querySnapshot!.documents {
            print(document.documentID)
            self.db.collection("Categories").document(document.documentID).collection("Questions").getDocuments(completion: { (subQuerySnapshot, error) in
                if error != nil {
                    print(error!.localizedDescription)
                } else {
                    var questionsArray: [QuestionsFB]?
                    questionsArray = subQuerySnapshot?.documents.compactMap({QuestionsFB(dictionary: $0.data())})
                    self.categoriesArray = querySnapshot?.documents.compactMap({CategoryFB(dictionary: $0.data(), questions: questionsArray!)})
                    print(self.categoriesArray![0].questions.count)
                    DispatchQueue.main.async {
                        self.tableView.reloadData()
                    }
                }
            })
        }
    }
}

【问题讨论】:

  • 首先您必须为问题创建模型,为类别创建第二个模型,然后在类别模型中创建问题模型数组。因此,当您可以创建类别模型的实例时,您可以按索引访问问题数组。能否请您显示存储的问题数组?
  • @AbhishekJadhav 代码太多.. 无法编辑。问题有:title、id、details 和一些数组。我有这个模型。现在我需要根据类别创建此对象的数组
  • 您已经在类别模型中创建了问题数组,然后当您必须在类别实例的问题数组中附加任何数据时,然后创建问题实例并将其附加到问题数组中
  • @AbhishekJadhav 我明白这一点,但不能通过代码做到这一点。我收集了 10 个类别,每个类别都有 10 个文档,其中包含 20-40 个问题的集合问题。
  • 问题集合中有什么?只是数组中的一系列问题?例如0:什么是……和 1:……在哪里?您能否附上实际结构的屏幕截图,因为它在问题中有点含糊。

标签: ios arrays swift firebase google-cloud-firestore


【解决方案1】:

这是我自己找到的解决方案。希望这对将来的人有所帮助。

func getData(completion: @escaping (_ result: [Any]) -> Void) {
    let rootCollection = db.collection("Categories")

    var data = [Any]()

    rootCollection.order(by: "id", descending: false).getDocuments(completion: {

        (querySnapshot, error) in

        if error != nil {
            print("Error when getting data \(String(describing: error?.localizedDescription))")
        } else {
            guard let topSnapshot = querySnapshot?.documents else { return }
            for category in topSnapshot {
                rootCollection.document(category.documentID).collection("Questions").getDocuments(completion: {
                    (snapshot, err) in

                    guard let snapshot = snapshot?.documents else { return }

                    var questions = [Question]()

                    for document in snapshot {
                        let title = document.data()["title"] as! String
                        let details = document.data()["details"] as! String
                        let article = document.data()["article"] as! String
                        let link = document.data()["link"] as! String
                        let id = document.data()["id"] as! String
                        let possibleAnswers = document.data()["possibleAnswers"] as! [String]
                        let rightAnswerID = document.data()["rightAnswerID"] as! Int

                        let newQuestion = Question(title: title, article: article, details: details, link: link, possibleAnswers: possibleAnswers, rightAnswerID: rightAnswerID, id: id)

                        questions.append(newQuestion)

                    }
                    let categoryTitle = category.data()["title"] as! String
                    let collectionID = category.data()["id"] as! Int


                    let newCategory = Category(title: categoryTitle, id: collectionID, questions: questions)


                    data.append(newCategory)

                    //Return data on completion
                    completion(data)
                })
            }
        }
    })
}

【讨论】:

    【解决方案2】:

    您的主要问题似乎源于您每次运行子查询时都在重新生成类别数组,而当您这样做时,您只为整个事物提供了一个问题数组。

    有很多方法可以解决这个问题。我可能会分解它,以便您 a) 首先允许自己创建一个没有任何问题的类别数组,然后 b) 回顾每个单独的子查询,并在获得它们时将它们插入到您的类别中。

    您的最终代码可能看起来像这样。请注意,这意味着更改您的 Category 对象,以便您可以在没有 Questions 数组的情况下首先创建它,并实现此自定义 addQuestions:toCategory: 方法(如果您将类别存储为字典而不是数组,这将容易得多)

    db.collection("Categories").order(by: "id", descending: false).getDocuments {
        (querySnapshot, error) in
        if error != nil {
            print("Error when getting data \(String(describing: error?.localizedDescription))")
        } else {
            self.categoriesArray = querySnapshot?.documents.compactMap({CategoryFB(dictionary: $0.data()})
            for document in querySnapshot!.documents {
                print(document.documentID)
                self.db.collection("Categories").document(document.documentID).collection("Questions").getDocuments(completion: { (subQuerySnapshot, error) in
                    if error != nil {
                        print(error!.localizedDescription)
                    } else {
                        var questionsArray: [QuestionsFB]?
                        questionsArray = subQuerySnapshot?.documents.compactMap({QuestionsFB(dictionary: $0.data())})
                        self.addQuestions(questionsArray toCategory: document.documentID)
                        print(self.categoriesArray![0].questions.count)
                        DispatchQueue.main.async {
                            self.tableView.reloadData()
                        }
                    }
                })
            }
        }
    }
    

    或者,如果您认为您将处于每次想要获取某个类别时总是想要获取您的问题的情况,您可能会考虑不放置它们根本就在一个子集合中,只是在原始类别文档中使它们成为一个地图。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-06
      • 1970-01-01
      • 2021-11-14
      • 1970-01-01
      • 2022-01-20
      • 2021-01-28
      • 1970-01-01
      • 2020-04-07
      相关资源
      最近更新 更多