Daten im Web lesen und schreiben

(Optional) Mit Firebase Local Emulator Suite einen Prototyp erstellen und testen

Bevor du darauf sprichst, wie deine App Daten aus dem Realtime Database liest und schreibt, stellen wir Ihnen eine Reihe von Tools vor, mit denen Sie Realtime Database-Prototypen erstellen und testen können. Funktion: Firebase Local Emulator Suite. Wenn Sie verschiedene Daten ausprobieren, Modelle zu erstellen, Sicherheitsregeln zu optimieren oder eine kostengünstige Möglichkeit für die Interaktion mit dem Backend, da die Möglichkeit, lokal zu arbeiten, ohne Live-Dienste bereitzustellen, ist das eine gute Idee.

Ein Realtime Database-Emulator ist Teil der Local Emulator Suite, die ermöglicht es Ihrer App, mit dem Inhalt und der Konfiguration Ihrer emulierten Datenbank zu interagieren, sowie optional Ihre emulierten Projektressourcen (Funktionen, andere Datenbanken, und Sicherheitsregeln).

Die Verwendung des Realtime Database-Emulators ist ganz einfach:

  1. Fügen Sie der Testkonfiguration Ihrer App eine Codezeile hinzu, um eine Verbindung zum Emulator herzustellen.
  2. Führen Sie im Stammverzeichnis Ihres lokalen Projektverzeichnisses firebase emulators:start aus.
  3. Über den Prototypcode Ihrer App über eine Realtime Database-Plattform Aufrufe ausführen oder die Realtime Database REST API verwenden.

Eine detaillierte Schritt-für-Schritt-Anleitung zu Realtime Database und Cloud Functions findest du. Du solltest dir auch die Einführung zu Local Emulator Suite ansehen.

Datenbankreferenz abrufen

Zum Lesen oder Schreiben von Daten aus der Datenbank benötigen Sie eine Instanz von firebase.database.Reference:

Web

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web

var database = firebase.database();

Daten schreiben

In diesem Dokument werden die Grundlagen des Abrufens von Daten und die Sortierung und Filterung von Firebase-Daten erläutert.

Firebase-Daten werden abgerufen, indem Sie einen asynchronen Listener zu firebase.database.Reference anfügen. Der Listener wird einmal für die Anfangszustand der Daten und jedes Mal, wenn sich die Daten ändern.

Grundlegende Schreibvorgänge

Bei einfachen Schreibvorgängen können Sie mit set() Daten in einer bestimmten Referenz speichern und alle vorhandenen Daten an diesem Pfad ersetzen. Zum Beispiel eine Social-Media- Bloganwendung kann einen Nutzer mit set() so hinzufügen:

Web

import { getDatabase, ref, set } from "firebase/database";

