Работа со списками данных

Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.

Получить ссылку на базу данных

Чтобы читать или записывать данные из базы данных, вам нужен экземпляр DatabaseReference :

DatabaseReference ref = FirebaseDatabase.instance.ref();

Чтение и написание списков

Добавить к списку данных

Используйте метод push() для добавления данных в список в многопользовательских приложениях. Метод push() генерирует уникальный ключ каждый раз, когда к указанной ссылке Firebase добавляется новый дочерний элемент. Используя эти автоматически сгенерированные ключи для каждого нового элемента в списке, несколько клиентов могут одновременно добавлять дочерние элементы в одно и то же место без конфликтов записи. Уникальный ключ, сгенерированный функцией push() , основан на метке времени, поэтому элементы списка автоматически упорядочиваются в хронологическом порядке.

Вы можете использовать ссылку на новые данные, возвращаемые методом push() , чтобы получить значение автоматически сгенерированного ключа дочернего элемента или установить данные для дочернего элемента. Свойство .key ссылки push() содержит автоматически сгенерированный ключ.

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

Например, push() можно использовать для добавления нового сообщения в список сообщений в социальном приложении:

DatabaseReference postListRef = FirebaseDatabase.instance.ref("posts");
DatabaseReference newPostRef = postListRef.push();
newPostRef.set({
  // ...
});

Прослушивание дочерних событий

Дочерние события запускаются в ответ на определенные операции, которые происходят с дочерними элементами узла из операции, такой как добавление нового дочернего элемента с помощью метода push() или обновление дочернего элемента с помощью метода update() .

Мероприятие Типичное использование
onChildAdded Получить списки элементов или прослушивать дополнения к списку элементов. Это событие запускается один раз для каждого существующего дочернего элемента, а затем снова каждый раз, когда новый дочерний элемент добавляется к указанному пути. Слушателю передается снимок, содержащий данные нового потомка.
onChildChanged Прислушивайтесь к изменениям элементов в списке. Это событие запускается каждый раз при изменении дочернего узла. Сюда входят любые модификации потомков дочернего узла. Моментальный снимок, переданный прослушивателю событий, содержит обновленные данные для дочернего элемента.
onChildRemoved Прослушивание элементов, удаляемых из списка. Это событие запускается при удалении непосредственного дочернего элемента. Моментальный снимок, переданный в блок обратного вызова, содержит данные для удаленного дочернего элемента.
onChildMoved Прислушивайтесь к изменениям порядка элементов в упорядоченном списке. События onChildMoved всегда следуют за событием onChildChanged, которое вызвало изменение порядка элементов (на основе вашего текущего метода упорядочения).

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

final commentsRef = FirebaseDatabase.instance.ref("post-comments/$postId");
commentsRef.onChildAdded.listen((event) {
  // A new comment has been added, so add it to the displayed list.
});
commentsRef.onChildChanged.listen((event) {
  // A comment has changed; use the key to determine if we are displaying this
  // comment and if so displayed the changed comment.
});
commentsRef.onChildRemoved.listen((event) {
  // A comment has been removed; use the key to determine if we are displaying
  // this comment and if so remove it.
});

Прослушивание событий значения

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

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

Даже если для запроса имеется только одно совпадение, снимок все равно представляет собой список; он просто содержит один элемент. Чтобы получить доступ к элементу, вам нужно перебрать результат:

myTopPostsQuery.onValue.listen((event) {
  for (final child in event.snapshot.children) {
    // Handle the post.
  }
}, onError: (error) {
  // Error.
});

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

Сортировка и фильтрация данных

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

Сортировать данные

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

Метод использование
orderByChild() Упорядочить результаты по значению указанного дочернего ключа или вложенного дочернего пути.
orderByKey() Упорядочить результаты по дочерним ключам.
orderByValue() Упорядочить результаты по дочерним значениям.

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

В следующем примере показано, как можно получить список самых популярных сообщений пользователя, отсортированных по количеству звездочек:

final myUserId = FirebaseAuth.instance.currentUser?.uid;
final topUserPostsRef = FirebaseDatabase.instance
    .ref("user-posts/$myUserId")
    .orderByChild("starCount");

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

Вызов метода orderByChild() указывает дочерний ключ, по которому упорядочиваются результаты. В этом случае сообщения сортируются по значению их соответствующего "starCount" . Запросы также могут быть упорядочены по вложенным дочерним элементам, если у вас есть данные, которые выглядят так:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

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

