Получить FIRDatabaseReference
Для чтения или записи данных из базы данных вам необходим экземпляр FIRDatabaseReference
:
Быстрый
var ref: DatabaseReference! ref = Database.database().reference()
Objective-C
@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 . |
Каждый из этих методов вместе может быть полезен для отслеживания изменений в определённом узле базы данных. Например, приложение для социальных блогов может использовать эти методы вместе для отслеживания активности в комментариях к публикации, как показано ниже:
Быстрый
// 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
// 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
к списку данных вернет весь список данных в виде одного снимка данных, который затем можно будет циклически перебрать для доступа к отдельным дочерним элементам.
Даже если для запроса найдено только одно совпадение, снимок всё равно представляет собой список, содержащий всего один элемент. Чтобы получить доступ к элементу, необходимо выполнить цикл по результату:
Быстрый
_commentsRef.observe(.value) { snapshot in for child in snapshot.children { ... } }
Objective-C
[_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 в одном запросе приводит к ошибке.
В следующем примере показано, как можно получить список лучших публикаций пользователя, отсортированный по количеству звезд:
Быстрый
// My top posts by number of stars let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")
Objective-C
// 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
.
Быстрый
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")
Objective-C
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 последних сообщений всех пользователей:
Быстрый
// 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
// 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
для сортировки данных данные возвращаются в порядке возрастания ключа.
- Сначала идут потомки с ключом, который можно проанализировать как 32-битное целое число, отсортированные по возрастанию.
- Далее следуют дочерние элементы со строковым значением в качестве ключа, отсортированные лексикографически в порядке возрастания.
queryOrderedByValue
При использовании queryOrderedByValue
дочерние элементы сортируются по их значению. Критерии упорядочивания те же, что и в queryOrderedByChild
, за исключением того, что вместо значения указанного дочернего ключа используется значение узла.
queryOrderedByChild
При использовании queryOrderedByChild
данные, содержащие указанный дочерний ключ, упорядочиваются следующим образом:
- Сначала идут дети с
nil
значением указанного дочернего ключа. - Далее идут дочерние элементы со значением
false
для указанного ключа. Если значениеfalse
есть у нескольких дочерних элементов, они сортируются лексикографически по ключу. - Далее идут дочерние элементы со значением
true
для указанного дочернего ключа. Если значениеtrue
есть у нескольких дочерних элементов, они сортируются лексикографически по ключу. - Далее следуют дочерние элементы с числовым значением, отсортированные по возрастанию. Если несколько дочерних элементов имеют одинаковое числовое значение для указанного дочернего узла, они сортируются по ключу.
- Строки следуют за числами и сортируются лексикографически по возрастанию. Если несколько дочерних элементов имеют одинаковое значение для указанного дочернего узла, они упорядочиваются лексикографически по ключу.
- Объекты идут последними и сортируются лексикографически по ключу в порядке возрастания.
Отсоединить слушателей
Наблюдатели не прекращают синхронизацию данных автоматически при выходе из ViewController
. Если наблюдатель не удалён корректно, он продолжает синхронизировать данные с локальной памятью и сохраняет все объекты, захваченные при замыкании обработчика событий, что может привести к утечкам памяти. Когда наблюдатель больше не нужен, удалите его, передав соответствующий FIRDatabaseHandle
методу removeObserverWithHandle
.
При добавлении блока обратного вызова к ссылке возвращается дескриптор FIRDatabaseHandle
. Эти дескрипторы можно использовать для удаления блока обратного вызова.
Если к ссылке на базу данных добавлено несколько прослушивателей, каждый из них вызывается при возникновении события. Чтобы остановить синхронизацию данных в этом месте, необходимо удалить всех наблюдателей в этом месте, вызвав метод removeAllObservers
.
Вызов removeObserverWithHandle
или removeAllObservers
для прослушивателя не приводит к автоматическому удалению прослушивателей, зарегистрированных на его дочерних узлах; необходимо также отслеживать эти ссылки или дескрипторы, чтобы удалять их.