Daten mit Firebase Realtime Database für C++ speichern

Jetzt starten

Lesen Sie zuerst den Get Started-Leitfaden, wenn Sie Ihre App und den Zugriff auf die Datenbank noch nicht eingerichtet haben.

DatabaseReference abrufen

Wenn Sie Daten in die Datenbank schreiben möchten, benötigen Sie eine Instanz von DatabaseReference:

    // Get the root reference location of the database.
    firebase::database::DatabaseReference dbref = database->GetReference();

Daten speichern

Es gibt vier Methoden, um Daten in Firebase Realtime Database zu schreiben:

Methode Gängige Einsatzmöglichkeiten
SetValue() Daten in einen definierten Pfad schreiben oder ersetzen, z. B. users/<user-id>/<username>.
PushChild() Zu einer Datenliste hinzufügen. Jedes Mal, wenn Sie Push() aufrufen, generiert Firebase einen eindeutigen Schlüssel, der auch als eindeutige Kennung verwendet werden kann, z. B. user-scores/<user-id>/<unique-score-id>.
UpdateChildren() Aktualisieren Sie einige der Schlüssel für einen definierten Pfad, ohne alle Daten zu ersetzen.
RunTransaction() Komplexe Daten aktualisieren, die durch gleichzeitige Aktualisierungen beschädigt werden könnten.

Daten in einer Referenz schreiben, aktualisieren oder löschen

Grundlegende Schreibvorgänge

Für grundlegende Schreibvorgänge können Sie SetValue() verwenden, um Daten in einer angegebenen Referenz zu speichern. Dabei werden alle vorhandenen Daten in diesem Pfad ersetzt. Mit dieser Methode können Sie von JSON akzeptierte Typen über einen Variant-Typ übergeben, der Folgendes unterstützt:

  • Null (dadurch werden die Daten gelöscht)
  • Ganzzahlen (64-Bit)
  • Gleitkommazahlen mit doppelter Genauigkeit
  • Boolesche Werte
  • Strings
  • Vektoren von Varianten
  • Zuordnungen von Strings zu Varianten

Wenn Sie SetValue() auf diese Weise verwenden, werden Daten am angegebenen Speicherort überschrieben, einschließlich aller untergeordneten Knoten. Sie können jedoch ein untergeordnetes Element aktualisieren, ohne das gesamte Objekt neu zu schreiben. Wenn Sie Nutzern erlauben möchten, ihre Profile zu aktualisieren, können Sie den Nutzernamen so aktualisieren:

dbref.Child("users").Child(userId).Child("username").SetValue(name);

An eine Liste von Daten anhängen

Verwenden Sie die Methode PushChild(), um Daten an eine Liste in Anwendungen mit mehreren Nutzern anzuhängen. Die Methode PushChild() generiert jedes Mal einen eindeutigen Schlüssel, wenn der angegebenen Firebase-Referenz ein neues untergeordnetes Element hinzugefügt wird. Durch die Verwendung dieser automatisch generierten Schlüssel für jedes neue Element in der Liste können mehrere Clients gleichzeitig untergeordnete Elemente am selben Speicherort hinzufügen, ohne dass es zu Schreibkonflikten kommt. Der von PushChild() generierte eindeutige Schlüssel basiert auf einem Zeitstempel, sodass Listenelemente automatisch chronologisch sortiert werden.

Sie können den Verweis auf die neuen Daten, die von der Methode PushChild() zurückgegeben werden, verwenden, um den Wert des automatisch generierten Schlüssels des untergeordneten Elements abzurufen oder Daten für das untergeordnete Element festzulegen. Wenn Sie GetKey() für eine PushChild()-Referenz aufrufen, wird der Wert des automatisch generierten Schlüssels zurückgegeben.

Bestimmte Felder aktualisieren

Wenn Sie gleichzeitig in bestimmte untergeordnete Knoten eines Knotens schreiben möchten, ohne andere untergeordnete Knoten zu überschreiben, verwenden Sie die Methode UpdateChildren().

Beim Aufrufen von UpdateChildren() können Sie untergeordnete Werte auf niedrigerer Ebene aktualisieren, indem Sie einen Pfad für den Schlüssel angeben. Wenn Daten zur besseren Skalierung an mehreren Orten gespeichert sind, können Sie alle Instanzen dieser Daten mithilfe von Daten-Fan-out aktualisieren. Ein Spiel könnte beispielsweise eine LeaderboardEntry-Klasse wie diese haben:

class LeaderboardEntry {
  std::string uid;
  int score = 0;

 public:
  LeaderboardEntry() {
  }

  LeaderboardEntry(std::string uid, int score) {
    this->uid = uid;
    this->score = score;
  }

  std::map&ltstd::string, Object&gt ToMap() {
    std::map&ltstring, Variant&gt result = new std::map&ltstring, Variant&gt();
    result["uid"] = Variant(uid);
    result["score"] = Variant(score);

    return result;
  }
}

Um einen LeaderboardEntry zu erstellen und ihn gleichzeitig im Feed mit den aktuellen Punktzahlen und in der Liste mit den eigenen Punktzahlen des Nutzers zu aktualisieren, verwendet das Spiel den folgenden Code:

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&ltstd::string, Variant&gt entryValues = entry.ToMap();

  std::map&ltstring, Variant&gt childUpdates = new std::map&ltstring, Variant&gt();
  childUpdates["/scores/" + key] = entryValues;
  childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

  dbref.UpdateChildren(childUpdates);
}

