Catch up on everthing we announced at this year's Firebase Summit. Learn more

Daten im Web lesen und schreiben

(Optional) Prototyp und Test mit Firebase Local Emulator Suite

Bevor wir darüber sprechen, wie Ihre App aus der Echtzeitdatenbank liest und in sie schreibt, stellen wir eine Reihe von Tools vor, die Sie zum Prototyping und Testen der Echtzeitdatenbankfunktionalität verwenden können: Firebase Local Emulator Suite. Wenn Sie verschiedene Datenmodelle ausprobieren, Ihre Sicherheitsregeln optimieren oder nach der kostengünstigsten Möglichkeit suchen, mit dem Back-End zu interagieren, kann es eine gute Idee sein, lokal zu arbeiten, ohne Live-Dienste bereitzustellen.

Ein Echtzeit-Datenbank-Emulator ist Teil der Local Emulator Suite, die es Ihrer App ermöglicht, mit Ihrem emulierten Datenbankinhalt und Ihrer Konfiguration sowie optional mit Ihren emulierten Projektressourcen (Funktionen, andere Datenbanken und Sicherheitsregeln) zu interagieren.

Die Verwendung des Echtzeit-Datenbank-Emulators umfasst nur wenige Schritte:

  1. Hinzufügen einer Codezeile zur Testkonfiguration Ihrer App, um eine Verbindung zum Emulator herzustellen.
  2. Von der Wurzel Ihrer lokalen Projektverzeichnis, laufen firebase emulators:start .
  3. Tätigen von Aufrufen aus dem Prototypcode Ihrer App wie gewohnt mit einem Realtime Database Platform SDK oder mit der Realtime Database REST API.

Eine detaillierte Komplettlösung beteiligt Realtime - Datenbank und Cloud - Funktionen zur Verfügung. Sie sollten auch einen Blick auf die haben Local Emulator Suite Einführung .

Holen Sie sich eine Datenbankreferenz

Zum Lesen oder Schreiben von Daten aus der Datenbank, müssen Sie eine Instanz von firebase.database.Reference :

Webversion 9

import { getDatabase } from "firebase/database";

const database = getDatabase();

Webversion 8

var database = firebase.database();

Daten schreiben

In diesem Dokument werden die Grundlagen des Abrufens von Daten sowie das Ordnen und Filtern von Firebase-Daten behandelt.

Feuerbasis Daten werden durch das Anbringen eines asynchronen Zuhörers auf eine abgerufene firebase.database.Reference . Der Listener wird einmal für den Anfangszustand der Daten und jedes Mal, wenn sich die Daten ändern, getriggert.

Grundlegende Schreibvorgänge

Für grundlegende Schreiboperationen, können Sie set() Daten zu einer bestimmten Referenz zu speichern, alle vorhandenen Daten auf diesem Weg zu ersetzen. Zum Beispiel eine soziale Blogging - Anwendung kann ein Benutzer mit hinzufügen set() wie folgt:

Webversion 9

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
  });
}

Webversion 8

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

Mit set() überschreibt Daten an der angegebenen Position, einschließlich aller untergeordneten Knoten.

Daten lesen

Auf Wertereignisse achten

Um Daten auf einem Pfad zu lesen und für Änderungen hören, verwenden Sie die on() oder once() Methoden der firebase.database.Reference Ereignisse zu beobachten.

Vorfall Typische Verwendung
value Lesen und hören Sie auf Änderungen am gesamten Inhalt eines Pfads.

Sie können die Verwendung value Ereignis eine statische Momentaufnahme der Inhalte zu einem bestimmten Pfad zu lesen, da sie zum Zeitpunkt der Veranstaltung bestanden. Diese Methode wird einmal ausgelöst, wenn der Listener angehängt wird, und jedes Mal, wenn sich die Daten, einschließlich der untergeordneten Elemente, ändern. Dem Ereignisrückruf wird ein Snapshot übergeben, der alle Daten an diesem Speicherort enthält, einschließlich der untergeordneten Daten. Wenn keine Daten vorhanden sind, wird der Snapshot zurückkehren false , wenn Sie anrufen exists() und null , wenn Sie anrufen val() auf sie.

Das folgende Beispiel zeigt eine Social-Blogging-Anwendung, die die Sternzahl eines Beitrags aus der Datenbank abruft:

Webversion 9

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);
});

Webversion 8

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

