Iniziare
Consulta prima la Guida Get Started
se non hai ancora configurato la tua app e l'accesso al database.
Ottieni un riferimento al database
Per scrivere i dati nel database, è necessaria 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 i dati nel database in tempo reale di Firebase:
Metodo | Usi comuni |
---|---|
SetValue() | Scrivere o sostituire i dati in un percorso definito, ad esempio users/<user-id>/<username> . |
PushChild() | Aggiungi 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() | Aggiorna dati complessi che potrebbero essere danneggiati da aggiornamenti simultanei. |
Scrivere, aggiornare o eliminare i dati in un riferimento
Operazioni di scrittura di base
Per le operazioni di scrittura di base, è possibile utilizzare SetValue()
per salvare i dati in un riferimento specificato, sostituendo i dati esistenti in quel percorso. Puoi utilizzare questo metodo per passare i tipi accettati da JSON attraverso un tipo Variant che supporta:
- Null (questo elimina i dati)
- Numeri interi (64 bit)
- Numeri in virgola mobile a doppia precisione
- Booleani
- stringhe
- Vettori di varianti
- Mappe delle stringhe alle varianti
L'utilizzo SetValue()
in questo modo sovrascrive i dati nella posizione specificata, inclusi eventuali nodi figlio. Tuttavia, puoi ancora aggiornare un figlio senza riscrivere l'intero oggetto. Se desideri consentire agli utenti di aggiornare i loro profili, puoi aggiornare il nome utente come segue:
dbref.Child("users").Child(userId).Child("username").SetValue(name);
Aggiungi a un elenco di dati
Utilizzare il metodo PushChild()
per aggiungere dati a un elenco nelle applicazioni multiutente. Il metodo PushChild()
genera una chiave univoca ogni volta che viene aggiunto un nuovo figlio al riferimento Firebase specificato. Utilizzando queste chiavi generate automaticamente per ogni nuovo elemento nell'elenco, diversi client possono aggiungere figli alla stessa posizione contemporaneamente senza conflitti di scrittura. La chiave univoca generata da PushChild()
si basa su un timestamp, quindi gli elementi dell'elenco vengono automaticamente ordinati cronologicamente.
È possibile utilizzare il riferimento ai nuovi dati restituiti dal metodo PushChild()
per ottenere il valore della chiave generata automaticamente del figlio o impostare i dati per il figlio. La chiamata GetKey()
su un riferimento PushChild()
restituisce il valore della chiave generata automaticamente.
Aggiorna campi specifici
Per scrivere simultaneamente su elementi figlio specifici di un nodo senza sovrascrivere altri nodi figlio, utilizzare il metodo UpdateChildren()
.
Quando si chiama UpdateChildren()
, è possibile aggiornare i valori figlio 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 di tali dati utilizzando il fan-out 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 una LeaderboardEntry
e aggiornarla contemporaneamente al feed dei punteggi recenti e all'elenco dei punteggi 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); }
Questo esempio utilizza PushChild()
per creare una voce nel nodo contenente voci per tutti gli utenti in /scores/$key
e contemporaneamente recuperare la chiave con key()
. La chiave può quindi essere utilizzata per creare una seconda voce nei punteggi dell'utente in /user-scores/$userid/$key
.
Utilizzando questi percorsi, puoi eseguire aggiornamenti simultanei in più posizioni nell'albero JSON con una singola chiamata a UpdateChildren()
, ad esempio come questo esempio crea la nuova voce in entrambe le posizioni. Gli aggiornamenti simultanei effettuati in questo modo sono atomici: o tutti gli aggiornamenti riescono o tutti gli aggiornamenti falliscono.
Elimina dati
Il modo più semplice per eliminare i dati consiste nel chiamare RemoveValue()
su un riferimento alla posizione di tali dati.
È inoltre possibile eliminare specificando Variant
null
come valore per un'altra operazione di scrittura come SetValue()
o UpdateChildren()
. Puoi utilizzare questa tecnica con UpdateChildren()
per eliminare più figli in una singola chiamata API.
Sapere quando i tuoi dati sono impegnati.
Per sapere quando i tuoi dati vengono sottoposti a commit nel server Firebase Realtime Database, verifica che il risultato Futuro abbia esito positivo.
Salva i dati come transazioni
Quando si lavora con dati che potrebbero essere danneggiati da modifiche simultanee, come i contatori incrementali, è possibile utilizzare un'operazione di transazione . Si assegna a questa operazione una funzione DoTransaction
. Questa funzione di aggiornamento prende lo stato corrente dei dati come argomento e restituisce il nuovo stato desiderato che si desidera scrivere. Se un altro client scrive nella posizione prima che il nuovo valore sia stato scritto correttamente, la funzione di aggiornamento viene chiamata di nuovo con il nuovo valore corrente e la scrittura viene ritentata.
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 punteggi contemporaneamente o il client dispone di dati obsoleti. Se la transazione viene rifiutata, il server restituisce il valore corrente al client, che esegue nuovamente la transazione con il valore aggiornato. Ciò si ripete fino a quando la transazione non viene accettata o sono stati effettuati troppi tentativi.
Scrivi dati offline
Se un client perde la connessione di rete, la tua app continuerà a funzionare correttamente.
Ogni client 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 tali dati con i server di database remoti e con altri client in base al "massimo sforzo".
Di conseguenza, tutte le scritture nel database attivano immediatamente gli eventi locali, prima che i dati vengano scritti nel server. Ciò significa che la tua app rimane reattiva indipendentemente dalla latenza di rete o dalla connettività.
Una volta ristabilita la connettività, la tua app riceve il set di eventi appropriato in modo che il client si sincronizzi con lo stato del server corrente, senza dover scrivere alcun codice personalizzato.