Zaczynaj
Najpierw zapoznaj się z przewodnikiem Get Started
, jeśli nie masz jeszcze skonfigurowanej aplikacji i dostępu do bazy danych.
Pobierz DatabaseReference
Aby zapisać dane w bazie danych, potrzebujesz instancji DatabaseReference
:
// Get the root reference location of the database. firebase::database::DatabaseReference dbref = database->GetReference();
Zapisywanie danych
Istnieją cztery metody zapisywania danych w bazie danych czasu rzeczywistego Firebase:
metoda | Typowe zastosowania |
---|---|
SetValue() | Zapisz lub zastąp dane w zdefiniowanej ścieżce, takiej jak users/<user-id>/<username> . |
PushChild() | 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> . |
UpdateChildren() | 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. |
Zapisuj, aktualizuj lub usuwaj dane w odwołaniu
Podstawowe operacje zapisu
W przypadku podstawowych operacji zapisu można użyć SetValue()
w celu zapisania danych do określonego odwołania, zastępując wszelkie istniejące dane w tej ścieżce. Możesz użyć tej metody, aby przekazać typy akceptowane przez JSON przez typ Variant, który obsługuje:
- Null (to usuwa dane)
- Liczby całkowite (64-bitowe)
- Liczby zmiennoprzecinkowe podwójnej precyzji
- Logiczne
- Smyczki
- Wektory wariantów
- Mapy ciągów znaków na warianty
Użycie SetValue()
w ten sposób nadpisuje 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:
dbref.Child("users").Child(userId).Child("username").SetValue(name);
Dołącz do listy danych
Użyj metody PushChild()
, aby dołączyć dane do listy w aplikacjach obsługujących wielu użytkowników. Metoda PushChild()
generuje unikalny klucz za każdym razem, gdy do określonego odwołania 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 PushChild()
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ę PushChild()
, aby uzyskać wartość automatycznie wygenerowanego klucza lub zestawu danych dziecka. Wywołanie metody GetKey()
na odwołaniu PushChild()
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 UpdateChildren()
.
Wywołując metodę UpdateChildren()
, możesz 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
:
class LeaderboardEntry { std::string uid; int score = 0; public: LeaderboardEntry() { } LeaderboardEntry(std::string uid, int score) { this->uid = uid; this->score = score; } std::map<std::string, Object> ToMap() { std::map<string, Variant> result = new std::map<string, Variant>(); result["uid"] = Variant(uid); result["score"] = Variant(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:
void WriteNewScore(std::string userId, int score) { // Create new entry at /user-scores/$userid/$scoreid and at // /leaderboard/$scoreid simultaneously std::string key = dbref.Child("scores").PushChild().GetKey(); LeaderBoardEntry entry = new LeaderBoardEntry(userId, score); std::map<std::string, Variant> entryValues = entry.ToMap(); std::map<string, Variant> childUpdates = new std::map<string, Variant>(); childUpdates["/scores/" + key] = entryValues; childUpdates["/user-scores/" + userId + "/" + key] = entryValues; dbref.UpdateChildren(childUpdates); }
W tym przykładzie zastosowano PushChild()
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 UpdateChildren()
, 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 metody RemoveValue()
w odniesieniu do lokalizacji tych danych.
Możesz również usunąć, określając wartość null
Variant
jako wartość dla innej operacji zapisu, takiej jak SetValue()
lub UpdateChildren()
. Możesz użyć tej techniki z UpdateChildren()
, aby usunąć wiele dzieci w jednym wywołaniu API.
Dowiedz się, kiedy Twoje dane są przekazywane.
Aby dowiedzieć się, kiedy Twoje dane zostaną przekazane na serwer Bazy danych czasu rzeczywistego Firebase, sprawdź wynik Przyszłość , aby sprawdzić, czy się powiodło.
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 funkcję DoTransaction
. Ta funkcja aktualizacji przyjmuje jako argument bieżący stan danych 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:
void AddScoreToLeaders(std::string email, long score, DatabaseReference leaderBoardRef) { leaderBoardRef.RunTransaction([](firebase::database::MutableData* mutableData) { if (mutableData.children_count() >= MaxScores) { long minScore = LONG_MAX; MutableData *minVal = null; std::vector<MutableData> children = mutableData.children(); std::vector<MutableData>::iterator it; for (it = children.begin(); it != children.end(); ++it) { if (!it->value().is_map()) continue; long childScore = (long)it->Child("score").value().int64_value(); if (childScore < minScore) { minScore = childScore; minVal = &*it; } } if (minScore > score) { // The new score is lower than the existing 5 scores, abort. return kTransactionResultAbort; } // Remove the lowest score. children.Remove(minVal); } // Add the new high score. std::map<std::string, Variant> newScoreMap = new std::map<std::string, Variant>(); newScoreMap["score"] = score; newScoreMap["email"] = email; children.Add(newScoreMap); mutableData->set_value(children); return kTransactionResultSuccess; }); }
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.