Как получать данные с помощью Firebase Realtime Database для C++

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

Подготовка

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

Извлечение данных

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

Как получить DatabaseReference

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

  // 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() Сортировать результаты по значениям дочерних элементов.

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

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

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

OrderByKey

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

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

OrderByValue

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

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