Swift: Firestore sub collection, пользовательские объекты и слушатели - PullRequest
0 голосов
/ 18 февраля 2019

У меня есть модель модели, как показано на рисунке ниже.

Model

В пользовательском интерфейсе я пытаюсь получить все 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)
        }
    })
}

1 Ответ

0 голосов
/ 18 февраля 2019

Теперь у меня проблема в том, что подколлекции не появятся в querysnapshot (я получаю только поля)

Правильно, именно так работают запросы Cloud Firestore.Запросы называются мелкими, что означает, что они получают только элементы из коллекции, к которой выполняется запрос.Невозможно получить документы из коллекции верхнего уровня и вложенных коллекций в одном запросе.Firestore не поддерживает запросы к различным коллекциям за один раз.Один запрос может использовать свойства документов только в одной коллекции.Вот почему ypu не может видеть вложенную коллекцию в объекте querysnapshot, поэтому вы можете выполнить прямое сопоставление объектов.

, что является лучшим способом обработки данных такого типа (при условии, что нет места для нормализациии мы не можем избежать вложенных коллекций)?

В этом случае вам следует дважды выполнить запрос к базе данных, один раз, чтобы получить объекты в коллекции, и второй, чтобы получить все объекты в коллекции.

Существует также другая практика, которая называется денормализация и является обычной практикой, когда дело доходит до Firebase.Этот метод подразумевает также двойной запрос к базе данных.Если вы новичок в базах данных NoQSL, я рекомендую вам посмотреть это видео, Денормализация нормальна с базой данных Firebase для лучшего понимания.Это для базы данных реального времени Firebase, но те же правила применяются к Cloud Firestore.

Также, когда вы дублируете данные, есть одна вещь, которую нужно иметь в виду.Точно так же, как вы добавляете данные, вы должны поддерживать их.Другими словами, если вы хотите обновить / обнаружить элемент, вы должны делать это в каждом месте, где он существует.

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

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