Der Hörer erhält eine snapshot , die die Daten an der angegebenen Stelle in der Datenbank zum Zeitpunkt des Ereignisses enthält. Sie können die Daten in dem Abrufen von snapshot mit der val() Methode.

Daten einmal lesen

Daten einmal mit get() lesen

Das SDK wurde entwickelt, um Interaktionen mit Datenbankservern zu verwalten, unabhängig davon, ob Ihre App online oder offline ist.

Im Allgemeinen sollten Sie die oben beschriebenen Wertereignistechniken verwenden, um Daten zu lesen, um über Aktualisierungen der Daten vom Back-End benachrichtigt zu werden. Die Listener-Techniken reduzieren Ihre Nutzung und Abrechnung und sind optimiert, um Ihren Benutzern die beste Erfahrung zu bieten, wenn sie online und offline gehen.

Wenn Sie die Daten nur einmal benötigen, können Sie get() eine Momentaufnahme der Daten aus der Datenbank zu erhalten. Wenn aus irgendeinem Grund get() nicht in der Lage ist , den Server - Wert zurückzukehren, wird der Client den lokalen Speicher - Cache - Sonde und einen Fehler zurück , wenn der Wert noch nicht gefunden wird.

Unnötige Verwendung von get() kann Nutzung der Bandbreite und führt zu Leistungsverlust erhöhen, die unter Verwendung eines Echtzeit - Hörers verhindert werden kann , wie oben gezeigt.

Webversion 9

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);
});

Webversion 8

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 möglicherweise, dass der Wert aus dem lokalen Cache sofort zurückgegeben wird, anstatt auf dem Server nach einem aktualisierten Wert zu suchen. In diesen Fällen können Sie verwenden , once() die Daten sofort aus dem lokalen Festplatten - Cache zu erhalten.

Dies ist nützlich für Daten, die nur einmal geladen werden müssen und sich nicht häufig ändern oder eine aktive Überwachung erfordern. Die Blogging-App in den vorherigen Beispielen verwendet beispielsweise diese Methode, um das Profil eines Benutzers zu laden, wenn er mit dem Verfassen eines neuen Beitrags beginnt:

Webversion 9

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
});

Webversion 8

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

Aktualisieren oder Löschen von Daten

Spezifische Felder aktualisieren

Um gleichzeitig auf bestimmte Kinder eines Knotens zu schreiben , ohne andere untergeordnete Knoten zu überschreiben, verwenden Sie die update() Methode.

Beim Aufruf von update() , können Sie auf niedrigerer Ebene Kind Werte aktualisieren , indem Sie einen Pfad für den Schlüssel angeben. Wenn Daten an mehreren Orten gespeichert ist , besser zu skalieren, können Sie alle Instanzen dieser Daten aktualisieren , die Daten Fanout .

Beispielsweise könnte eine Social-Blogging-App einen Beitrag erstellen und ihn gleichzeitig mit dem folgenden Code auf den Feed der letzten Aktivitäten und den Aktivitätsfeed des postenden Benutzers aktualisieren:

Webversion 9

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);
}

Webversion 8

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() einen Beitrag in dem Knoten für alle Benutzer enthält Beiträge erstellen /posts/$postid und gleichzeitig den Schlüssel abzurufen. Der Schlüssel kann dann verwendet werden , um einen zweiten Eintrag in den Benutzern Beiträge zu erstellen /user-posts/$userid/$postid .

Mit Hilfe dieser Pfade können Sie gleichzeitige Aktualisierungen auf mehrere Standorte im JSON - Struktur mit einem einzigen Aufruf ausführen update() , wie , wie dieses Beispiel in den beiden Standorten den neuen Beitrag erstellt. Gleichzeitige Aktualisierungen, die auf diese Weise durchgeführt werden, sind atomar: Entweder sind alle Aktualisierungen erfolgreich oder alle Aktualisierungen schlagen fehl.

Hinzufügen eines Abschlussrückrufs

Wenn Sie wissen möchten, wann Ihre Daten festgeschrieben wurden, können Sie einen Abschlussrückruf hinzufügen. Beiden set() und update() nehmen einen optionalen Abschluss Rückruf, der aufgerufen wird , wenn der Schreib wird in die Datenbank übernommen worden. Wenn der Aufruf nicht erfolgreich war, wird dem Rückruf ein Fehlerobjekt übergeben, das angibt, warum der Fehler aufgetreten ist.

Webversion 9

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...
});

Webversion 8

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

Die einfachste Art und Weise zu löschen Daten aufrufen remove() auf einem Verweis auf den Speicherort der Daten.

