Prima di iniziare
Prima di poter utilizzare Realtime Database, devi:
Registrare il tuo progetto Unity e configurarlo in modo che utilizzi Firebase.
Se il tuo progetto Unity utilizza già Firebase, è già registrato e configurato per Firebase.
Se non hai un progetto Unity, puoi scaricare un' app di esempio.
Aggiungere Firebase Unity SDK (in particolare,
FirebaseDatabase.unitypackage) al tuo progetto Unity.
Tieni presente che l'aggiunta di Firebase al tuo progetto Unity comporta attività sia nella Firebase console sia nel progetto Unity aperto (ad esempio, scarichi i file di configurazione Firebase dalla console, quindi sposti i file nel progetto Unity).
Strutturazione dei dati
Questa guida illustra alcuni dei concetti chiave dell'architettura dei dati e le best practice per la strutturazione dei dati JSON in Firebase Realtime Database.
La creazione di un database con una struttura corretta richiede una certa pianificazione. La cosa più importante è pianificare la modalità di salvataggio e recupero dei dati per semplificare il più possibile la procedura.
Come sono strutturati i dati: un albero JSON
Tutti i dati Firebase Realtime Database vengono archiviati come oggetti JSON. Puoi considerare il database come un albero JSON ospitato nel cloud. A differenza di un database SQL, non esistono tabelle o record. Quando aggiungi dati all'albero JSON, questi diventano un nodo nella struttura JSON esistente con una chiave associata. Puoi fornire le tue chiavi, come ID utente o nomi semantici, oppure possono essere fornite utilizzando il metodo Push().
Ad esempio, considera un'applicazione di chat che consente agli utenti di archiviare un profilo di base e un elenco contatti. Un profilo utente tipico si trova in un percorso, ad esempio /users/$uid. L'utente alovelace potrebbe avere una voce di database simile alla seguente:
{ "users": { "alovelace": { "name": "Ada Lovelace", "contacts": { "ghopper": true }, }, "ghopper": { "..." }, "eclarke": { "..." } } }
Sebbene il database utilizzi un albero JSON, i dati archiviati nel database possono essere rappresentati come determinati tipi nativi che corrispondono ai tipi JSON disponibili per aiutarti a scrivere codice più gestibile.
Best practice per la struttura dei dati
Evita di nidificare i dati
Poiché Firebase Realtime Database consente di nidificare i dati fino a 32 livelli di profondità, potresti essere tentato di pensare che questa dovrebbe essere la struttura predefinita. Tuttavia, quando recuperi i dati in una posizione del database, recuperi anche tutti i relativi nodi secondari. Inoltre, quando concedi a qualcuno l'accesso in lettura o scrittura a un nodo del database, gli concedi anche l'accesso a tutti i dati sotto quel nodo. Pertanto, in pratica, è preferibile mantenere la struttura dei dati il più piatta possibile.
Per un esempio del motivo per cui i dati nidificati sono negativi, considera la seguente struttura a più livelli:
{ // This is a poorly nested data architecture, because iterating the children // of the "chats" node to get a list of conversation titles requires // potentially downloading hundreds of megabytes of messages "chats": { "one": { "title": "Historical Tech Pioneers", "messages": { "m1": { "sender": "ghopper", "message": "Relay malfunction found. Cause: moth." }, "m2": { ... }, // a very long list of messages } }, "two": { "..." } } }
Con questa struttura nidificata, l'iterazione dei dati diventa problematica. Ad esempio, per elencare i titoli delle conversazioni di chat è necessario scaricare l'intero albero chats, inclusi tutti i membri e i messaggi, sul client.
Appiattisci le strutture dei dati
Se i dati vengono suddivisi in percorsi separati, chiamati anche denormalizzazione, possono essere scaricati in modo efficiente in chiamate separate, in base alle esigenze. Considera questa struttura appiattita:
{ // Chats contains only meta info about each conversation // stored under the chats's unique ID "chats": { "one": { "title": "Historical Tech Pioneers", "lastMessage": "ghopper: Relay malfunction found. Cause: moth.", "timestamp": 1459361875666 }, "two": { "..." }, "three": { "..." } }, // Conversation members are easily accessible // and stored by chat conversation ID "members": { // we'll talk about indices like this below "one": { "ghopper": true, "alovelace": true, "eclarke": true }, "two": { "..." }, "three": { "..." } }, // Messages are separate from data we may want to iterate quickly // but still easily paginated and queried, and organized by chat // conversation ID "messages": { "one": { "m1": { "name": "eclarke", "message": "The relay seems to be malfunctioning.", "timestamp": 1459361875337 }, "m2": { "..." }, "m3": { "..." } }, "two": { "..." }, "three": { "..." } } }
Ora è possibile scorrere l'elenco delle stanze scaricando solo pochi byte per conversazione, recuperando rapidamente i metadati per elencare o visualizzare le stanze in un'interfaccia utente. I messaggi possono essere recuperati separatamente e visualizzati man mano che arrivano, consentendo all'interfaccia utente di rimanere reattiva e veloce.
Crea dati scalabili
Quando crei app, spesso è meglio scaricare un sottoinsieme di un elenco. Questo è particolarmente comune se l'elenco contiene migliaia di record. Quando questa relazione è statica e unidirezionale, puoi semplicemente nidificare gli oggetti secondari sotto l'oggetto principale.
A volte, questa relazione è più dinamica o potrebbe essere necessario denormalizzare questi dati. Molte volte puoi denormalizzare i dati utilizzando una query per recuperare un sottoinsieme dei dati, come descritto in Recupera dati.
Ma anche questo potrebbe non essere sufficiente. Considera, ad esempio, una relazione bidirezionale tra utenti e gruppi. Gli utenti possono appartenere a un gruppo e i gruppi comprendono un elenco di utenti. Quando arriva il momento di decidere a quali gruppi appartiene un utente, le cose si complicano.
È necessario un modo elegante per elencare i gruppi a cui appartiene un utente e recuperare solo i dati di questi gruppi. Un indice dei gruppi può essere di grande aiuto in questo caso:
// An index to track Ada's memberships { "users": { "alovelace": { "name": "Ada Lovelace", // Index Ada's groups in her profile "groups": { // the value here doesn't matter, just that the key exists "techpioneers": true, "womentechmakers": true } }, // ... }, "groups": { "techpioneers": { "name": "Historical Tech Pioneers", "members": { "alovelace": true, "ghopper": true, "eclarke": true } }, // ... } }
Potresti notare che questa operazione duplica alcuni dati memorizzando la relazione sia nel record di Ada sia nel gruppo. Ora alovelace è indicizzato in un gruppo e techpioneers è elencato nel profilo di Ada. Quindi, per eliminare Ada dal gruppo, deve essere aggiornato in due posizioni.
Questa è una ridondanza necessaria per le relazioni bidirezionali. Ti consente di recuperare in modo rapido ed efficiente le appartenenze di Ada, anche quando l'elenco di utenti o gruppi raggiunge milioni di elementi o quando Realtime Database regole di sicurezza impediscono l'accesso ad alcuni record.
Questo approccio, che inverte i dati elencando gli ID come chiavi e impostando il valore su true, semplifica il controllo di una chiave: basta leggere /users/$uid/groups/$group_id e verificare se è null. L'indice è più veloce e molto più efficiente rispetto all'esecuzione di query o alla scansione dei dati.