In diesem Beispiel wird PushChild() verwendet, um einen Eintrag im Knoten zu erstellen, der Einträge für alle Nutzer unter /scores/$key enthält, und gleichzeitig den Schlüssel mit key() abzurufen. Der Schlüssel kann dann verwendet werden, um einen zweiten Eintrag in den Punktzahlen des Nutzers unter /user-scores/$userid/$key zu erstellen.

Mit diesen Pfaden können Sie mit einem einzigen Aufruf von UpdateChildren() gleichzeitige Aktualisierungen an mehreren Stellen im JSON-Baum vornehmen, wie in diesem Beispiel, in dem der neue Eintrag an beiden Stellen erstellt wird. Gleichzeitige Aktualisierungen, die auf diese Weise vorgenommen werden, sind unteilbar: Entweder sind alle Aktualisierungen erfolgreich oder alle schlagen fehl.

Daten löschen

Am einfachsten lassen sich Daten löschen, indem Sie RemoveValue() für einen Verweis auf den Speicherort dieser Daten aufrufen.

Sie können auch löschen, indem Sie einen null-Variant als Wert für einen anderen Schreibvorgang wie SetValue() oder UpdateChildren() angeben. Sie können diese Technik mit UpdateChildren() verwenden, um mehrere untergeordnete Elemente in einem einzigen API-Aufruf zu löschen.

Wissen, wann Ihre Daten festgeschrieben sind.

Wenn Sie wissen möchten, wann Ihre Daten auf dem Firebase Realtime Database-Server festgeschrieben werden, prüfen Sie das Future-Ergebnis auf Erfolg.

Daten als Transaktionen speichern

Wenn Sie mit Daten arbeiten, die durch gleichzeitige Änderungen beschädigt werden könnten, z. B. inkrementelle Zähler, können Sie einen Transaktionsvorgang verwenden. Sie weisen diesem Vorgang eine DoTransaction-Funktion zu. Diese Aktualisierungsfunktion verwendet den aktuellen Status der Daten als Argument und gibt den neuen gewünschten Status zurück, den Sie schreiben möchten. Wenn ein anderer Client in den Speicherort schreibt, bevor Ihr neuer Wert erfolgreich geschrieben wurde, wird Ihre Aktualisierungsfunktion noch einmal mit dem neuen aktuellen Wert aufgerufen und der Schreibvorgang wird wiederholt.

In einem Spiel können Sie Nutzern beispielsweise erlauben, eine Bestenliste mit den fünf höchsten Punktzahlen zu aktualisieren:

void AddScoreToLeaders(std::string email,
                       long score,
                       DatabaseReference leaderBoardRef) {
  leaderBoardRef.RunTransaction([](firebase::database::MutableData* mutableData) {
    if (mutableData.children_count() &gt= MaxScores) {
      long minScore = LONG_MAX;
      MutableData *minVal = null;
      std::vector&ltMutableData&gt children = mutableData.children();
      std::vector&ltMutableData&gt::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 &lt minScore) {
          minScore = childScore;
          minVal = &amp*it;
        }
      }
      if (minScore &gt 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&ltstd::string, Variant&gt newScoreMap =
      new std::map&ltstd::string, Variant&gt();
    newScoreMap["score"] = score;
    newScoreMap["email"] = email;
    children.Add(newScoreMap);
    mutableData->set_value(children);
    return kTransactionResultSuccess;
  });
}

Durch die Verwendung einer Transaktion wird verhindert, dass die Bestenliste fehlerhaft ist, wenn mehrere Nutzer gleichzeitig Ergebnisse aufzeichnen oder der Client veraltete Daten hatte. Wenn die Transaktion abgelehnt wird, gibt der Server den aktuellen Wert an den Client zurück, der die Transaktion dann mit dem aktualisierten Wert noch einmal ausführt. Dies wird wiederholt, bis die Transaktion akzeptiert wird oder zu viele Versuche unternommen wurden.

Daten offline schreiben

Wenn ein Client die Netzwerkverbindung verliert, funktioniert Ihre App weiterhin ordnungsgemäß.

Jeder Client, der mit einer Firebase-Datenbank verbunden ist, verwaltet eine eigene interne Version aller aktiven Daten. Wenn Daten geschrieben werden, werden sie zuerst in diese lokale Version geschrieben. Der Firebase-Client synchronisiert diese Daten dann nach dem Best-Effort-Prinzip mit den Remote-Datenbankservern und anderen Clients.

Daher lösen alle Schreibvorgänge in der Datenbank sofort lokale Ereignisse aus, bevor Daten auf den Server geschrieben werden. Das bedeutet, dass Ihre App unabhängig von Netzwerklatenz oder -verbindung reaktionsfähig bleibt.

Sobald wieder eine Verbindung hergestellt wurde, erhält Ihre App die entsprechenden Ereignisse, sodass der Client mit dem aktuellen Serverstatus synchronisiert wird, ohne dass Sie benutzerdefinierten Code schreiben müssen.

Nächste Schritte