Работа со списками данных на платформах Apple

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

Для чтения или записи данных из базы данных необходим экземпляр класса FIRDatabaseReference :

Быстрый

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

Списки для чтения и письма

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

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

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

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

Слушайте новости о детских мероприятиях

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

Тип события Типичное использование
FIRDataEventTypeChildAdded Получает списки элементов или отслеживает добавления элементов в список. Это событие срабатывает один раз для каждого существующего дочернего элемента, а затем снова каждый раз, когда к указанному пути добавляется новый дочерний элемент. Обработчику передается снимок, содержащий данные нового дочернего элемента.
FIRDataEventTypeChildChanged Отслеживайте изменения элементов в списке. Это событие срабатывает всякий раз, когда изменяется дочерний узел. Это включает в себя любые изменения потомков дочернего узла. Снимок, передаваемый обработчику событий, содержит обновленные данные для дочернего узла.
FIRDataEventTypeChildRemoved Отслеживайте удаление элементов из списка. Это событие срабатывает при удалении непосредственного дочернего элемента. Снимок, передаваемый в блок обратного вызова, содержит данные удаленного дочернего элемента.
FIRDataEventTypeChildMoved Отслеживайте изменения порядка элементов в упорядоченном списке. Это событие срабатывает всякий раз, когда обновление приводит к изменению порядка дочерних элементов. Оно используется с данными, упорядоченными по параметрам queryOrderedByChild или queryOrderedByValue .

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

Быстрый

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
// Listen for new comments in the Firebase database
commentsRef.observe(.childAdded, with: { (snapshot) -> Void in
  self.comments.append(snapshot)
  self.tableView.insertRows(
    at: [IndexPath(row: self.comments.count - 1, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})
// Listen for deleted comments in the Firebase database
commentsRef.observe(.childRemoved, with: { (snapshot) -> Void in
  let index = self.indexOfMessage(snapshot)
  self.comments.remove(at: index)
  self.tableView.deleteRows(
    at: [IndexPath(row: index, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})

Objective-C

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
// Listen for new comments in the Firebase database
[_commentsRef
              observeEventType:FIRDataEventTypeChildAdded
              withBlock:^(FIRDataSnapshot *snapshot) {
                [self.comments addObject:snapshot];
                [self.tableView insertRowsAtIndexPaths:@[
                  [NSIndexPath indexPathForRow:self.comments.count - 1 inSection:kSectionComments]
                ]
                                      withRowAnimation:UITableViewRowAnimationAutomatic];
              }];
// Listen for deleted comments in the Firebase database
[_commentsRef
 observeEventType:FIRDataEventTypeChildRemoved
 withBlock:^(FIRDataSnapshot *snapshot) {
   int index = [self indexOfMessage:snapshot];
   [self.comments removeObjectAtIndex:index];
   [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:kSectionComments]]
                         withRowAnimation:UITableViewRowAnimationAutomatic];
 }];

Обращайте внимание на важные события.

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

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

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

Быстрый

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
_commentsRef.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}

Objective-C

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
[_commentsRef
              observeEventType:FIRDataEventTypeValue
              withBlock:^(FIRDataSnapshot *snapshot) {
                // Loop over children
                NSEnumerator *children = [snapshot children];
                FIRDataSnapshot *child;
                while (child = [children nextObject]) {
                  // ...
                }
              }];

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

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

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

Сортировка данных

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

Метод Использование
queryOrderedByKey Сортировать результаты по дочерним ключам.
queryOrderedByValue Сортировать результаты по значениям дочерних элементов.
queryOrderedByChild Результаты сортировки определяются по значению указанного дочернего ключа или вложенного дочернего пути.

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

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

Быстрый

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
// My top posts by number of stars
let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")

Objective-C

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
// My top posts by number of stars
FIRDatabaseQuery *myTopPostsQuery = [[[self.ref child:@"user-posts"]
                                      child:[super getUid]]
                                     queryOrderedByChild:@"starCount"];

Этот запрос извлекает публикации пользователя из указанного пути в базе данных на основе его идентификатора пользователя, упорядоченные по количеству звезд, полученных каждой публикацией. Такой метод использования идентификаторов в качестве ключей индекса называется «расширение данных» (data fan out), подробнее об этом можно прочитать в статье «Структурирование базы данных» .

Вызов метода queryOrderedByChild указывает ключ дочернего элемента, по которому следует сортировать результаты. В этом примере записи сортируются по значению дочернего элемента "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 , указав относительный путь к вложенному дочернему элементу в вызове queryOrderedByChild .

Быстрый

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
 
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")

Objective-C

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
 
FIRDatabaseQuery *postsByMostPopular = [[ref child:@"posts"] queryOrderedByChild:@"metrics/views"];

Для получения дополнительной информации о порядке упорядочивания других типов данных см. раздел «Как упорядочиваются данные запроса» .

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

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

Метод Использование
queryLimitedToFirst Устанавливает максимальное количество элементов, возвращаемых с начала упорядоченного списка результатов.
queryLimitedToLast Устанавливает максимальное количество элементов, возвращаемых с конца упорядоченного списка результатов.
queryStartingAtValue Возвращает элементы, большие или равные указанному ключу или значению, в зависимости от выбранного метода сортировки.
queryStartingAfterValue Возвращает элементы, превышающие указанный ключ или значение, в зависимости от выбранного метода сортировки.
queryEndingAtValue Возвращает элементы, меньшие или равные указанному ключу или значению, в зависимости от выбранного метода сортировки.
queryEndingBeforeValue Возвращает количество элементов меньше указанного ключа или значения в зависимости от выбранного метода сортировки.
queryEqualToValue Возвращает элементы, равные указанному ключу или значению, в зависимости от выбранного метода сортировки.

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

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

Методы queryLimitedToFirst и queryLimitedToLast позволяют установить максимальное количество дочерних элементов, синхронизируемых для данного коллбэка. Например, если вы используете queryLimitedToFirst для установки лимита в 100, вы изначально получите только до 100 коллбэков FIRDataEventTypeChildAdded . Если в вашей базе данных Firebase хранится менее 100 элементов, для каждого элемента будет срабатывать коллбэк FIRDataEventTypeChildAdded .

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

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

Быстрый

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
let recentPostsQuery = (ref?.child("posts").queryLimited(toFirst: 100))!

Objective-C

Примечание: Этот продукт Firebase недоступен в целевом приложении App Clip.
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
FIRDatabaseQuery *recentPostsQuery = [[self.ref child:@"posts"] queryLimitedToFirst:100];

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

Вы можете использовать queryStartingAtValue , queryStartingAfterValue , queryEndingAtValue , queryEndingBeforeValue и queryEqualToValue для выбора произвольных начальных, конечных и эквивалентных точек для запросов. Это может быть полезно для постраничной навигации данных или поиска элементов, имеющих дочерние элементы с определенным значением.

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

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

queryOrderedByKey

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

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

queryOrderedByValue

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

queryOrderedByChild

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

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

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

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

При добавлении блока обратного вызова к ссылке возвращается объект FIRDatabaseHandle . Эти дескрипторы можно использовать для удаления блока обратного вызова.

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

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

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