В этом документе рассматриваются основы извлечения данных, а также порядок упорядочивания и фильтрации данных Firebase.
Прежде чем начать
Убедитесь, что вы настроили свое приложение и можете получить доступ к базе данных, как описано в руководстве Get Started
.
Извлечение данных
Данные Firebase извлекаются либо однократным вызовом GetValue()
, либо путём присоединения к ValueListener
по ссылке FirebaseDatabase
. Прослушиватель значений вызывается один раз для начального состояния данных и затем каждый раз при их изменении.
Получить ссылку на базу данных
Для записи данных в базу данных вам необходим экземпляр DatabaseReference
:
// Get the root reference location of the database. firebase::database::DatabaseReference dbref = database->GetReference();
Прочитать данные один раз
Метод GetValue()
позволяет однократно прочитать статический снимок содержимого по заданному пути. Результатом выполнения задачи будет снимок, содержащий все данные в этом месте, включая дочерние данные. Если данные отсутствуют, возвращается снимок null
.
firebase::Future<firebase::database::DataSnapshot> result = dbRef.GetReference("Leaders").GetValue();
В этот момент запрос уже сделан, но нам нужно дождаться завершения Future, чтобы прочитать значение. Поскольку игры обычно работают в цикле и меньше зависят от обратных вызовов, чем другие приложения, обычно вы будете опрашивать выполнение.
// In the game loop that polls for the result... if (result.status() != firebase::kFutureStatusPending) { if (result.status() != firebase::kFutureStatusComplete) { LogMessage("ERROR: GetValue() returned an invalid result."); // Handle the error... } else if (result.error() != firebase::database::kErrorNone) { LogMessage("ERROR: GetValue() returned error %d: %s", result.error(), result.error_message()); // Handle the error... } else { firebase::database::DataSnapshot snapshot = result.result(); // Do something with the snapshot... } }
Здесь показана базовая проверка ошибок. Дополнительную информацию о проверке ошибок и способах определения готовности результата см. в справочнике firebase::Future.
Следите за событиями
Вы можете добавить прослушивателей, чтобы подписаться на изменения данных:
Базовый класс ValueListener
Перезвонить | Типичное использование |
---|---|
OnValueChanged | Чтение и прослушивание изменений во всем содержимом пути. |
Базовый класс OnChildListener
OnChildAdded | Извлекайте списки элементов или отслеживайте их добавление. Рекомендуется использовать с OnChildChanged и OnChildRemoved для отслеживания изменений в списках. |
OnChildChanged | Отслеживайте изменения элементов списка. Используйте с OnChildAdded и OnChildRemoved для отслеживания изменений в списках. |
OnChildRemoved | Отслеживайте удаление элементов из списка. Используйте с OnChildAdded и OnChildChanged для отслеживания изменений в списках. |
OnChildMoved | Отслеживайте изменения порядка элементов в упорядоченном списке. Обратные вызовы OnChildMoved всегда следуют за обратными вызовами OnChildChanged , поскольку порядок элементов изменяется (в соответствии с текущим методом сортировки). |
Класс ValueListener
Вы можете использовать обратные вызовы OnValueChanged
, чтобы подписаться на изменения содержимого по заданному пути. Этот обратный вызов срабатывает один раз при подключении прослушивателя и затем каждый раз при изменении данных, включая дочерние. В обратный вызов передаётся снимок, содержащий все данные в этом месте, включая дочерние данные. Если данные отсутствуют, возвращается снимок, равный null
.
В следующем примере демонстрируется игра, извлекающая результаты таблицы лидеров из базы данных:
class LeadersValueListener : public firebase::database::ValueListener { public: void OnValueChanged( const firebase::database::DataSnapshot& snapshot) override { // Do something with the data in snapshot... } void OnCancelled(const firebase::database::Error& error_code, const char* error_message) override { LogMessage("ERROR: LeadersValueListener canceled: %d: %s", error_code, error_message); } }; // Elsewhere in the code... LeadersValueListener* listener = new LeadersValueListener(); firebase::Future<firebase::database::DataSnapshot> result = dbRef.GetReference("Leaders").AddValueListener(listener);
Результат Future<DataSnapshot>
содержит данные, находившиеся в указанном месте базы данных на момент события. Вызов метода value()
для снимка возвращает Variant
представляющий эти данные.
В этом примере метод OnCancelled
также переопределяется, чтобы проверить, отменено ли чтение. Например, чтение может быть отменено, если у клиента нет разрешения на чтение из расположения базы данных Firebase. database::Error
укажет причину сбоя.
Класс ChildListener
Дочерние события запускаются в ответ на определённые операции, выполняемые над дочерними элементами узла, например, при добавлении нового дочернего элемента методом PushChild()
или обновлении дочернего элемента методом UpdateChildren()
. Каждое из этих действий вместе может быть полезно для отслеживания изменений в определённом узле в базе данных. Например, игра может использовать эти методы вместе для отслеживания активности в комментариях во время игрового сеанса, как показано ниже:
class SessionCommentsChildListener : public firebase::database::ChildListener { public: void OnChildAdded(const firebase::database::DataSnapshot& snapshot, const char* previous_sibling) override { // Do something with the data in snapshot ... } void OnChildChanged(const firebase::database::DataSnapshot& snapshot, const char* previous_sibling) override { // Do something with the data in snapshot ... } void OnChildRemoved( const firebase::database::DataSnapshot& snapshot) override { // Do something with the data in snapshot ... } void OnChildMoved(const firebase::database::DataSnapshot& snapshot, const char* previous_sibling) override { // Do something with the data in snapshot ... } void OnCancelled(const firebase::database::Error& error_code, const char* error_message) override { LogMessage("ERROR: SessionCommentsChildListener canceled: %d: %s", error_code, error_message); } }; // elsewhere .... SessionCommentsChildListener* listener = new SessionCommentsChildListener(); firebase::Future<firebase::database::DataSnapshot> result = dbRef.GetReference("GameSessionComments").AddChildListener(listener);
Обратный вызов OnChildAdded
обычно используется для получения списка элементов в базе данных Firebase. Обратный вызов OnChildAdded
вызывается один раз для каждого существующего дочернего элемента и затем каждый раз при добавлении нового дочернего элемента в указанный путь. Слушателю передаётся снимок, содержащий данные нового дочернего элемента.
Обратный вызов OnChildChanged
вызывается при каждом изменении дочернего узла. Это включает любые изменения потомков дочернего узла. Обычно он используется вместе с вызовами OnChildAdded
и OnChildRemoved
для реагирования на изменения в списке элементов. Снимок, передаваемый прослушивателю, содержит обновлённые данные дочернего узла.
Обратный вызов OnChildRemoved
срабатывает при удалении непосредственного дочернего элемента. Обычно он используется вместе с обратными вызовами OnChildAdded
и OnChildChanged
. Снимок, передаваемый в обратный вызов, содержит данные об удаленном дочернем элементе.
Обратный вызов OnChildMoved
срабатывает всякий раз, когда происходит вызов OnChildChanged
при обновлении, приводящем к переупорядочиванию дочернего элемента. Он используется с данными, упорядоченными с помощью OrderByChild
или OrderByValue
.
Сортировка и фильтрация данных
Вы можете использовать класс Realtime Database Query
для извлечения данных, отсортированных по ключу, значению или значению дочернего элемента. Вы также можете отфильтровать отсортированный результат по определённому количеству результатов или диапазону ключей или значений.
Сортировка данных
Чтобы получить отсортированные данные, начните с указания одного из методов сортировки, чтобы определить, как будут упорядочены результаты:
Метод | Использование |
---|---|
OrderByChild() | Сортировать результаты по значению указанного дочернего ключа. | OrderByKey() | Сортировать результаты по дочерним ключам. |
OrderByValue() | Сортировать результаты по дочерним значениям. |
Одновременно можно использовать только один метод order-by. Многократный вызов метода order-by в одном запросе приводит к ошибке.
В следующем примере показано, как можно подписаться на таблицу лидеров, упорядоченную по количеству набранных очков.
firebase::database::Query query = dbRef.GetReference("Leaders").OrderByChild("score"); // To get the resulting DataSnapshot either use query.GetValue() and poll the // future, or use query.AddValueListener() and register to handle the // OnValueChanged callback.
Это определяет firebase::Query
, который в сочетании с ValueListener синхронизирует клиент с таблицей лидеров в базе данных, упорядоченной по баллам каждой записи. Подробнее об эффективной структуризации данных можно узнать в статье «Структурирование базы данных» .
Вызов метода OrderByChild()
указывает дочерний ключ, по которому следует упорядочить результаты. В этом случае результаты сортируются по значению "score"
для каждого дочернего элемента. Подробнее об упорядочивании других типов данных см. в разделе «Как упорядочиваются данные запроса ».
Фильтрация данных
Для фильтрации данных при построении запроса можно комбинировать любой из методов ограничения или диапазона с методом сортировки.
Метод | Использование |
---|---|
LimitToFirst() | Устанавливает максимальное количество элементов, возвращаемых с начала упорядоченного списка результатов. |
LimitToLast() | Устанавливает максимальное количество элементов, возвращаемых из конца упорядоченного списка результатов. |
StartAt() | Возвращает элементы, большие или равные указанному ключу или значению в зависимости от выбранного метода сортировки. |
EndAt() | Возвращает элементы, меньшие или равные указанному ключу или значению в зависимости от выбранного метода сортировки. |
EqualTo() | Возвращает элементы, равные указанному ключу или значению, в зависимости от выбранного метода сортировки. |
В отличие от методов order-by, вы можете комбинировать несколько функций ограничения или диапазона. Например, можно объединить методы StartAt()
и EndAt()
чтобы ограничить результаты заданным диапазоном значений.
Даже если для запроса есть только одно совпадение, снимок все равно представляет собой список; он содержит только один элемент.
Ограничить количество результатов
Вы можете использовать методы LimitToFirst()
и LimitToLast()
, чтобы задать максимальное количество дочерних элементов, синхронизируемых для заданного обратного вызова. Например, если вы используете LimitToFirst()
для установки ограничения в 100, изначально вы получите не более 100 обратных вызовов OnChildAdded
. Если в базе данных Firebase хранится менее 100 элементов, обратный вызов OnChildAdded
срабатывает для каждого элемента.
По мере изменения элементов вы получаете обратные вызовы OnChildAdded
для элементов, которые входят в запрос, и обратные вызовы OnChildRemoved
для элементов, которые из него выпадают, так что общее количество остается равным 100.
Например, приведенный ниже код возвращает лучший результат из таблицы лидеров:
firebase::database::Query query = dbRef.GetReference("Leaders").OrderByChild("score").LimitToLast(1); // To get the resulting DataSnapshot either use query.GetValue() and poll the // future, or use query.AddValueListener() and register to handle the // OnValueChanged callback.
Фильтр по ключу или значению
Вы можете использовать StartAt()
, EndAt()
и EqualTo()
для выбора произвольных начальных, конечных и эквивалентных точек для запросов. Это может быть полезно для разбиения данных на страницы или поиска элементов с дочерними элементами, имеющими определённое значение.
Как упорядочиваются данные запроса
В этом разделе объясняется, как данные сортируются каждым из методов сортировки в классе Query
.
OrderByChild
При использовании OrderByChild()
данные, содержащие указанный дочерний ключ, упорядочиваются следующим образом:
- Сначала идут дочерние элементы с
null
значением для указанного дочернего ключа. - Далее идут дочерние элементы со значением
false
для указанного ключа. Если значениеfalse
есть у нескольких дочерних элементов, они сортируются лексикографически по ключу. - Далее идут дочерние элементы со значением
true
для указанного дочернего ключа. Если значениеtrue
есть у нескольких дочерних элементов, они сортируются лексикографически по ключу. - Далее следуют дочерние элементы с числовым значением, отсортированные по возрастанию. Если несколько дочерних элементов имеют одинаковое числовое значение для указанного дочернего узла, они сортируются по ключу.
- Строки следуют за числами и сортируются лексикографически по возрастанию. Если несколько дочерних элементов имеют одинаковое значение для указанного дочернего узла, они упорядочиваются лексикографически по ключу.
- Объекты идут последними и сортируются лексикографически по ключу в порядке возрастания.
OrderByKey
При использовании OrderByKey()
для сортировки данных данные возвращаются в порядке возрастания ключа.
- Сначала идут потомки с ключом, который можно проанализировать как 32-битное целое число, отсортированные по возрастанию.
- Далее следуют дочерние элементы со строковым значением в качестве ключа, отсортированные лексикографически в порядке возрастания.
OrderByValue
При использовании OrderByValue()
дочерние элементы сортируются по их значению. Критерии упорядочивания те же, что и в OrderByChild()
, за исключением того, что вместо значения указанного дочернего ключа используется значение узла.