final mostViewedPosts =
    FirebaseDatabase.instance.ref('posts').orderByChild('metrics/views');

Дополнительные сведения о том, как упорядочиваются другие типы данных, см. в разделе Упорядочивание данных запроса .

Фильтрация данных

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

Метод использование
limitToFirst() Устанавливает максимальное количество элементов, возвращаемых с начала упорядоченного списка результатов.
limitToLast() Устанавливает максимальное количество элементов, возвращаемых с конца упорядоченного списка результатов.
startAt() Возвращает элементы, большие или равные указанному ключу или значению, в зависимости от выбранного метода упорядочения.
startAfter() Возвращает элементы, превышающие указанный ключ или значение, в зависимости от выбранного метода упорядочения.
endAt() Возвращает элементы, меньшие или равные указанному ключу или значению, в зависимости от выбранного метода упорядочения.
endBefore() Возвращает элементы меньше указанного ключа или значения в зависимости от выбранного метода упорядочения.
equalTo() Возвращает элементы, равные указанному ключу или значению, в зависимости от выбранного метода упорядочения.

В отличие от методов упорядочения, вы можете комбинировать несколько функций ограничения или диапазона. Например, вы можете комбинировать startAt() и endAt() , чтобы ограничить результаты указанным диапазоном значений.

Ограничьте количество результатов

Вы можете использовать limitToFirst() и limitToLast() , чтобы установить максимальное количество дочерних элементов, которые будут синхронизированы для данного события. Например, если вы используете limitToFirst() для установки ограничения в 100, вы изначально получаете только до 100 событий onChildAdded . Если в вашей базе данных Firebase хранится менее 100 элементов, для каждого элемента срабатывает событие onChildAdded .

По мере изменения элементов вы получаете события onChildAdded для элементов, которые входят в запрос, и события onChildRemoved для элементов, которые выпадают из него, так что общее число остается равным 100.

В следующем примере показано, как примерное приложение для ведения блога определяет запрос для получения списка из 100 самых последних сообщений всех пользователей:

final recentPostsRef = FirebaseDatabase.instance.ref('posts').limitToLast(100);

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

Фильтровать по ключу или значению

Вы можете использовать startAt() , startAfter() , endAt() , endBefore() и equalTo() для выбора произвольных начальных, конечных точек и точек эквивалентности для запросов. Это может быть полезно для разбиения данных на страницы или поиска элементов с дочерними элементами, имеющими определенное значение.

Как упорядочиваются данные запроса

В этом разделе объясняется, как данные сортируются каждым из методов упорядочивания в классе Query .

orderByChild

При использовании orderByChild() данные, содержащие указанный дочерний ключ, упорядочиваются следующим образом:

  1. Дети с null значением для указанного дочернего ключа идут первыми.
  2. Далее идут дочерние элементы со значением false для указанного дочернего ключа. Если несколько дочерних элементов имеют значение false , они лексикографически сортируются по ключу.
  3. Далее идут дочерние элементы со значением true для указанного дочернего ключа. Если несколько дочерних элементов имеют значение true , они лексикографически сортируются по ключу.
  4. Далее идут дети с числовым значением, отсортированные в порядке возрастания. Если несколько дочерних элементов имеют одинаковое числовое значение для указанного дочернего узла, они сортируются по ключу.
  5. Строки идут после чисел и сортируются лексикографически в порядке возрастания. Если несколько потомков имеют одинаковое значение для указанного дочернего узла, они лексикографически упорядочиваются по ключу.
  6. Объекты идут последними и лексикографически сортируются по ключу в порядке возрастания.

orderByKey

При использовании orderByKey() для сортировки данных данные возвращаются в порядке возрастания по ключу.

  1. Дети с ключом, который может быть проанализирован как 32-битное целое число, идут первыми, отсортированные в порядке возрастания.
  2. Далее идут дочерние элементы со строковым значением в качестве ключа, отсортированные лексикографически в порядке возрастания.

orderByValue

При использовании orderByValue() дочерние элементы упорядочиваются по их значению. Критерии упорядочения такие же, как в orderByChild() , за исключением того, что значение узла используется вместо значения указанного дочернего ключа.

Отключить слушателей

Обратные вызовы удаляются путем вызова метода off() в вашей ссылке на базу данных Firebase.

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

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

Следующие шаги