Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Strukturieren Sie Ihre Datenbank

Dieses Handbuch behandelt einige der wichtigsten Konzepte der Datenarchitektur und Best Practices für die Strukturierung der JSON-Daten in Ihrer Firebase-Echtzeitdatenbank.

Das Erstellen einer ordnungsgemäß strukturierten Datenbank erfordert einige Überlegungen. Am wichtigsten ist, dass Sie planen, wie Daten gespeichert und später abgerufen werden, um diesen Vorgang so einfach wie möglich zu gestalten.

Wie Daten strukturiert sind: Es ist ein JSON-Baum

Alle Firebase Realtime Database-Daten werden als JSON-Objekte gespeichert. Sie können sich die Datenbank als einen in der Cloud gehosteten JSON-Baum vorstellen. Im Gegensatz zu einer SQL-Datenbank gibt es keine Tabellen oder Datensätze. Wenn Sie dem JSON-Baum Daten hinzufügen, wird dieser zu einem Knoten in der vorhandenen JSON-Struktur mit einem zugeordneten Schlüssel. Sie können Ihre eigenen Schlüssel wie Benutzer-IDs oder semantische Namen oder diese mit push() für Sie bereitstellen.

Wenn Sie Ihre eigenen Schlüssel erstellen, müssen diese UTF-8-codiert sein, dürfen maximal 768 Byte umfassen und dürfen nicht enthalten . , $ , # , [ , ] , / oder ASCII-Steuerzeichen 0-31 oder 127. Sie können auch keine ASCII-Steuerzeichen in den Werten selbst verwenden.

Stellen Sie sich beispielsweise eine Chat-Anwendung vor, mit der Benutzer ein Basisprofil und eine Kontaktliste speichern können. Ein typisches Benutzerprofil befindet sich in einem Pfad, z. B. /users/$uid . Der Benutzer alovelace möglicherweise über einen Datenbankeintrag, der alovelace 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 verfügbaren JSON-Typen entsprechen, damit Sie besser wartbaren Code schreiben können.

Best Practices für die Datenstruktur

Vermeiden Sie das Verschachteln von Daten

Da die Firebase-Echtzeitdatenbank das Verschachteln von Daten mit einer Tiefe von bis zu 32 Ebenen ermöglicht, könnten Sie versucht sein zu glauben, dass dies die Standardstruktur sein sollte. Wenn Sie jedoch Daten an einem Speicherort in Ihrer Datenbank abrufen, rufen Sie auch alle untergeordneten Knoten ab. Wenn Sie jemandem Lese- oder Schreibzugriff auf einen Knoten in Ihrer Datenbank gewähren, gewähren Sie ihm außerdem Zugriff auf alle Daten unter diesem Knoten. In der Praxis ist es daher am besten, die Datenstruktur so flach wie möglich zu halten.

Betrachten Sie als Beispiel dafür, warum verschachtelte Daten schlecht sind, 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 diesem verschachtelten Design wird das Durchlaufen der Daten problematisch. Zum Beispiel erfordert den Titel der Chat - Konversationen Auflistung den gesamten chats Baum, darunter alle Mitglieder und Nachrichten, auf den Client heruntergeladen werden.

Datenstrukturen reduzieren

Wenn die Daten stattdessen in separate Pfade aufgeteilt werden, die auch als Denormalisierung bezeichnet werden, können sie bei Bedarf in separaten Aufrufen effizient heruntergeladen werden. Betrachten Sie diese abgeflachte 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": { ... }
  }
}

Es ist jetzt möglich, die Liste der Räume zu durchlaufen, indem nur wenige Bytes pro Konversation heruntergeladen werden und schnell Metadaten zum Auflisten oder Anzeigen von Räumen in einer Benutzeroberfläche abgerufen werden. Nachrichten können separat abgerufen und bei ihrem Eingang angezeigt werden, sodass die Benutzeroberfläche schnell und reaktionsschnell bleibt.

Erstellen Sie skalierbare Daten

Beim Erstellen von Apps ist es oft besser, eine Teilmenge einer Liste herunterzuladen. Dies ist besonders häufig, wenn die Liste Tausende von Datensätzen enthält. Wenn diese Beziehung statisch und einseitig ist, können Sie die untergeordneten Objekte einfach unter dem übergeordneten Objekt verschachteln.

Manchmal ist diese Beziehung dynamischer, oder es kann erforderlich sein, diese Daten zu denormalisieren. Oft können Sie die Daten denormalisieren, indem Sie eine Abfrage verwenden, um eine Teilmenge der Daten abzurufen, wie unter Abrufen von Daten beschrieben .

Aber auch das kann nicht ausreichen. Stellen Sie sich zum Beispiel eine wechselseitige Beziehung zwischen Benutzern und Gruppen vor. Benutzer können einer Gruppe angehören, und Gruppen umfassen eine Liste von Benutzern. Wenn es darum geht, zu entscheiden, zu welchen Gruppen ein Benutzer gehört, werden die Dinge kompliziert.

Was benötigt wird, ist eine elegante Möglichkeit, die Gruppen aufzulisten, zu denen ein Benutzer gehört, und nur Daten für diese Gruppen abzurufen. Ein Gruppenindex 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
      }
    },
    ...
  }
}

Möglicherweise stellen Sie fest, dass dadurch einige Daten dupliziert werden, indem Sie die Beziehung sowohl unter Adas Datensatz als auch unter der Gruppe speichern. Jetzt ist alovelace unter einer Gruppe indiziert und techpioneers ist in Adas Profil aufgeführt. Um Ada aus der Gruppe zu löschen, muss es an zwei Stellen aktualisiert werden.

Dies ist eine notwendige Redundanz für wechselseitige Beziehungen. Sie können damit schnell und effizient Adas Mitgliedschaften abrufen, selbst wenn die Liste der Benutzer oder Gruppen in Millionenhöhe skaliert oder wenn Sicherheitsregeln für Echtzeitdatenbanken den Zugriff auf einige Datensätze verhindern.

Dieser Ansatz, bei dem die Daten invertiert werden, indem die IDs als Schlüssel /users/$uid/groups/$group_id und der Wert auf true gesetzt wird, macht das Suchen nach einem Schlüssel so einfach wie das Lesen von /users/$uid/groups/$group_id und das Überprüfen, ob er null . Der Index ist schneller und wesentlich effizienter als das Abfragen oder Scannen der Daten.

Nächste Schritte