Сохранить данные

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

Прежде чем использовать Realtime Database , вам необходимо:

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

    • Если ваш проект Unity уже использует Firebase, значит, он уже зарегистрирован и настроен для Firebase.

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

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

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

Сохранение данных

Существует пять методов записи данных в Firebase Realtime Database :

Метод Распространенные применения
SetValueAsync() Запишите или замените данные по определенному пути, например, users/<user-id>/<username> .
SetRawJsonValueAsync() Запишите или замените данные необработанным Json, например users/<user-id>/<username> .
Push() Добавление данных в список. Каждый раз при вызове Push() Firebase генерирует уникальный ключ, который также можно использовать как уникальный идентификатор, например, user-scores/<user-id>/<unique-score-id> .
UpdateChildrenAsync() Обновить некоторые ключи для определенного пути без замены всех данных.
RunTransaction() Обновляйте сложные данные, которые могут быть повреждены одновременными обновлениями.

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

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

using Firebase;
using Firebase.Database;

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

Запись, обновление или удаление данных по ссылке

Базовые операции записи

Для базовых операций записи можно использовать SetValueAsync() для сохранения данных по указанной ссылке, заменяя любые существующие данные по этому пути. Этот метод можно использовать для передачи типов, соответствующих доступным типам JSON, следующим образом:

  • string
  • long
  • double
  • bool
  • Dictionary<string, Object>
  • List<Object>

Если вы используете типизированный объект C#, вы можете использовать встроенную функцию JsonUtility.ToJson() для преобразования объекта в необработанный JSON и вызвать SetRawJsonValueAsync() . Например, у вас может быть класс User, который выглядит следующим образом:

public class User {
    public string username;
    public string email;

    public User() {
    }

    public User(string username, string email) {
        this.username = username;
        this.email = email;
    }
}

Вы можете добавить пользователя с помощью SetRawJsonValueAsync() следующим образом:

private void writeNewUser(string userId, string name, string email) {
    User user = new User(name, email);
    string json = JsonUtility.ToJson(user);

    mDatabaseRef.Child("users").Child(userId).SetRawJsonValueAsync(json);
}

Использование SetValueAsync() или SetRawJsonValueAsync() таким образом перезаписывает данные в указанном месте, включая все дочерние узлы. Однако вы всё равно можете обновить дочерний элемент, не переписывая весь объект. Если вы хотите разрешить пользователям обновлять свои профили, вы можете обновить имя пользователя следующим образом:

mDatabaseRef.Child("users").Child(userId).Child("username").SetValueAsync(name);

Добавить к списку данных

Используйте метод Push() для добавления данных в список в многопользовательских приложениях. Метод Push() генерирует уникальный ключ каждый раз при добавлении нового дочернего элемента в указанную ссылку Firebase. Используя эти автоматически сгенерированные ключи для каждого нового элемента в списке, несколько клиентов могут добавлять дочерние элементы в одно и то же место одновременно без конфликтов записи. Уникальный ключ, генерируемый методом Push() , основан на временной метке, поэтому элементы списка автоматически упорядочиваются в хронологическом порядке.

Вы можете использовать ссылку на новые данные, возвращаемые методом Push() чтобы получить значение автоматически сгенерированного ключа дочернего элемента или задать данные для него. Вызов метода Key для ссылки Push() возвращает значение автоматически сгенерированного ключа.

Обновить определенные поля

Для одновременной записи в определенные дочерние узлы узла без перезаписи других дочерних узлов используйте метод UpdateChildrenAsync() .

При вызове метода UpdateChildrenAsync() можно обновить значения дочерних элементов нижнего уровня, указав путь к ключу. Если данные хранятся в нескольких местах для лучшего масштабирования, можно обновить все экземпляры этих данных, используя функцию data fan-out . Например, в игре может быть класс LeaderboardEntry , подобный этому:

public class LeaderboardEntry {
    public string uid;
    public int score = 0;

    public LeaderboardEntry() {
    }

    public LeaderboardEntry(string uid, int score) {
        this.uid = uid;
        this.score = score;
    }

    public Dictionary&ltstring, Object&gt ToDictionary() {
        Dictionary&ltstring, Object&gt result = new Dictionary&ltstring, Object&gt();
        result["uid"] = uid;
        result["score"] = score;

        return result;
    }
}

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

