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

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