Zapisz dane

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Zanim zaczniesz

Zanim będziesz mógł korzystać z Bazy danych czasu rzeczywistego , musisz:

  • Zarejestruj swój projekt Unity i skonfiguruj go do korzystania z Firebase.

    • Jeśli Twój projekt Unity korzysta już z Firebase, oznacza to, że jest już zarejestrowany i skonfigurowany dla Firebase.

    • Jeśli nie masz projektu Unity, możesz pobrać przykładową aplikację .

  • Dodaj zestaw Firebase Unity SDK (konkretnie FirebaseDatabase.unitypackage ) do swojego projektu Unity.

Pamiętaj, że dodanie Firebase do projektu Unity obejmuje zadania zarówno w konsoli Firebase , jak i w otwartym projekcie Unity (na przykład pobierasz pliki konfiguracyjne Firebase z konsoli, a następnie przenosisz je do projektu Unity).

Zapisywanie danych

Istnieje pięć metod zapisywania danych w bazie danych czasu rzeczywistego Firebase:

metoda Typowe zastosowania
SetValueAsync() Zapisz lub zastąp dane w zdefiniowanej ścieżce, takiej jak users/<user-id>/<username> .
SetRawJsonValueAsync() Zapisz lub zastąp dane nieprzetworzonym kodem Json, takim jak users/<user-id>/<username> .
Push() Dodaj do listy danych. Za każdym razem, gdy wywołujesz Push() , Firebase generuje unikalny klucz, którego można również użyć jako unikalnego identyfikatora, takiego jak user-scores/<user-id>/<unique-score-id> .
UpdateChildrenAsync() Zaktualizuj niektóre klucze dla zdefiniowanej ścieżki bez zastępowania wszystkich danych.
RunTransaction() Aktualizuj złożone dane, które mogą zostać uszkodzone przez równoczesne aktualizacje.

Pobierz DatabaseReference

Aby zapisać dane w bazie danych, potrzebujesz instancji 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;
  }
}

Zapisuj, aktualizuj lub usuwaj dane w odwołaniu

Podstawowe operacje zapisu

W przypadku podstawowych operacji zapisu można użyć SetValueAsync() do zapisania danych w określonym odwołaniu, zastępując wszelkie istniejące dane w tej ścieżce. Tej metody można użyć do przekazywania typów odpowiadających dostępnym typom JSON w następujący sposób:

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

Jeśli używasz obiektu C# z określonym typem, możesz użyć wbudowanej JsonUtility.ToJson() w celu przekonwertowania obiektu na surowy Json i wywołania SetRawJsonValueAsync() . Na przykład możesz mieć klasę User, która wyglądała następująco:

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

    public User() {
    }

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

Możesz dodać użytkownika za pomocą SetRawJsonValueAsync() w następujący sposób:

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);
}

Użycie SetValueAsync() lub SetRawJsonValueAsync() w ten sposób zastępuje dane w określonej lokalizacji, w tym wszelkie węzły podrzędne. Jednak nadal możesz zaktualizować obiekt podrzędny bez przepisywania całego obiektu. Jeśli chcesz zezwolić użytkownikom na aktualizowanie ich profili, możesz zaktualizować nazwę użytkownika w następujący sposób:

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

Dołącz do listy danych

Użyj metody Push() , aby dołączyć dane do listy w aplikacjach obsługujących wielu użytkowników. Metoda Push() generuje unikalny klucz za każdym razem, gdy do określonego odniesienia Firebase zostanie dodane nowe dziecko. Korzystając z tych automatycznie generowanych kluczy dla każdego nowego elementu na liście, kilku klientów może dodawać elementy podrzędne do tej samej lokalizacji w tym samym czasie bez konfliktów zapisu. Unikalny klucz generowany przez Push() jest oparty na znaczniku czasu, więc elementy listy są automatycznie uporządkowane chronologicznie.

Możesz użyć odwołania do nowych danych zwróconych przez metodę Push() , aby uzyskać wartość automatycznie wygenerowanego klucza lub zestawu danych dziecka. Wywołanie Key w odwołaniu Push() zwraca wartość automatycznie wygenerowanego klucza.

Zaktualizuj określone pola

Aby jednocześnie zapisywać do określonych elementów podrzędnych węzła bez zastępowania innych węzłów podrzędnych, należy użyć metody UpdateChildrenAsync() .

Podczas wywoływania UpdateChildrenAsync() można zaktualizować wartości podrzędne niższego poziomu, określając ścieżkę dla klucza. Jeśli dane są przechowywane w wielu lokalizacjach w celu lepszego skalowania, możesz zaktualizować wszystkie instancje tych danych, korzystając z funkcji rozkładania danych . Na przykład gra może mieć taką klasę 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<string, Object> ToDictionary() {
        Dictionary<string, Object> result = new Dictionary<string, Object>();
        result["uid"] = uid;
        result["score"] = score;

        return result;
    }
}

Aby utworzyć pozycję LeaderboardEntry i jednocześnie zaktualizować ją do ostatniego kanału wyników i własnej listy wyników użytkownika, gra używa następującego kodu:

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<string, Object> entryValues = entry.ToDictionary();

    Dictionary<string, Object> childUpdates = new Dictionary<string, Object>();
    childUpdates["/scores/" + key] = entryValues;
    childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

    mDatabase.UpdateChildrenAsync(childUpdates);
}