Sie können auch durch Angabe löschen null als Wert für eine weitere Schreiboperation wie set() oder update() . Sie können diese Technik mit verwenden update() , um mehrere Kinder in einem einzigen API - Aufruf zu löschen.

Empfangen Sie ein Promise

Um zu wissen , wenn Sie Ihre Daten in dem Firebase Realtime - Datenbank - Server gebunden ist, können Sie ein verwenden Promise . Beide set() und update() kann eine Rückkehr Promise Sie verwenden können , zu wissen , wann das Schreiben in die Datenbank übergeben wird.

Hörer trennen

Rückrufe werden durch den Aufruf der entfernt off() Methode auf Firebase Datenbank Referenz.

Sie können einen einzelnen Hörer entfernen , indem Sie es als Parameter vorbei off() . Der Aufruf off() auf der Stelle ohne Argumente werden alle Zuhörer an dieser Stelle.

Der Aufruf off() auf einem übergeordneten Hörer nicht automatisch Hörer entfernen auf seinen untergeordneten Knoten registriert ist ; off() muss auch auf alle untergeordneten Hörer aufgerufen werden , um den Rückruf zu entfernen.

Daten als Transaktionen speichern

Bei der Arbeit mit Daten , die durch die gleichzeitigen Änderungen beschädigt werden könnten, wie Inkrementalzähler, können Sie einen verwenden Transaktion Betrieb . Sie können dieser Operation eine Update-Funktion und einen optionalen Abschluss-Callback geben. Die Update-Funktion nimmt den aktuellen Zustand der Daten als Argument und gibt den neuen gewünschten Zustand zurück, den Sie schreiben möchten. Wenn ein anderer Client in die Position schreibt, bevor Ihr neuer Wert erfolgreich geschrieben wurde, wird Ihre Update-Funktion erneut mit dem neuen aktuellen Wert aufgerufen und der Schreibvorgang wird wiederholt.

In der Beispiel-App für soziales Bloggen könnten Sie beispielsweise Benutzern erlauben, Beiträge zu markieren und die Markierung aufzuheben und wie folgt zu verfolgen, wie viele Sterne ein Beitrag erhalten hat:

Webversion 9

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;
  });
}

Webversion 8

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;
  });
}

Die Verwendung einer Transaktion verhindert, dass die Sternzählung falsch ist, wenn mehrere Benutzer denselben Beitrag gleichzeitig markieren oder der Kunde veraltete Daten hat. Wenn die Transaktion abgelehnt wird, gibt der Server den aktuellen Wert an den Client zurück, der die Transaktion mit dem aktualisierten Wert erneut ausführt. Dies wiederholt sich, bis die Transaktion akzeptiert wird oder Sie die Transaktion abbrechen.

Atomare serverseitige Inkremente

Im obigen Anwendungsfall schreiben wir zwei Werte in die Datenbank: die ID des Benutzers, der den Beitrag markiert/deaktiviert, und die inkrementierte Sternzahl. Wenn wir bereits wissen, dass der Benutzer den Beitrag markiert, können wir anstelle einer Transaktion eine atomare Inkrementierungsoperation verwenden.

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 keine Transaktionsoperation, daher wird er nicht automatisch erneut ausgeführt, wenn ein Update widersprüchlich ist. Da die Inkrementierungsoperation jedoch direkt auf dem Datenbankserver erfolgt, besteht keine Möglichkeit eines Konflikts.

Wenn Sie anwendungsspezifische Konflikte erkennen und ablehnen möchten, z. B. wenn ein Benutzer einen Beitrag markiert, den er bereits zuvor markiert hat, sollten Sie benutzerdefinierte Sicherheitsregeln für diesen Anwendungsfall schreiben.

Offline mit Daten arbeiten

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

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

Daher lösen alle Schreibvorgänge in die Datenbank sofort lokale Ereignisse aus, bevor Daten auf den Server geschrieben werden. Das bedeutet, dass Ihre App unabhängig von Netzwerklatenz oder Konnektivität reaktionsschnell bleibt.

Sobald die Verbindung wiederhergestellt ist, empfängt Ihre App die entsprechenden Ereignisse, sodass der Client mit dem aktuellen Serverstatus synchronisiert wird, ohne benutzerdefinierten Code schreiben zu müssen.

Wir werden mehr über Offline - Verhalten sprechen in Erfahren Sie mehr über Online - und Offline - Funktionen ..

Nächste Schritte