Hinweis
Bevor Sie Realtime Database verwenden können, müssen Sie Folgendes tun:
Registrieren Sie Ihr Unity-Projekt und konfigurieren Sie es für die Verwendung von Firebase.
Wenn Ihr Unity-Projekt bereits Firebase verwendet, ist es bereits registriert und für Firebase konfiguriert.
Wenn Sie kein Unity-Projekt haben, können Sie eine Beispiel-App herunterladen.
Fügen Sie Ihrem Unity-Projekt das Firebase Unity SDK hinzu, insbesondere
FirebaseDatabase.unitypackage.
Das Hinzufügen von Firebase zu Ihrem Unity-Projekt umfasst Aufgaben in der Firebase Konsole und in Ihrem geöffneten Unity-Projekt (Sie laden beispielsweise Firebase-Konfigurationsdateien aus der Konsole herunter und verschieben sie dann in Ihr Unity-Projekt).
Daten strukturieren
In diesem Leitfaden werden einige der wichtigsten Konzepte der Datenarchitektur und Best Practices für die Strukturierung der JSON-Daten in Ihrer Firebase Realtime Database behandelt.
Der Aufbau einer ordnungsgemäß strukturierten Datenbank erfordert einiges an Vorplanung. Vor allem müssen Sie planen, wie Daten gespeichert und später abgerufen werden, um diesen Prozess so einfach wie möglich zu gestalten.
So sind Daten strukturiert: als JSON-Baum
Alle Firebase Realtime Database Daten werden als JSON-Objekte gespeichert. Sie können sich die Datenbank als eine cloud-gehostete JSON-Baumstruktur vorstellen. Im Gegensatz zu einer SQL-Datenbank gibt es keine Tabellen oder Datensätze. Wenn Sie der JSON-Baumstruktur Daten hinzufügen, werden diese zu einem Knoten in der vorhandenen JSON-Baumstruktur mit einem verknüpften Schlüssel. Sie können Ihre eigenen Schlüssel angeben, z. B. Nutzer-IDs oder semantische Namen, oder sie können mit der Methode Push() für Sie bereitgestellt werden.
Betrachten wir beispielsweise eine Chat-Anwendung, mit der Nutzer ein einfaches Profil und eine Kontaktliste speichern können. Ein typisches Nutzerprofil befindet sich unter einem Pfad wie /users/$uid. Der Nutzer alovelace hat möglicherweise einen Datenbankeintrag, der so aussieht:
{ "users": { "alovelace": { "name": "Ada Lovelace", "contacts": { "ghopper": true }, }, "ghopper": { "..." }, "eclarke": { "..." } } }
Obwohl die Datenbank einen JSON-Baum verwendet, können in der Datenbank gespeicherte Daten als bestimmte native Typen dargestellt werden, die den verfügbaren JSON-Typen entsprechen. So können Sie besser wartbaren Code schreiben.
Best Practices für die Datenstruktur
Verschachtelung von Daten vermeiden
Da die Firebase Realtime Database die Verschachtelung von Daten auf bis zu 32 Ebenen ermöglicht, könnten Sie versucht sein, dies als Standardstruktur zu betrachten. Wenn Sie jedoch Daten an einem Speicherort in Ihrer Datenbank abrufen, werden auch alle untergeordneten Knoten abgerufen. Wenn Sie außerdem jemandem Lese- oder Schreibzugriff auf einen Knoten in Ihrer Datenbank gewähren, gewähren Sie ihm auch Zugriff auf alle Daten unter diesem Knoten. Daher ist es in der Praxis am besten, die Datenstruktur so flach wie möglich zu halten.
Ein Beispiel dafür, warum verschachtelte Daten schlecht sind, ist die folgende mehrfach verschachtelte Struktur:
{ // 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": { "..." } } }
Bei dieser verschachtelten Struktur ist die Iteration durch die Daten problematisch. Wenn Sie beispielsweise die Titel von Chatunterhaltungen auflisten möchten, muss der gesamte chats-Baum, einschließlich aller Mitglieder und Nachrichten, auf den Client heruntergeladen werden.
Datenstrukturen vereinfachen
Wenn die Daten stattdessen in separate Pfade aufgeteilt werden, auch Denormalisierung genannt, können sie bei Bedarf effizient in separaten Aufrufen heruntergeladen werden. Betrachten Sie diese vereinfachte Struktur:
{ // 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": { "..." } } }
Jetzt können Sie die Liste der Räume durchlaufen, indem Sie nur wenige Byte pro Unterhaltung herunterladen und schnell Metadaten abrufen, um Räume in einer Benutzeroberfläche aufzulisten oder anzuzeigen. Nachrichten können separat abgerufen und angezeigt werden, sobald sie eingehen. So bleibt die Benutzeroberfläche reaktionsschnell und schnell.
Skalierbare Daten erstellen
Beim Erstellen von Apps ist es oft besser, eine Teilmenge einer Liste herunterzuladen. Das ist besonders häufig der Fall, wenn die Liste Tausende von Einträgen enthält. Wenn diese Beziehung statisch und unidirektional ist, können Sie die untergeordneten Objekte einfach unter dem übergeordneten Objekt verschachteln.
Manchmal ist diese Beziehung dynamischer oder es ist erforderlich, diese Daten zu denormalisieren. In vielen Fällen können Sie die Daten denormalisieren, indem Sie eine Abfrage verwenden, um eine Teilmenge der Daten abzurufen, wie unter Daten abrufenbeschrieben.
Aber auch das reicht möglicherweise nicht aus. Betrachten wir beispielsweise eine bidirektionale Beziehung zwischen Nutzern und Gruppen. Nutzer können Mitglied einer Gruppe sein und Gruppen bestehen aus einer Liste von Nutzern. Wenn es darum geht, zu entscheiden, welchen Gruppen ein Nutzer angehört, wird es kompliziert.
Es ist eine elegante Möglichkeit erforderlich, die Gruppen aufzulisten, denen ein Nutzer angehört, und nur Daten für diese Gruppen abzurufen. Ein Index von Gruppen kann hier sehr hilfreich sein:
// 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 } }, // ... } }
Sie werden feststellen, dass dadurch einige Daten dupliziert werden, da die Beziehung sowohl im Eintrag von Ada als auch in der Gruppe gespeichert wird. Jetzt ist alovelace unter einer Gruppe indexiert und techpioneers ist im Profil von Ada aufgeführt. Wenn Sie Ada also aus der Gruppe löschen möchten, muss sie an zwei Stellen aktualisiert werden.
Das ist eine notwendige Redundanz für bidirektionale Beziehungen. So können Sie die Mitgliedschaften von Ada schnell und effizient abrufen, auch wenn die Liste der Nutzer oder Gruppen Millionen umfasst oder wenn Realtime Database Sicherheitsregeln den Zugriff auf einige Einträge verhindern.
Bei diesem Ansatz, bei dem die Daten umgekehrt werden, indem die IDs als Schlüssel aufgeführt und der Wert auf „true“ gesetzt wird, ist die Suche nach einem Schlüssel so einfach wie das Lesen von /users/$uid/groups/$group_id und das Prüfen, ob er null ist. Der Index ist schneller und viel effizienter als das Abfragen oder Scannen der Daten.
Nächste Schritte
- Daten in der Realtime Database speichern
- Daten aus Ihrer Realtime Database abrufen