private void WriteNewScore(string userId, int score) {
    // Create new entry at /user-scores/$userid/$scoreid and at
    // /leaderboard/$scoreid simultaneously
    string key = mDatabase.Child("scores").Push().Key;
    LeaderBoardEntry entry = new LeaderBoardEntry(userId, score);
    Dictionary&ltstring, Object&gt entryValues = entry.ToDictionary();

    Dictionary&ltstring, Object&gt childUpdates = new Dictionary&ltstring, Object&gt();
    childUpdates["/scores/" + key] = entryValues;
    childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

    mDatabase.UpdateChildrenAsync(childUpdates);
}

В этом примере метод Push() используется для создания записи в узле, содержащем записи всех пользователей в /scores/$key , и одновременного извлечения ключа с помощью Key . Затем этот ключ можно использовать для создания второй записи в результатах пользователя в /user-scores/$userid/$key .

Используя эти пути, вы можете выполнять одновременные обновления нескольких локаций в дереве JSON одним вызовом UpdateChildrenAsync() , например, как в этом примере создаётся новая запись в обеих локациях. Одновременные обновления, выполненные таким образом, являются атомарными: либо все обновления выполнены успешно, либо все обновления завершены неудачей.

Удалить данные

Самый простой способ удалить данные — вызвать RemoveValue() для ссылки на местоположение этих данных.

Вы также можете удалить элемент, указав значение null в качестве значения для другой операции записи, например SetValueAsync() или UpdateChildrenAsync() . Этот метод можно использовать с UpdateChildrenAsync() для удаления нескольких дочерних элементов за один вызов API.

Знайте, когда ваши данные передаются.

Чтобы узнать, когда данные будут переданы на сервер Firebase Realtime Database , можно добавить продолжение. Методы SetValueAsync() и UpdateChildrenAsync() возвращают Task , позволяющую узнать, когда операция завершена. Если вызов по какой-либо причине не удался, свойство Task IsFaulted будет иметь значение true, а свойство Exception укажет причину сбоя.

Сохранить данные как транзакции

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

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

private void AddScoreToLeaders(string email, 
                               long score,
                               DatabaseReference leaderBoardRef) {

    leaderBoardRef.RunTransaction(mutableData =&gt {
      List&ltobject&gt leaders = mutableData.Value as List&ltobject>

      if (leaders == null) {
        leaders = new List&ltobject&gt();
      } else if (mutableData.ChildrenCount &gt= MaxScores) {
        long minScore = long.MaxValue;
        object minVal = null;
        foreach (var child in leaders) {
          if (!(child is Dictionary&ltstring, object&gt)) continue;
          long childScore = (long)
                      ((Dictionary&ltstring, object&gt)child)["score"];
          if (childScore &lt minScore) {
            minScore = childScore;
            minVal = child;
          }
        }
        if (minScore &gt score) {
          // The new score is lower than the existing 5 scores, abort.
          return TransactionResult.Abort();
        }

        // Remove the lowest score.
        leaders.Remove(minVal);
      }

      // Add the new high score.
      Dictionary&ltstring, object&gt newScoreMap =
                       new Dictionary&ltstring, object&gt();
      newScoreMap["score"] = score;
      newScoreMap["email"] = email;
      leaders.Add(newScoreMap);
      mutableData.Value = leaders;
      return TransactionResult.Success(mutableData);
    });
}

Использование транзакций предотвращает некорректность таблицы лидеров, если несколько пользователей одновременно регистрируют результаты или данные клиента устарели. Если транзакция отклонена, сервер возвращает клиенту текущее значение, и тот снова запускает транзакцию с обновлённым значением. Это повторяется до тех пор, пока транзакция не будет принята или пока не будет сделано слишком много попыток.

Запись данных в автономном режиме

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

Каждый клиент, подключенный к базе данных Firebase, хранит собственную внутреннюю версию любых активных данных. При записи данных они сначала записываются в эту локальную версию. Затем клиент Firebase синхронизирует эти данные с удаленными серверами баз данных и другими клиентами по принципу «максимальных усилий».

В результате все записи в базу данных запускают локальные события немедленно, ещё до того, как данные будут записаны на сервер. Это означает, что ваше приложение остаётся отзывчивым независимо от задержек в сети или проблем с подключением.

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

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