(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:
- Fügen Sie der Testkonfiguration Ihrer App eine Codezeile hinzu, um eine Verbindung zum Emulator herzustellen.
- Führen Sie im Stammverzeichnis Ihres lokalen Projektverzeichnisses
firebase emulators:start
aus. - Ü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