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

Получите FIRDatabaseReference

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

Swift

Примечание. Эта функция Firebase недоступна для блиц-приложений.
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

Примечание. Эта функция Firebase недоступна для блиц-приложений.
@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.

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

Swift

Примечание. Эта функция Firebase недоступна для блиц-приложений.
// 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 недоступна для блиц-приложений.
// 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, который можно перебрать в цикле, чтобы получить доступ к отдельным дочерним элементам.

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

Swift

Примечание. Эта функция Firebase недоступна для блиц-приложений.
_commentsRef.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}

Objective-C

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

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

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

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

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

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

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

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

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

Swift

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

Objective-C

Примечание. Эта функция Firebase недоступна для блиц-приложений.
// 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.

Swift

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

Objective-C

Примечание. Эта функция Firebase недоступна для блиц-приложений.
 
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 последних записей всех пользователей:

Swift

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

Дальнейшие действия