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

Получить FIRDatabaseReference

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

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

Быстрый

Примечание: этот продукт 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 Сортировать результаты по значению указанного дочернего ключа или вложенного дочернего пути.

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

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

Быстрый

Примечание: этот продукт 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 Возвращает элементы, равные указанному ключу или значению, в зависимости от выбранного метода сортировки.

В отличие от методов order-by, можно комбинировать несколько функций ограничения или диапазона. Например, можно объединить методы 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 для выбора произвольных начальных, конечных и эквивалентных точек для запросов. Это может быть полезно для разбиения данных на страницы или поиска элементов с дочерними элементами, имеющими определённое значение.

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

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

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