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

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

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

Быстрый

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

ref = Database.database().reference()

Цель-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
  )
})

Цель-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 {
    ...
  }
}

Цель-C

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

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

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

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

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

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

Метод Применение
queryOrderedByKey Упорядочить результаты по дочерним ключам.
queryOrderedByValue Упорядочить результаты по дочерним значениям.
queryOrderedByChild Упорядочите результаты по значению указанного дочернего ключа или вложенного дочернего пути.

Одновременно можно использовать только один метод order-by. Вызов метода упорядочивания несколько раз в одном и том же запросе приводит к ошибке.

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

Быстрый

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

Цель-C

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

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

Вызов метода 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")

Цель-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))!

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

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