Получение данных с помощью базы данных Firebase Realtime для C++

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

Прежде чем начать

Убедитесь, что ваше приложение настроено и вы можете получить доступ к базе данных, как описано в руководстве Get Started .

Получение данных

Данные Firebase извлекаются либо однократным вызовом метода GetValue() , либо путем привязки к ValueListener на ссылке FirebaseDatabase . ValueListener вызывается один раз для начального состояния данных и повторно всякий раз, когда данные изменяются.

Получить ссылку на базу данных

Для записи данных в базу данных вам потребуется экземпляр класса DatabaseReference :

    // Get the root reference location of the database.
    firebase::database::DatabaseReference dbref = database->GetReference();

Прочитайте данные один раз

Метод GetValue() позволяет один раз прочитать статический снимок содержимого по указанному пути. Результатом выполнения задачи станет снимок, содержащий все данные в этом месте, включая данные дочерних элементов. Если данных нет, возвращается значение null .

  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("Leaders").GetValue();

Запрос уже отправлен, но нам нужно дождаться завершения Future, прежде чем мы сможем прочитать значение. Поскольку игры обычно работают в цикле и в меньшей степени зависят от обратных вызовов, чем другие приложения, обычно приходится опрашивать 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&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("Leaders").AddValueListener(listener);

Результат Future&ltDataSnapshot&gt содержит данные, находящиеся в указанном месте базы данных на момент события. Вызов метода 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&ltfirebase::database::DataSnapshot&gt 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() Сортировать результаты по значениям дочерних элементов.

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

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

  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() Возвращает элементы, равные указанному ключу или значению в зависимости от выбранного метода сортировки.

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

Как упорядочиваются данные запроса

В этом разделе объясняется, как данные сортируются каждым из методов ORDER BY в классе Query .

OrderByChild

При использовании функции OrderByChild() данные, содержащие указанный дочерний ключ, упорядочиваются следующим образом:

  1. В первую очередь идут дочерние элементы, у которых указанный ключ дочернего элемента имеет null значение.
  2. Далее следуют дочерние элементы со значением false для указанного ключа дочернего элемента. Если несколько дочерних элементов имеют значение false , они сортируются лексикографически по ключу.
  3. Далее следуют дочерние элементы, у которых для указанного ключа дочернего элемента значение равно true . Если несколько дочерних элементов имеют значение true , они сортируются лексикографически по ключу.
  4. Далее следуют дочерние узлы с числовым значением, отсортированные в порядке возрастания. Если несколько дочерних узлов имеют одинаковое числовое значение для указанного дочернего узла, они сортируются по ключу.
  5. Строки следуют за числами и сортируются лексикографически в порядке возрастания. Если несколько дочерних узлов имеют одинаковое значение для указанного дочернего узла, они упорядочиваются лексикографически по ключу.
  6. Объекты располагаются в самом конце и сортируются лексикографически по ключу в порядке возрастания.

OrderByKey

При использовании OrderByKey() для сортировки данных, данные возвращаются в порядке возрастания по ключу.

  1. В порядке возрастания первыми идут дочерние элементы, ключ которых может быть интерпретирован как 32-битное целое число.
  2. Далее следуют дети, у которых в качестве ключа используется строковое значение, отсортированные лексикографически в порядке возрастания.

OrderByValue

При использовании OrderByValue() дочерние узлы упорядочиваются по их значению. Критерии сортировки такие же, как и в OrderByChild() , за исключением того, что вместо значения указанного ключа дочернего узла используется значение самого узла.

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