W tym przykładzie zastosowano Push() do utworzenia wpisu w węźle zawierającym wpisy dla wszystkich użytkowników w /scores/$key i jednoczesnego pobrania klucza za pomocą Key . Klucza można następnie użyć do utworzenia drugiego wpisu w wynikach użytkownika w /user-scores/$userid/$key .

Korzystając z tych ścieżek, można przeprowadzać jednoczesne aktualizacje w wielu lokalizacjach w drzewie JSON za pomocą jednego wywołania UpdateChildrenAsync() , na przykład w ten sposób tworzy nowy wpis w obu lokalizacjach. Jednoczesne aktualizacje przeprowadzane w ten sposób są niepodzielne: albo wszystkie aktualizacje powiodą się, albo wszystkie aktualizacje się nie powiodą.

Usunąć dane

Najprostszym sposobem usunięcia danych jest wywołanie RemoveValue() w odniesieniu do lokalizacji tych danych.

Możesz również usunąć, określając null jako wartość dla innej operacji zapisu, takiej jak SetValueAsync() lub UpdateChildrenAsync() . Możesz użyć tej techniki z UpdateChildrenAsync() , aby usunąć wiele elementów podrzędnych w jednym wywołaniu interfejsu API.

Dowiedz się, kiedy Twoje dane są przekazywane.

Aby wiedzieć, kiedy Twoje dane zostaną przekazane na serwer bazy danych czasu rzeczywistego Firebase, możesz dodać kontynuację. Zarówno SetValueAsync() , jak i UpdateChildrenAsync() zwracają Task , które pozwala wiedzieć, kiedy operacja została zakończona. Jeśli wywołanie zakończy się niepowodzeniem z jakiegokolwiek powodu, Tasks IsFaulted będzie miało wartość true z właściwością Exception wskazującą przyczynę niepowodzenia.

Zapisz dane jako transakcje

Podczas pracy z danymi, które mogą zostać uszkodzone przez jednoczesne modyfikacje, takie jak liczniki przyrostowe, można użyć operacji transakcyjnej . Nadajesz tej operacji Func . Ta aktualizacja Func przyjmuje bieżący stan danych jako argument i zwraca nowy żądany stan, który chcesz zapisać. Jeśli inny klient zapisze w lokalizacji przed pomyślnym zapisaniem nowej wartości, funkcja aktualizacji zostanie ponownie wywołana z nową bieżącą wartością i ponowiona zostanie próba zapisu.

Na przykład w grze możesz zezwolić użytkownikom na aktualizowanie tabeli liderów z pięcioma najwyższymi wynikami:

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

    leaderBoardRef.RunTransaction(mutableData => {
      List<object> leaders = mutableData.Value as List<object>

      if (leaders == null) {
        leaders = new List<object>();
      } else if (mutableData.ChildrenCount >= MaxScores) {
        long minScore = long.MaxValue;
        object minVal = null;
        foreach (var child in leaders) {
          if (!(child is Dictionary<string, object>)) continue;
          long childScore = (long)
                      ((Dictionary<string, object>)child)["score"];
          if (childScore < minScore) {
            minScore = childScore;
            minVal = child;
          }
        }
        if (minScore > 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<string, object> newScoreMap =
                       new Dictionary<string, object>();
      newScoreMap["score"] = score;
      newScoreMap["email"] = email;
      leaders.Add(newScoreMap);
      mutableData.Value = leaders;
      return TransactionResult.Success(mutableData);
    });
}

Korzystanie z transakcji zapobiega błędom tabeli liderów, jeśli wielu użytkowników rejestruje wyniki w tym samym czasie lub klient ma nieaktualne dane. Jeśli transakcja zostanie odrzucona, serwer zwraca aktualną wartość klientowi, który ponownie uruchamia transakcję ze zaktualizowaną wartością. Powtarza się to do momentu zaakceptowania transakcji lub podjęcia zbyt wielu prób.

Zapisuj dane offline

Jeśli klient utraci połączenie sieciowe, Twoja aplikacja będzie nadal działać poprawnie.

Każdy klient podłączony do bazy danych Firebase utrzymuje własną wewnętrzną wersję wszelkich aktywnych danych. Gdy dane są zapisywane, są one najpierw zapisywane w tej wersji lokalnej. Następnie klient Firebase synchronizuje te dane ze zdalnymi serwerami baz danych i innymi klientami na zasadzie „najlepszych starań”.

W rezultacie wszystkie zapisy do bazy danych natychmiast wyzwalają zdarzenia lokalne, zanim jakiekolwiek dane zostaną zapisane na serwerze. Oznacza to, że Twoja aplikacja pozostaje responsywna niezależnie od opóźnienia sieci lub łączności.

Po przywróceniu łączności aplikacja otrzymuje odpowiedni zestaw zdarzeń, dzięki czemu klient synchronizuje się z bieżącym stanem serwera bez konieczności pisania niestandardowego kodu.

Następne kroki