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

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

Подготовка

Чтобы использовать Realtime Database, необходимо:

  • Зарегистрируйте проект Unity и настройте его для использования Firebase.

    • Если в проекте уже используется Firebase, можете пропустить этот шаг.

    • Если у вас нет проекта Unity, вы можете скачать пример приложения.

  • Добавьте в свой проект Unity Unity SDK для Firebase (в частности, FirebaseDatabase.unitypackage).

Обратите внимание, что для добавления Firebase в проект Unity нужно выполнить действия как в консоли Firebase, так и в вашем открытом проекте Unity. Например, вам потребуется скачать файлы конфигурации Firebase из консоли, а затем переместить их в проект Unity.

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

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

Получение DatabaseReference

Чтобы считать данные из базы данных, вам нужен экземпляр DatabaseReference:

using Firebase;
using Firebase.Database;
using Firebase.Extensions.TaskExtension; // for ContinueWithOnMainThread

public class MyScript: MonoBehaviour {
  void Start() {
    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

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

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

    FirebaseDatabase.DefaultInstance
      .GetReference("Leaders")
      .GetValueAsync().ContinueWithOnMainThread(task =&gt {
        if (task.IsFaulted) {
          // Handle the error...
        }
        else if (task.IsCompleted) {
          DataSnapshot snapshot = task.Result;
          // Do something with snapshot...
        }
      });

Прослушивание событий

Вы можете добавить прослушиватели событий, чтобы подписаться на изменения данных:

Событие Типичное использование
ValueChanged Чтение и отслеживание изменений всего содержимого пути.
ChildAdded Получать списки объектов или слушать дополнения к списку объектов. Рекомендуется использовать с ChildChanged и ChildRemoved, чтобы отслеживать изменения в списках.
ChildChanged Отслеживание изменений элементов в списке. Используйте вместе с ChildAdded и ChildRemoved, чтобы отслеживать изменения в списках.
ChildRemoved Прослушивание событий удаления элементов из списка. Используйте вместе с ChildAdded и ChildChanged, чтобы отслеживать изменения в списках.
ChildMoved Отслеживать изменения в порядке элементов в упорядоченном списке. События ChildMoved всегда следуют за событием ChildChanged, которое привело к изменению порядка элементов (в соответствии с текущим способом сортировки).

Событие ValueChanged

Чтобы подписаться на изменения контента по заданному пути, используйте событие ValueChanged. Это событие запускается один раз при подключении прослушивателя и затем каждый раз, когда изменяются данные, включая дочерние. Обратному вызову события передается снимок, содержащий все данные в этом местоположении, включая дочерние данные. Если данных нет, возвращается снимок null.

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

ValueChangedEventArgs содержит DataSnapshot с данными в указанном месте базы данных на момент события. Вызов Value для снимка возвращает Dictionary<string, object>, представляющий данные. Если в указанном месте нет данных, вызов Value возвращает null.

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

Позже вы можете отменить подписку на событие, используя любой объект DatabaseReference с тем же путем. Экземпляры DatabaseReference недолговечны и могут рассматриваться как способ доступа к любому пути и запросу.

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged -= HandleValueChanged; // unsubscribe from ValueChanged.
    }

Дочерние события

Дочерние события активируются в ответ на определенные операции, которые происходят с дочерними элементами узла, например добавление нового дочернего элемента с помощью метода Push() или обновление дочернего элемента с помощью метода UpdateChildrenAsync(). Каждый из них может быть полезен для прослушивания изменений в определенном узле базы данных. Например, в игре эти методы могут использоваться вместе для отслеживания активности в комментариях к игровому сеансу, как показано ниже:

      var ref = FirebaseDatabase.DefaultInstance
      .GetReference("GameSessionComments");

      ref.ChildAdded += HandleChildAdded;
      ref.ChildChanged += HandleChildChanged;
      ref.ChildRemoved += HandleChildRemoved;
      ref.ChildMoved += HandleChildMoved;
    }

    void HandleChildAdded(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildChanged(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildRemoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildMoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

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

Событие ChildChanged вызывается каждый раз, когда изменяется дочерний узел. Это относится и к изменениям дочерних узлов. Обычно он используется вместе с событиями ChildAdded и ChildRemoved, чтобы реагировать на изменения в списке элементов. Снимок, переданный прослушивателю событий, содержит обновленные данные для дочернего объекта.

Событие ChildRemoved активируется, когда удаляется дочерний элемент. Обычно он используется вместе с обратными вызовами ChildAdded и ChildChanged. Объект snapshot, переданный обратному вызову события, содержит данные удаленного дочернего элемента.

Событие ChildMoved активируется каждый раз, когда событие ChildChanged вызывается обновлением, которое приводит к изменению порядка дочерних элементов. Используется с данными, упорядоченными с помощью OrderByChild или OrderByValue.

Сортировка и фильтрация данных

Вы можете использовать класс Realtime Database Query, чтобы получать данные, отсортированные по ключу, значению или значению дочернего элемента. Вы также можете отфильтровать отсортированный результат по определенному количеству результатов или диапазону ключей или значений.

Отсортировать данные

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

Метод Использование
OrderByChild() Упорядочить результаты по значению указанного дочернего ключа.
OrderByKey() Упорядочить результаты по дочерним ключам.
OrderByValue() Упорядочить результаты по дочерним значениям.

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

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

Это определяет запрос, который в сочетании с прослушивателем событий valuechanged синхронизирует клиент с таблицей лидеров в базе данных, упорядоченной по оценке каждой записи. Подробнее о том, как эффективно структурировать данные в базе данных…

Вызов метода OrderByChild() указывает дочерний ключ, по которому нужно упорядочить результаты. В этом случае результаты сортируются по значению "score" в каждом дочернем элементе. Подробнее о том, как упорядочиваются данные запросов…

Фильтрация данных

Чтобы отфильтровать данные, вы можете комбинировать любые методы ограничения или диапазона со способом сортировки при создании запроса.

Метод Использование
LimitToFirst() Задает максимальное количество элементов, которые будут возвращены из начала упорядоченного списка результатов.
LimitToLast() Задает максимальное количество элементов, которые будут возвращены из конца упорядоченного списка результатов.
StartAt() Возвращает элементы, которые больше или равны указанному ключу или значению в зависимости от выбранного способа сортировки.
EndAt() Возвращает объекты, которые меньше или равны указанному ключу или значению в зависимости от выбранного способа сортировки.
EqualTo() Возвращает элементы, равные указанному ключу или значению в зависимости от выбранного способа сортировки.

В отличие от способов сортировки, вы можете комбинировать несколько функций ограничения или диапазона. Например, вы можете объединить методы StartAt() и EndAt(), чтобы ограничить результаты определенным диапазоном значений.

Даже если запросу соответствует только один элемент, снимок все равно будет списком, просто с одним элементом.

Ограничение количества результатов

С помощью методов LimitToFirst() и LimitToLast() можно задать максимальное количество дочерних элементов, которые будут синхронизироваться для определенного обратного вызова. Например, если вы используете LimitToFirst(), чтобы установить ограничение в 100, вы сначала получите только до 100 обратных вызовов ChildAdded. Если в базе данных Firebase хранится менее 100 элементов, обратный вызов ChildAdded срабатывает для каждого элемента.

По мере изменения элементов вы получаете обратные вызовы ChildAdded для элементов, которые входят в запрос, и обратные вызовы ChildRemoved для элементов, которые выпадают из него, так что общее число остается равным 100.

Например, следующий код возвращает лучший результат из таблицы лидеров:

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score").LimitToLast(1)
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

Фильтр по ключу или значению

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