Inizia
Consulta prima la guida Get Started
se non hai ancora configurato l'app e l'accesso al database.
Recuperare un DatabaseReference
Per scrivere dati nel database, devi avere un'istanza di DatabaseReference
:
// Get the root reference location of the database. firebase::database::DatabaseReference dbref = database->GetReference();
Salvataggio dei dati
Esistono quattro metodi per scrivere dati in Firebase Realtime Database:
Metodo | Utilizzi comuni |
---|---|
SetValue() |
Scrivere o sostituire i dati in un percorso definito, ad esempio
users/<user-id>/<username> . |
PushChild() |
Aggiungere elementi a un elenco di dati. Ogni volta che chiami
Push() , Firebase genera una chiave univoca che può essere utilizzata anche come identificatore univoco, ad esempio
user-scores/<user-id>/<unique-score-id> . |
UpdateChildren() |
Aggiorna alcune delle chiavi per un percorso definito senza sostituire tutti i dati. |
RunTransaction() |
Aggiornare dati complessi che potrebbero essere danneggiati da aggiornamenti simultanei. |
Scrivere, aggiornare o eliminare dati in un riferimento
Operazioni di scrittura di base
Per le operazioni di scrittura di base, puoi utilizzare SetValue()
per salvare i dati in un riferimento specificato, sostituendo eventuali dati esistenti in quel percorso. Puoi utilizzare questo metodo per passare i tipi accettati da JSON tramite un tipo di variante che supporta:
- Null (viene eliminato il dato)
- Numeri interi (64 bit)
- Numeri a virgola mobile a precisione doppia
- Valori booleani
- Stringhe
- Vettori delle varianti
- Mappe di stringhe a Varianti
L'utilizzo di SetValue()
in questo modo sovrascrive i dati nella posizione specificata, inclusi eventuali nodi secondari. Tuttavia, puoi comunque aggiornare un asset secondario
senza riscrivere l'intero oggetto. Se vuoi consentire agli utenti di aggiornare i propri profili, puoi aggiornare il nome utente come segue:
dbref.Child("users").Child(userId).Child("username").SetValue(name);
Aggiungere elementi a un elenco di dati
Utilizza il metodo PushChild()
per accodare dati a un elenco in applicazioni multiutente.
Il metodo PushChild()
genera una chiave univoca ogni volta che viene aggiunto un nuovo asset secondario al riferimento Firebase specificato. Utilizzando queste chiavi generate automaticamente per ogni nuovo elemento dell'elenco, diversi client possono aggiungere contemporaneamente elementi figlio alla stessa località senza conflitti di scrittura. La chiave unica generata da PushChild()
si basa su un timestamp, pertanto gli elementi dell'elenco vengono ordinati automaticamente in ordine cronologico.
Puoi utilizzare il riferimento ai nuovi dati restituiti dal metodo PushChild()
per recuperare il valore della chiave generata automaticamente dell'elemento secondario o impostare i dati per l'elemento secondario.
La chiamata di GetKey()
su un riferimento PushChild()
restituisce il valore della chiave generata automaticamente.
Aggiornare campi specifici
Per scrivere contemporaneamente in nodi secondari specifici di un nodo senza sovrascrivere altri nodi secondari, utilizza il metodo UpdateChildren()
.
Quando chiami UpdateChildren()
, puoi aggiornare i valori secondari di livello inferiore specificando un percorso per la chiave. Se i dati vengono archiviati in più posizioni per una migliore scalabilità, puoi aggiornare tutte le istanze utilizzando la distribuzione dei dati. Ad esempio, un gioco potrebbe avere una classe LeaderboardEntry
come questa:
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; } }
Per creare un LeaderboardEntry
e aggiornarlo contemporaneamente nel feed dei risultati recenti e nell'elenco dei risultati dell'utente, il gioco utilizza il seguente codice:
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); }
In questo esempio viene utilizzato PushChild()
per creare una voce nel nodo contenente
le voci per tutti gli utenti in /scores/$key
e recuperare contemporaneamente la chiave con
key()
. La chiave può quindi essere utilizzata per creare una seconda voce nei
voti dell'utente in /user-scores/$userid/$key
.
Utilizzando questi percorsi, puoi eseguire aggiornamenti simultanei a più località nell'albero JSON con una singola chiamata a UpdateChildren()
, ad esempio il modo in cui questo esempio crea la nuova voce in entrambe le località. Gli aggiornamenti simultanei apportati in questo modo sono atomici: o tutti gli aggiornamenti vanno a buon fine o tutti non vanno a buon fine.
Elimina dati
Il modo più semplice per eliminare i dati è chiamare RemoveValue()
su un riferimento alla loro posizione.
Puoi anche eseguire l'eliminazione specificando un Variant
null
come valore per un'altra operazione di scrittura, ad esempio SetValue()
o UpdateChildren()
. Puoi utilizzare questa
tecnica con UpdateChildren()
per eliminare più elementi secondari in una singola
chiamata API.
Scopri quando i dati vengono sottoposti a commit.
Per sapere quando i dati vengono applicati al server Firebase Realtime Database, controlla il risultato Future per verificare che l'operazione sia andata a buon fine.
Salvare i dati come transazioni
Quando lavori con dati che potrebbero essere danneggiati da modifiche simultanee, ad esempio i contatori incrementali, puoi utilizzare un'operazione di transazione.
Assegna a questa operazione una funzione DoTransaction
. Questa funzione di aggiornamento prende come argomento lo stato corrente dei dati e restituisce il nuovo stato desiderato che vuoi scrivere. Se un altro client scrive nella posizione prima che il nuovo valore venga scritto correttamente, la funzione di aggiornamento viene richiamata di nuovo con il nuovo valore corrente e la scrittura viene riprovata.
Ad esempio, in un gioco puoi consentire agli utenti di aggiornare una classifica con i cinque punteggi più alti:
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; }); }
L'utilizzo di una transazione impedisce che la classifica sia errata se più utenti registrano i punteggi contemporaneamente o se il client ha dati obsoleti. Se la transazione viene rifiutata, il server restituisce il valore corrente al client, che esegue di nuovo la transazione con il valore aggiornato. L'operazione viene ripetuta fino a quando la transazione non viene accettata o non sono stati effettuati troppi tentativi.
Scrivi dati offline
Se un client perde la connessione di rete, l'app continua a funzionare correttamente.
Ogni cliente connesso a un database Firebase mantiene la propria versione interna di tutti i dati attivi. Quando i dati vengono scritti, vengono prima scritti in questa versione locale. Il client Firebase sincronizza quindi i dati con i server database remoto e con altri client in base al criterio "best effort".
Di conseguenza, tutte le scritture nel database attivano immediatamente gli eventi locali, prima che qualsiasi dato venga scritto sul server. Ciò significa che la tua app rimane dinamica indipendentemente dalla latenza o dalla connettività di rete.
Una volta ripristinata la connettività, l'app riceve l'insieme appropriato di eventi in modo che il client si sincronizzi con lo stato attuale del server, senza dover scrivere codice personalizzato.