Как получать данные с помощью 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() Упорядочить результаты по дочерним значениям.

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

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

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

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