Как создать массив в массиве, используя коллекции и вложенные коллекции в Firestore? - PullRequest
0 голосов
/ 14 сентября 2018

Мне нужно создать массив Categories, содержащий Questions массив.

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. Collection ( "Категория")
  2. Документ ( "some_id")
  3. Collection ( "Вопросы")

Как создать такой массив?

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()
                    }
                }
            })
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 15 сентября 2018

Это решение, которое я нашел сам.Надеюсь, это поможет кому-то в будущем.

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)
                })
            }
        }
    })
}
0 голосов
/ 15 сентября 2018

Ваша основная проблема, кажется, связана с тем фактом, что вы регенерируете массив категорий каждый раз, когда запускаете свой подзапрос, и когда вы это делаете, вы предоставляете только один массив вопросов для всего этого.

Есть много способов исправить это. Я бы, вероятно, разбил его так, чтобы вы a) сначала позволили себе создать массив категорий без каких-либо вопросов, а затем b) вернулись бы к каждому из ваших отдельных подзапросов и вставляли их в свои категории по мере их получения.

Ваш окончательный код может выглядеть примерно так. Обратите внимание, что это будет означать изменение вашего объекта Category, чтобы вы могли сначала создать его без массива вопросов, и реализацию этого пользовательского метода 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()
                    }
                }
            })
        }
    }
}

С другой стороны, если вы думаете, что окажетесь в ситуации, когда вы всегда захотите отвечать на ваши вопросы каждый раз, когда вы хотите получить категорию, вы можете не ставить их во вложенной коллекции вообще, и просто сделать их карту в исходном документе категории.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...