Работа со списками данных на платформах 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]) {
                  // ...
                }
              }];

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

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

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

Сортировать данные

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

Метод Использование
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, вы можете прочитать больше о нем в разделе Structure Your Database .

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

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