function writeUserData(userId, name, email, imageUrl) {
  const db = getDatabase();
  set(ref(db, 'users/' + userId), {
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

Web

function writeUserData(userId, name, email, imageUrl) {
  firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

Bei Verwendung von set() werden Daten am angegebenen Speicherort überschrieben, einschließlich aller untergeordneten Elemente Knoten.

Daten lesen

Auf Wertereignisse warten

Wenn Sie Daten in einem Pfad lesen und auf Änderungen warten möchten, verwenden Sie onValue(), um zu beobachten, Ereignisse. Mit diesem Ereignis können Sie statische Momentaufnahmen des Inhalts angegebenen Pfad, wie sie zum Zeitpunkt des Ereignisses existierten. Diese Methode wird einmal ausgelöst, wenn der Listener angehängt wird, und jedes Mal, wenn sich die Daten (einschließlich untergeordneter Elemente) ändern. Dem Ereignis-Callback wird ein Snapshot übergeben, der alle Daten an diesem Speicherort, einschließlich untergeordneter Daten. Wenn keine Daten vorhanden sind, gibt der Snapshot false zurück, wenn exists() aufgerufen wird, und null, wenn val() aufgerufen wird.

Das folgende Beispiel zeigt eine Blog-Anwendung für soziale Netzwerke, Anzahl der Sterne für einen Beitrag aus der Datenbank:

Web

import { getDatabase, ref, onValue } from "firebase/database";

const db = getDatabase();
const starCountRef = ref(db, 'posts/' + postId + '/starCount');
onValue(starCountRef, (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

Web

var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
starCountRef.on('value', (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

Der Listener empfängt eine snapshot, die die Daten am angegebenen Standort in der Datenbank zum Zeitpunkt des Ereignisses. Sie können die Daten abrufen, in der snapshot mit der val()-Methode.

Daten einmal lesen

Daten einmal mit get() lesen

Das SDK ist darauf ausgelegt, Interaktionen mit Datenbankservern zu verwalten, unabhängig davon, ob Sie App ist online oder offline.

Im Allgemeinen sollten Sie die oben beschriebenen Methoden für Wert-Ereignisse verwenden, um Daten zu lesen und benachrichtigt zu werden, wenn Daten im Backend aktualisiert werden. Der Zuhörer reduzieren Ihre Nutzung und die Kosten. um Ihren Nutzern sowohl online als auch offline eine optimale Nutzererfahrung zu bieten.

Wenn Sie die Daten nur einmal benötigen, können Sie mit get() einen Snapshot der Daten aus der Datenbank abrufen. Falls get() den Server aus irgendeinem Grund nicht zurückgeben kann prüft der Client den lokalen Speicher und gibt einen Fehler zurück, -Wert wurde immer noch nicht gefunden.

Die unnötige Verwendung von get() kann die Bandbreitennutzung erhöhen und zu Leistungseinbußen führen. Dies kann durch die Verwendung eines Echtzeit-Listeners wie oben gezeigt verhindert werden.

Web

import { getDatabase, ref, child, get } from "firebase/database";

const dbRef = ref(getDatabase());
get(child(dbRef, `users/${userId}`)).then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Web

const dbRef = firebase.database().ref();
dbRef.child("users").child(userId).get().then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Daten einmal mit einem Beobachter lesen

In einigen Fällen möchten Sie vielleicht, dass der Wert aus dem lokalen Cache zurückgegeben wird. anstatt auf dem Server nach einem aktualisierten Wert zu suchen. In diesen In Fällen können Sie die Daten mit once() sofort aus dem lokalen Festplatten-Cache abrufen.

Das ist nützlich für Daten, die nur einmal geladen werden müssen und sich voraussichtlich nicht häufig ändern oder für die aktives Zuhören erforderlich ist. Zum Beispiel hat die Blog-App in den vorherigen Beispielen verwendet diese Methode zum Laden von Nutzerprofilen, mit dem Verfassen eines neuen Beitrags beginnen:

Web

import { getDatabase, ref, onValue } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const userId = auth.currentUser.uid;
return onValue(ref(db, '/users/' + userId), (snapshot) => {
  const username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
}, {
  onlyOnce: true
});

Web

var userId = firebase.auth().currentUser.uid;
return firebase.database().ref('/users/' + userId).once('value').then((snapshot) => {
  var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
});

Daten aktualisieren oder löschen

Bestimmte Felder aktualisieren

Um gleichzeitig in bestimmte untergeordnete Knoten eines Knotens zu schreiben, ohne andere untergeordneten Knoten, verwenden Sie die Methode update().

Wenn Sie update() aufrufen, können Sie untergeordnete Werte auf niedrigerer Ebene aktualisieren, indem Sie und gibt einen Pfad für den Schlüssel an. Wenn Daten zur besseren Skalierung an mehreren Orten gespeichert werden, können Sie alle Instanzen dieser Daten mithilfe der Datenfan-out-Funktion aktualisieren.

Eine soziale Blog-App könnte beispielsweise einen Beitrag erstellen und gleichzeitig in den Feed „Letzte Aktivität“ und den Aktivitätsfeed des Nutzers, Code wie diesen aussehen:

Web

import { getDatabase, ref, child, push, update } from "firebase/database";

function writeNewPost(uid, username, picture, title, body) {
  const db = getDatabase();

  // A post entry.
  const postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  const newPostKey = push(child(ref(db), 'posts')).key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  const updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return update(ref(db), updates);
}

Web

function writeNewPost(uid, username, picture, title, body) {
  // A post entry.
  var postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  var newPostKey = firebase.database().ref().child('posts').push().key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  var updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return firebase.database().ref().update(updates);
}

In diesem Beispiel wird push() verwendet, um einen Beitrag im Knoten zu erstellen, der Beiträge für alle Nutzer unter /posts/$postid enthält, und gleichzeitig den Schlüssel abzurufen. Der Schlüssel kann wird dann verwendet, um einen zweiten Eintrag in der Beiträge auf /user-posts/$userid/$postid.

Mit diesen Pfaden kannst du mit einem einzigen Aufruf von update() gleichzeitig mehrere Stellen im JSON-Baum aktualisieren. In diesem Beispiel wird beispielsweise der neue Beitrag an beiden Stellen erstellt. So werden gleichzeitige Aktualisierungen durchgeführt sind atomar: Entweder sind alle Updates erfolgreich oder alle schlagen fehl.

Abschluss-Callback hinzufügen

Wenn Sie wissen möchten, wann ein Commit für Ihre Daten durchgeführt wurde, können Sie Callback für den Abschluss des Vorgangs. Für set() und update() ist ein optionaler Abschluss erforderlich -Callback, der nach dem Commit des Schreibvorgangs in der Datenbank aufgerufen wird. Wenn der Aufruf war nicht erfolgreich, dem Callback wird ein Fehlerobjekt, das angibt, warum der Fehler aufgetreten ist.

Web

import { getDatabase, ref, set } from "firebase/database";

const db = getDatabase();
set(ref(db, 'users/' + userId), {
  username: name,
  email: email,
  profile_picture : imageUrl
})
.then(() => {
  // Data saved successfully!
})
.catch((error) => {
  // The write failed...
});

Web

firebase.database().ref('users/' + userId).set({
  username: name,
  email: email,
  profile_picture : imageUrl
}, (error) => {
  if (error) {
    // The write failed...
  } else {
    // Data saved successfully!
  }
});

Daten löschen

Am einfachsten löschen Sie Daten, indem Sie remove() auf eine Referenz zum Speicherort dieser Daten anwenden.

Zum Löschen können Sie auch null als Wert für einen weiteren Schreibvorgang angeben. wie set() oder update(). Mit dieser Technik können Sie mit update(), um mehrere untergeordnete Elemente in einem einzigen API-Aufruf zu löschen.

Promise erhalten

Wenn Sie wissen möchten, wann Ihre Daten auf dem Firebase Realtime Database-Server verbindlich gespeichert werden, können Sie einen Promise verwenden. Sowohl set() als auch update() können eine Promise zurückgeben, mit der Sie feststellen können, wann der an die Datenbank übergeben wird.

Listener trennen

Callbacks werden durch Aufrufen der off()-Methode auf Ihrem Firebase-Datenbankreferenz

Sie können einen einzelnen Listener entfernen, indem Sie ihn als Parameter an off() übergeben. Wenn Sie off() für den Standort ohne Argumente aufrufen, werden alle Listener an diesem Standort entfernt Standort.

Das Aufrufen von off() für einen übergeordneten Listener erfolgt nicht Listener, die auf den untergeordneten Knoten registriert sind, werden automatisch entfernt. off() muss auch für alle untergeordneten Listener aufgerufen werden um den Callback zu entfernen.

Daten als Transaktionen speichern

Wenn Sie mit Daten arbeiten, die durch gleichzeitige wie inkrementelle Zähler, können Sie mit einem Transaktionsvorgang Sie können diesem Vorgang eine Aktualisierungsfunktion und einen optionalen Callback für den Abschluss des Vorgangs. Die Aktualisierungsfunktion nimmt den aktuellen Status der Daten ein Argument und gibt den neuen gewünschten Status zurück, den Sie schreiben möchten. Wenn ein anderer Client an den Speicherort schreibt, bevor der neue Wert erfolgreich geschrieben wurde, wird die Aktualisierungsfunktion noch einmal mit dem neuen aktuellen Wert aufgerufen und der Schreibvorgang wird noch einmal versucht.

In der Beispiel-App für soziales Bloggen könnten die Nutzer beispielsweise Beiträge markieren und Markierungen wieder aufheben und verfolgen, wie viele Sterne ein Beitrag erhalten hat wie folgt:

Web

import { getDatabase, ref, runTransaction } from "firebase/database";

function toggleStar(uid) {
  const db = getDatabase();
  const postRef = ref(db, '/posts/foo-bar-123');

  runTransaction(postRef, (post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

Web

function toggleStar(postRef, uid) {
  postRef.transaction((post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

Durch eine Transaktion wird verhindert, dass die Anzahl der Sterne falsch ist, wenn mehrere Nutzer denselben Beitrag zur selben Zeit markieren oder die Daten des Kunden veraltet sind. Wenn die Transaktion abgelehnt wird, gibt der Server den aktuellen Wert an den Client zurück, der die Transaktion mit dem aktualisierten Wert noch einmal ausführt. Dieser Vorgang wird wiederholt, bis die Transaktion akzeptiert wird oder Sie den Vorgang abbrechen. der Transaktion.

Atomare serverseitige Inkremente

Im obigen Anwendungsfall schreiben wir zwei Werte in die Datenbank: die ID des Nutzers, der dem Beitrag ein bzw. kein Sternchen gibt, und die inkrementierte Anzahl der Sterne. Wenn wir dass der Nutzer den Beitrag markiert, können wir ein atomares Inkrement verwenden, statt einer Transaktion.

Web

function addStar(uid, key) {
  import { getDatabase, increment, ref, update } from "firebase/database";
  const dbRef = ref(getDatabase());

  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = increment(1);
  update(dbRef, updates);
}

Web

function addStar(uid, key) {
  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  firebase.database().ref().update(updates);
}

Dieser Code verwendet keinen Transaktionsvorgang, daher wird er nicht automatisch erstellt bei einem Update noch einmal ausführen. Da der Inkrementierungsvorgang jedoch direkt auf dem Datenbankserver erfolgt, besteht kein Konflikt.

Wenn Sie anwendungsspezifische Konflikte erkennen und ablehnen möchten, z. B. wenn ein Nutzer einem Beitrag ein Sternchen hinzufügt, das er ihm bereits zuvor gegeben hat, sollten Sie benutzerdefinierte Sicherheitsregeln für diesen Anwendungsfall schreiben.

Offline mit Daten arbeiten

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

Jeder Client, der mit einer Firebase-Datenbank verbunden ist, verwaltet seine eigenen internen Versionen aller aktiven Daten. Beim Schreiben von Daten werden sie in diese lokale Version geschrieben. . Der Firebase-Client synchronisiert diese Daten dann auf Best-Effort-Basis mit den Remote-Datenbankservern und anderen Clients.

Daher werden alle Schreibvorgänge in der Datenbank sofort als lokale Ereignisse ausgelöst, bevor Daten auf den Server geschrieben werden. Das bedeutet, dass Ihre App reaktionsschnell und unabhängig von der Netzwerklatenz oder Konnektivität.

Sobald die Verbindung wiederhergestellt ist, erhält Ihre App die entsprechenden Ereignisse, damit der Client mit dem aktuellen Serverstatus synchronisiert wird, ohne dass benutzerdefinierter Code geschrieben werden muss.

Wir werden später noch näher auf das Offlineverhalten eingehen, Weitere Informationen zu Online- und Offlinefunktionen

Nächste Schritte