Firestore, реплицирующий SQL Join для noSQL и Flutter - PullRequest
0 голосов
/ 12 февраля 2019

Я понимаю, что есть много вопросов относительно репликации объединений с базами данных документов NoSql, такими как FireStore, однако я не могу найти исчерпывающее решение, использующее Dart / Flutter с FireStore.

Я провел некоторое исследованиеЯ чувствую, что в следующем примере я буду искать отношения «многие ко многим» (пожалуйста, исправьте меня, если это не так), поскольку в будущем может потребоваться просмотреть все профили, а также все соединения.

В firebase у меня есть две коллекции корневого уровня (профиль и соединение):

profile
    > documentKey(Auto Generated)
         > name = "John Smith"
         > uid = "xyc4567"

    > documentKey(Auto Generated)
         > name = "Jane Doe"
         > uid = "abc1234"

    > documentKey(Auto Generated)
         > name = "Kate Dee"
         > uid = "efg8910"



connection
    > documentKey(Auto Generated)
         > type = "friend"
         > profileuid = "abc1234"
         > uid = "xyc4567"

    > documentKey(Auto Generated)
         > type = "family"
         > profileuid = "abc1234"
         > uid = "efg8910"

Для этого примера документы «подключения» были гипотетически созданы для пользователя Джона Смита (uid: xyc4567), когда онподключен к Джейн Доу (uid: abc1234) и Кейт Ди (uid: efg8910).

Вот реляционный SQL, который я хочу скопировать, чтобы показать список профилей, с которыми Джон Смит связался:

Select * FROM profile, connection 
WHERE profile.uid = connection.profileuid 
AND profile.uid = "xyc4567"

Во флаттере моего приложения флаттера у меня есть начальная точка запроса fireStore:

stream: Firestore.instance.collection('profile')
.where('uid', isEqualTo: "xyc4567").snapshots(),

Очевидно, это только ретурны из одной коллекции.Как мне присоединиться к коллекциям во многих отношениях?

Ответы [ 2 ]

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

Я сделал что-то подобное, чтобы объединить результаты двух объектов и категорий наборов.

я сделал два StreamBuilder для отображения в списке, в первом я получил категории и поместил в карту, затем язапросите объекты и получите объект категории с карты, используя categoryID:

StreamBuilder<QuerySnapshot>(
              stream: Firestore.instance
                  .collection('categoryPath')
                  .snapshots(),
              builder: (BuildContext context,
                  AsyncSnapshot<QuerySnapshot> categorySnapshot) {
                //get data from categories

                if (!categorySnapshot.hasData) {
                  return const Text('Loading...');
                }

                //put all categories in a map
                Map<String, Category> categories = Map();
                categorySnapshot.data.documents.forEach((c) {
                  categories[c.documentID] =
                      Category.fromJson(c.documentID, c.data);
                });

                //then from objects

                return StreamBuilder<QuerySnapshot>(
                  stream: Firestore.instance
                      .collection('objectsPath')
                      .where('day', isGreaterThanOrEqualTo: _initialDate)
                      .where('day', isLessThanOrEqualTo: _finalDate)
                      .snapshots(),
                  builder: (BuildContext context,
                      AsyncSnapshot<QuerySnapshot> objectsSnapshot) {
                    if (!objectsSnapshot.hasData)
                      return const Text('Loading...');

                    final int count =
                        objectsSnapshot.data.documents.length;
                    return Expanded(
                      child: Container(
                        child: Card(
                          elevation: 3,
                          child: ListView.builder(
                              padding: EdgeInsets.only(top: 0),
                              itemCount: count,
                              itemBuilder: (_, int index) {
                                final DocumentSnapshot document =
                                    objectsSnapshot.data.documents[index];
                                Object object = Object.fromJson(
                                    document.documentID, document.data);

                                return Column(
                                  children: <Widget>[
                                    Card(
                                      margin: EdgeInsets.only(
                                          left: 0, right: 0, bottom: 1),
                                      shape: RoundedRectangleBorder(
                                        borderRadius: BorderRadius.all(
                                            Radius.circular(0)),
                                      ),
                                      elevation: 1,
                                      child: ListTile(
                                        onTap: () {},
                                        title: Text(object.description,
                                            style: TextStyle(fontSize: 20)),
//here is the magic, i get the category name using the map 
of the categories and the category id from the object
                                        subtitle: Text(
                                          categories[object.categoryId] !=
                                                  null
                                              ? categories[
                                                      object.categoryId]
                                                  .name
                                              : 'Uncategorized',
                                          style: TextStyle(
                                              color: Theme.of(context)
                                                  .primaryColor),
                                        ),

                                      ),
                                    ),
                                  ],
                                );
                              }),
                        ),
                      ),
                    );

Я не уверен, что это то, что вы хотите или ясно, но я надеюсь, что это поможет вам.

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

К сожалению, в Cloud Firestore, как и в других базах данных NoSQL, нет условия JOIN.В Firestore запросы мелкие.Это означает, что они получают только элементы из коллекции, к которой выполняется запрос.Нет возможности получить документы из двух коллекций верхнего уровня за один запрос.Firestore не поддерживает запросы к различным коллекциям за один раз.Один запрос может использовать только свойства документов в одной коллекции.

Поэтому самое простое решение, о котором я могу подумать, - запросить базу данных, чтобы получить uid пользователя из коллекции profile.Получив этот идентификатор, сделайте еще один вызов базы данных (внутри обратного вызова) и получите соответствующие данные, которые вам нужны, из коллекции connection, используя следующий запрос:

stream: Firestore.instance.collection('connection').where('uid', isEqualTo: "xyc4567").snapshots(),

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

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

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