Dieser Artikel wird Ihnen, liebe Frontend-Entwickler, helfen, alles über Firebase zu verstehen. Wir werden viele Details darüber behandeln, was Firebase ist, warum es für Sie nützlich sein kann, und Beispiele zeigen, wie. Aber zuerst denke ich, Sie werden eine kleine Geschichte darüber genießen, wie Firebase entstanden ist.
Vor acht Jahren bauten Andrew Lee und James Tamplin ein Echtzeit-Chat-Startup namens Envolve auf. Der Dienst war ein Erfolg. Er wurde auf Websites von Prominenten wie Ricky Martin und Limp Bizkit genutzt. Envolve richtete sich an Entwickler, die nicht – schon wieder – ihr eigenes Chat-Widget bauen wollten. Der Wert des Dienstes ergab sich aus der einfachen Einrichtung und der schnellen Nachrichtenübermittlung. Envolve war nur ein Chat-Widget. Der Prozess war einfach. Platziere ein Skript-Tag auf einer Seite. Sobald das Widget hochgefahren war, erledigte es alles für Sie. Es war, als ob bereits eine Datenbank und ein Server für Chat-Nachrichten eingerichtet wären.
James und Andrew bemerkten einen merkwürdigen Trend, als der Dienst immer beliebter wurde. Einige Entwickler fügten das Widget auf der Seite ein, machten es aber unsichtbar. Warum sollte jemand ein Chat-Widget mit versteckten Nachrichten wollen? Nun, es wurden nicht nur Chat-Daten zwischen Geräten gesendet. Es waren Spieldaten, Highscores, App-Einstellungen, To-dos oder was auch immer der Entwickler schnell senden und synchronisieren musste. Entwickler hörten auf neue Nachrichten im Widget und nutzten sie, um den Zustand in ihren Apps zu synchronisieren. Dies war eine einfache Möglichkeit, Echtzeit-Erlebnisse zu schaffen, ohne ein Backend zu benötigen.
Dies war ein Erweckungsmoment für die Mitbegründer von Firebase. Was wäre, wenn Entwickler *mehr* als nur Chat-Nachrichten senden könnten? Was wäre, wenn sie einen Dienst hätten, um ihre Anwendungen schnell zu entwickeln und zu skalieren? Die Verantwortung für die Verwaltung der Backend-Infrastruktur entfällt. Konzentration auf das Frontend. So wurde Firebase geboren.
Was ist Firebase?
Ist Firebase nicht eine Datenbank? Nein… ja… meistens nein. Firebase ist eine Plattform, die die Infrastruktur für Entwickler und Tools für Vermarkter bereitstellt. Aber das war nicht immer so.
Vor sieben Jahren war Firebase ein einzelnes Produkt: eine Echtzeit-Cloud-Datenbank. Heute ist Firebase eine Sammlung von 19 Produkten. Jedes Produkt ist darauf ausgelegt, einen Teil der Anwendungs-Infrastruktur zu stärken. Firebase gibt Ihnen auch Einblicke, wie Ihre App funktioniert, was Ihre Benutzer tun und wie Sie das Gesamterlebnis Ihrer App verbessern können. Während Firebase den gesamten Backend-Bereich Ihrer App ausmachen kann, können Sie jedes Produkt auch einzeln verwenden.
Hier ist nur eine Auswahl dieser 19 Produkte
- Hosting: Stellen Sie für jede GitHub-Pull-Anfrage eine neue Version Ihrer Website bereit.
- Firestore: Erstellen Sie Apps, die in Echtzeit funktionieren, auch offline, ohne Server.
- Auth: Authentifizieren und verwalten Sie Benutzer mit einer Vielzahl von Anbietern.
- Storage: Verwalten Sie benutzergenerierte Inhalte wie Fotos, Videos und GIFs.
- Cloud Functions: Servercode, der von Ereignissen gesteuert wird (z. B. Datensatz erstellt, Benutzeranmeldung usw.).
- Extensions: Vorkonfigurierte Funktionssätze mit UI (z. B. Stripe-Zahlungen, Textübersetzungen usw.)
- Google Analytics: Verstehen Sie Benutzeraktivitäten, organisiert nach Segmenten und Zielgruppen.
- Remote Config: Schlüssel-Wert-Speicher mit dynamischen Bedingungen, ideal für die Funktionssteuerung.
- Performance Monitoring: Seitenlade-Metriken und benutzerdefinierte Traces aus der realen Nutzung.
- Cloud Messaging: Plattformübergreifende Push-Benachrichtigungen.
Puh. Das ist viel, und ich habe nicht einmal die anderen neun Produkte aufgelistet. Das ist in Ordnung. Es gibt keine Verpflichtung, jeden spezifischen Dienst oder sogar mehr als eine Sache zu nutzen. Aber jetzt ist es an der Zeit, diese Dienste etwas greifbarer zu machen und zu zeigen, was Sie mit Firebase tun können.
Eine großartige Möglichkeit zu lernen ist, etwas funktionieren zu sehen. Der erste Abschnitt unten hilft Ihnen bei der Einrichtung von Firebase-Diensten. Die folgenden Abschnitte beleuchten die Firebase-Details einer Demo-App, um zu zeigen, wie Firebase-Funktionen genutzt werden. Obwohl dies ein relativ umfassender Leitfaden für Firebase ist, handelt es sich nicht um ein Schritt-für-Schritt-Tutorial. Ziel ist es, die funktionierenden Teile in den eingebetteten Demos hervorzuheben, um in diesem einen Artikel mehr abzudecken. Wenn Sie Schritt-für-Schritt-Firebase-Tutorials wünschen, hinterlassen Sie einen Kommentar, um mich zu motivieren, einen zu schreiben.
Eine grundlegende Firebase-Einrichtung
Dieser Abschnitt ist hilfreich, wenn Sie planen, die Demo mit Ihrem eigenen Firebase-Backend zu forken. Sie können diesen Abschnitt überspringen, wenn Sie mit Firebase-Projekten vertraut sind oder einfach nur die schicken Demos sehen möchten.
Firebase ist ein Cloud-basierter Dienst, was bedeutet, dass Sie eine grundlegende Kontoeinrichtung vornehmen müssen, bevor Sie seine Dienste nutzen können. Die Firebase-Entwicklung ist jedoch nicht an eine Netzwerkverbindung gebunden. Es ist sehr erwähnenswert, dass Sie Firebase für die Entwicklung lokal auf Ihrem Rechner ausführen können (und das sollten Sie normalerweise auch). Diese Anleitung demonstriert die Erstellung einer App mit CodePen, was bedeutet, dass ein Cloud-verbundener Dienst benötigt wird. Ziel ist es hier, Ihr persönliches Backend mit Firebase zu erstellen und dann die Konfiguration abzurufen, die das Frontend benötigt, um sich damit zu verbinden.
Ein Firebase-Projekt erstellen
Gehen Sie zur Firebase Console. Sie werden gefragt, ob Sie Google Analytics einrichten möchten. Keines dieser Beispiele verwendet es, sodass Sie es überspringen und später bei Bedarf wieder hinzufügen können.
Eine Web-Firebase-App erstellen
Als Nächstes sehen Sie Optionen zum Erstellen einer „App“. Klicken Sie auf die Web-Option und geben Sie ihr einen Namen – jeder Name ist in Ordnung. Firebase-Projekte können mehrere „Apps“ enthalten. Ich werde nicht tief in diese Hierarchie eintauchen, da sie für den Einstieg nicht so wichtig ist. Sobald die App erstellt ist, erhalten Sie ein Konfigurationsobjekt.

let firebaseConfig = {
apiKey: "your-key",
authDomain: "your-domain.firebaseapp.com",
projectId: "your-projectId",
storageBucket: "your-projectId.appspot.com",
messagingSenderId: "your-senderId",
appId: "your-appId",
measurementId: "your-measurementId"
};
Dies ist die Konfiguration, die Sie im Frontend verwenden, um sich mit Firebase zu verbinden. Machen Sie sich keine Sorgen um die Sicherheit dieser Eigenschaften. Es ist nichts Unsicheres daran, diese Eigenschaften in Ihrem Frontend-Code zu enthalten. Sie lernen in einem der folgenden Abschnitte, wie Sicherheit in Firebase funktioniert.
Jetzt ist es an der Zeit, diese erstellte „App“ im Code darzustellen. Diese „App“ ist lediglich ein Container, der Logik und Authentifizierungsstatus zwischen verschiedenen Firebase-Diensten teilt. Firebase bietet eine Reihe von Bibliotheken, die die Entwicklung erheblich erleichtern. In diesem Beispiel verwende ich sie von einem CDN, aber sie funktionieren auch gut mit Modul-Bundlern wie Webpack und Rollup.
// This pen adds Firebase via the "Add External Scripts" option in codepen
// https://www.gstatic.com/firebasejs/8.2.10/firebase-app.js
// https://www.gstatic.com/firebasejs/8.2.10/firebase-auth.js
// Create a Project at the Firebase Console
// (console.firebase.google.com)
let firebaseConfig = {
apiKey: "your-key",
authDomain: "your-domain.firebaseapp.com",
projectId: "your-projectId",
storageBucket: "your-projectId.appspot.com",
messagingSenderId: "your-senderId",
appId: "your-appId",
measurementId: "your-measurementId"
};
// Create your Firebase app
let firebaseApp = firebase.initializeApp(firebaseConfig);
// The auth instance
console.log(firebaseApp.auth());
Großartig! Sie sind so, so nah dran, mit Ihrem ganz eigenen Firebase-Backend kommunizieren zu können. Jetzt müssen Sie die Dienste aktivieren, die Sie nutzen möchten.
Authentifizierungsanbieter aktivieren
Die folgenden Beispiele verwenden die Authentifizierung, um Benutzer anzumelden und Daten in der Datenbank zu sichern. Wenn Sie ein neues Firebase-Projekt erstellen, sind alle Ihre Authentifizierungsanbieter deaktiviert. Dies ist anfangs unbequem, aber für die Sicherheit unerlässlich. Sie möchten nicht, dass Benutzer versuchen, sich mit Anbietern anzumelden, die Ihr Backend nicht unterstützt.

Um einen Anbieter zu aktivieren, gehen Sie zum Tab Authentifizierung in der Seitenleiste und klicken Sie dann oben auf die Schaltfläche „Anmeldemethode“. Darunter sehen Sie eine große Liste von Anbietern wie E-Mail und Passwort, Google, Facebook, GitHub, Microsoft und Twitter. Für die folgenden Beispiele müssen Sie Google und Anonym aktivieren. Google befindet sich oben in der Liste und Anonym am Ende. Wenn Sie Google auswählen, werden Sie aufgefordert, eine Support-E-Mail-Adresse anzugeben. Ich empfehle, Ihre persönliche E-Mail-Adresse zum Testen einzugeben, aber Produktions-Apps sollten eine dedizierte E-Mail haben.
Wenn Sie die Authentifizierung innerhalb von CodePen verwenden möchten, müssen Sie auch CodePen als autorisierte Domain hinzufügen. Autorisierte Domains können Sie am unteren Rand des Tabs „Anmeldemethode“ hinzufügen.

Eine wichtige Anmerkung zu dieser Autorisierung: Dies erlaubt jedem Projekt, das auf cdpn.io gehostet wird, sich bei Ihrem Firebase-Projekt anzumelden. Für kurzfristige Demo-Zwecke gibt es kein großes Risiko. Die Nutzung von Firebase Auth ist kostenlos, abgesehen von der Telefonnummern-Authentifizierung. Idealerweise möchten Sie dies nicht als autorisierte Domain beibehalten, wenn Sie diese App in einer Produktionsumgebung nutzen möchten.
Nun zum letzten Schritt in der Firebase Console: Erstellen einer Firestore-Datenbank!
Eine Firestore-Datenbank erstellen
Klicken Sie in der linken Navigation auf Firestore. Von hier aus müssen Sie auf die Schaltfläche klicken, um die Firestore-Datenbank zu erstellen. Sie werden gefragt, ob Sie im „Produktionsmodus“ oder im „Testmodus“ beginnen möchten. Für dieses Beispiel möchten Sie den „Testmodus“. Wenn Sie sich Sorgen um die Sicherheit machen, werden wir das im letzten Abschnitt behandeln.

Jetzt, da Sie die Grundlagen kennen, kommen wir zu einigen realen Anwendungsfällen.
Benutzer authentifizieren
Die besten Teile einer App liegen normalerweise hinter einem Anmeldeformular. Warum lassen wir den Benutzer nicht einfach als Gast herein, damit er es selbst sehen kann? Systeme erfordern oft Konten, weil das Backend nicht für Gäste ausgelegt ist. Es gibt eine Systemanforderung, eine heilige userId-Eigenschaft zu haben, um jeden Datensatz zu speichern, der zu einem Benutzer gehört. Hier sind „Gast“-Konten hilfreich. Sie bieten Nutzern mit geringem Aufwand den Einstieg und geben ihnen eine temporäre userId, die das System zufriedenstellt. Firebase Auth bietet einen Prozess, um genau das zu tun.
Anonyme Authentifizierung einrichten
Eines meiner Lieblingsfeatures von Firebase Auth ist die anonyme Authentifizierung. Es gibt zwei Vorteile. Erstens können Sie einen Benutzer authentifizieren, ohne Eingaben (z. B. Passwörter, Telefonnummer usw.) entgegenzunehmen. Zweitens werden Sie wirklich gut im Tippen von „anonymous“. Es ist wirklich eine Win-Win-Situation.
Nehmen Sie zum Beispiel dieses CodePen.
Es ist ein Formular, das dem Benutzer erlaubt zu entscheiden, ob er sich mit Google oder als Gast anmelden möchte. Der Großteil des Codes in diesem Beispiel ist spezifisch für die Benutzeroberfläche. Die Firebase-Teile sind eigentlich ziemlich einfach.
// Firebase-specific code
let firebaseConfig = { /* config */ };
let firebaseApp = firebase.initializeApp(firebaseConfig);
// End Firebase-specific code
let socialForm = document.querySelector('form.sign-in-social');
let guestForm = document.querySelector('form.sign-in-guest');
guestForm.addEventListener('submit', async submitEvent => {
submitEvent.preventDefault();
let formData = new FormData(guestForm);
let displayName = formData.get('name');
let photoURL = await getRandomPhotoURL();
// Firebase-specific code
let { user } = await firebaseApp.auth().signInAnonymously();
await user.updateProfile({ displayName, photoURL });
// End Firebase-specific code
});
In den 17 Codezeilen oben (ohne Kommentare) sind nur fünf Firebase-spezifisch. Vier Zeilen werden zum Importieren und Konfigurieren benötigt. Zwei Zeilen zum Aufrufen von signInAnonymously() und user.updateProfile(). Die erste Anmeldemethode ruft Ihr Firebase-Backend auf und authentifiziert den Benutzer. Der Aufruf gibt ein Ergebnis zurück, das die benötigten Eigenschaften wie die uid enthält. Selbst bei Gastbenutzern können Sie mit dieser uid Daten in Ihrem Backend einem Benutzer zuordnen. Nachdem der Benutzer angemeldet ist, ruft das Beispiel updateProfile auf dem Benutzerobjekt auf. Auch wenn dieser Benutzer ein Gast ist, kann er dennoch einen Anzeigenamen und ein Profilbild haben.
Google-Authentifizierung einrichten
Die gute Nachricht ist, dass dies mit allen anderen permanenten Anbietern, wie E-Mail und Passwort, Google, Facebook, Twitter, GitHub, Microsoft, Telefonnummer und vielem mehr, auf die exakt gleiche Weise funktioniert. Die Implementierung der Google-Anmeldung erfordert ebenfalls nur wenige Zeilen Code.
socialForm.addEventListener('submit', submitEvent => {
submitEvent.preventDefault();
// Firebase-specific code
let provider = new firebase.auth.GoogleAuthProvider();
firebaseApp.auth().signInWithRedirect(provider);
// End Firebase-specific code
});
Jeder soziale Anbieter initiiert einen auf Weiterleitungen basierenden Authentifizierungsablauf. Das ist eine schicke Art zu sagen, dass die Methode signInWithRedirect zur Anmeldeseite des Anbieters weiterleitet und dann mit dem authentifizierten Benutzer zu Ihrer App zurückkehrt. In diesem Fall wird der Benutzer zur Google-Anmeldeseite weitergeleitet, meldet sich an und kehrt dann zu Ihrer App zurück.
Authentifizierungsstatus überwachen
Wie erhält man den Benutzer nach dieser Weiterleitung zurück? Es gibt ein paar Möglichkeiten, aber ich werde die gängigste wählen. Sie können den Authentifizierungsstatus jedes aktiven Benutzers erkennen, ob er angemeldet oder abgemeldet ist.
firebaseApp.auth().onAuthStateChanged(user => {
if(user != null) {
console.log(user.toJSON());
} else {
console.log("No user!");
}
});
Die Methode onAuthStateChanged aktualisiert sich, wenn sich der Authentifizierungsstatus eines Benutzers ändert. Sie wird zunächst beim Laden der Seite ausgelöst und informiert Sie darüber, ob ein Benutzer angemeldet ist, sich anmeldet oder abmeldet. Dies ermöglicht Ihnen, eine Benutzeroberfläche zu erstellen, die auf diese Zustandsänderungen reagiert. Sie passt auch gut zu clientseitigen Routen, da sie einen Benutzer mit wenig Code zur richtigen Seite weiterleiten kann.
Die App in diesem Fall verwendet nur <template>-Tags, um den Inhalt des „phone“-Elements zu ersetzen. Wenn der Benutzer angemeldet ist, leitet die App zur neuen Vorlage weiter.
<div class="container">
<div class="phone">
<!-- Phone contents replaced with template tags -->
</div>
</div>
Dies bietet eine einfache Beziehung. Das .phone ist die „Hauptansicht“. Jedes <template>-Tag ist eine „Unteransicht“. Der Authentifizierungsstatus bestimmt, welche Ansicht angezeigt wird.
firebaseApp.auth().onAuthStateChanged(user => {
if(user != null) {
// Show demo view
routeTo("demo", firebaseApp, user);
} else {
console.log("No user!");
// Show log in page
routeTo("signIn", firebaseApp);
}
});
Die eingebettete Demo ist nicht „produktionsreif“, da die Anforderungen nur die Arbeit innerhalb eines einzigen CodePens umfassten. Ziel war es, die Lesbarkeit zu erleichtern, wobei jede „Ansicht“ innerhalb eines Vorlagen-Tags enthalten war. Dies ahmt lose nach, wie eine gängige Routing-Lösung mit einem Framework aussehen würde.
Ein wichtiger Punkt, der hier zu beachten ist: Das Benutzerobjekt wird an die Funktion routeTo übergeben. Das Ermitteln des Anmeldestatus ist asynchron. Ich finde, es ist viel einfacher, den Benutzerstatus an die Ansicht weiterzugeben, als asynchrone Aufrufe innerhalb der Ansicht zu tätigen. Viele Framework-Router haben einen Platz für diese Art von asynchroner Datenabfrage.
Gäste in permanente Benutzer umwandeln
Das <template id="demo">-Tag hat eine Submit-Schaltfläche zum Umwandeln von Gästen in permanente Benutzer. Dies geschieht, indem der Benutzer sich mit dem Hauptanbieter (wiederum Google in diesem Fall) anmeldet.
let convertForm = document.querySelector('form.convert');
convertForm.addEventListener("submit", submitEvent => {
submitEvent.preventDefault();
let provider = new firebase.auth.GoogleAuthProvider();
firebaseApp.auth().currentUser.linkWithRedirect(provider);
});
Die Verwendung der Methode linkWithRedirect leitet den Benutzer zur Authentifizierung mit dem sozialen Anbieter weiter. Wenn die Weiterleitung zurückkehrt, wird das Konto zusammengeführt. Es gibt nichts, was Sie an der Methode onAuthStateChanged ändern müssen, die das Routing der „Kindansicht“ steuert. Wichtig ist, dass die uid gleich bleibt.
Fehler bei der Zusammenführung von Konten behandeln
Beim Zusammenführen von Konten können einige Randfälle auftreten. In einigen Fällen hat ein Benutzer möglicherweise bereits ein Konto mit Google erstellt und versucht nun, dieses bestehende Konto zusammenzuführen. Es gibt viele Möglichkeiten, dieses Szenario zu behandeln, je nachdem, wie Ihre App funktionieren soll. Ich werde hier nicht tief darauf eingehen, da wir noch viel mehr zu behandeln haben, aber es ist wichtig zu wissen, wie man diese Fehler behandelt.
async function checkForRedirect() {
let auth = firebaseApp.auth();
try {
let result = await auth.getRedirectResult();
}
catch (error) {
switch(error.code) {
case 'auth/credential-already-in-use': {
// You can check for the provider(s) in use
let providers = await auth.fetchProvidersForEmail(error.email);
// Then decide what strategy to take. A possible strategy is
// notifying the user and asking them to sign in as that account
}
}
}
}
Der obige Code verwendet die Methode getRedirectResult, um zu erkennen, ob ein Benutzer direkt von einer sozialen Anmeldungsumleitung zurückgekehrt ist. Wenn ja, enthält dieses Ergebnis viele Informationen. Am wichtigsten ist hier, dass wir wissen wollen, ob es ein Problem gab. Firebase Auth löst einen Fehler aus und liefert relevante Informationen über den Fehler, wie z. B. die E-Mail-Adresse und die Anmeldeinformationen, die es Ihnen ermöglichen, mit der Zusammenführung des Kontos fortzufahren. Das ist nicht immer das, was Sie tun möchten. In diesem Fall würde ich dem Benutzer wahrscheinlich anzeigen, dass das Konto existiert, und ihn auffordern, sich damit anzumelden. Aber ich schweife ab; ich könnte stundenlang über Anmeldeformulare reden.
Nun geht es darum, die Datenvisualisierung zu erstellen (okay, es ist nur ein Tortendiagramm) und ihr einen Echtzeit-Datenstrom bereitzustellen.
Datenvisualisierung einrichten
Ich werde ehrlich sein. Ich habe keine Ahnung, was diese App wirklich tut. Ich wollte wirklich das Erstellen von Tortendiagrammen mit einem conic-gradient ausprobieren. Ich war begeistert davon, CSS Custom Properties zu verwenden, um die Werte des Diagramms zu ändern und diese in Echtzeit mit einer Datenbank wie Firestore zu synchronisieren. Machen wir einen kurzen Abstecher, um zu besprechen, wie conic-gradient funktioniert.
Ein conic-gradient ist ein überraschend gut unterstütztes CSS-Feature. Sein Hauptmerkmal ist, dass seine Farbstopps am Umfang des Kreises platziert werden.
.pie-chart {
background-image: conic-gradient(
purple 10%, /* 10% of the circumference */
magenta 0 20%, /* start at 0 go 20%, acts like 10% */
cyan 0 /* Fill the rest */
);
}
Sie können ein Tortendiagramm mit schneller Mathematik erstellen: lastStopPercent + percent. Ich habe diese Werte in vier CSS Custom Properties in der App-Pen gespeichert: --pie-{n}-value (ersetzen Sie n durch eine Zahl). Diese Werte werden in einer weiteren benutzerdefinierten Eigenschaft verwendet, die wie eine berechnete Funktion fungiert.
:root {
--pie-1-value: 10%;
--pie-2-value: 10%;
--pie-3-value: 80%;
--pie-1-computed: var(--pie-1-value);
--pie-2-computed: 0 calc(var(--pie-1-value) + var(--pie-2-value));
--pie-3-computed: 0 calc(var(--pie-2-value) + var(--pie-3-value));
}
Dann werden die berechneten Werte im conic-gradient gesetzt.
background-image: conic-gradient(
purple var(--pie-1-computed),
magenta var(--pie-2-computed),
cyan 0
);
Der letzte berechnete Wert, --pie-3-computed, wird ignoriert, da er immer bis zum Ende füllt (ähnlich wie z bei SVG-Pfaden). Ich denke, es ist immer noch eine gute Idee, ihn in JavaScript zu setzen, damit alles Sinn ergibt.
function setPieChartValue(percentage, index) {
let root = document.documentElement;
root.style.setProperty(`--pie-${index+1}-value`, `${percentage}%`);
}
let percentages = [25, 35, 60];
percentages.forEach(setPieChartValue);
Mit diesem neu gewonnenen Wissen können Sie das Tortendiagramm mit jedem Datensatz verbinden. Die Firestore-Datenbank verfügt über eine Methode .onSnapshot(), die Daten aus Ihrer Datenbank streamt.
const fullPathDoc = firebaseApp.firestore().doc('/users/1234/expenses/3-2021');
fullPathDoc.onSnapshot(snap => {
const { items } = doc.data();
items.forEach(setPieChartValue);
});
Ein Echtzeit-Update löst die Methode .onSnapshot() aus, wann immer sich ein Wert in Ihrer Firestore-Datenbank an diesem Dokumentenstandort ändert. Nun fragen Sie sich vielleicht: Was ist ein Dokumentenstandort? Wie speichere ich überhaupt Daten in dieser Datenbank? Lassen Sie uns eintauchen, wie Firestore funktioniert und wie man Daten in NoSQL-Datenbanken modelliert.
Daten in NoSQL-Datenbanken modellieren
Firestore ist eine Dokumenten- (NoSQL) Datenbank. Sie bietet ein hierarchisches Muster von Sammlungen, die eine Liste von Dokumenten sind. Betrachten Sie ein Dokument wie ein JSON-Objekt, das viele weitere Datentypen enthält. Ein Dokument kann selbst eine Sammlung enthalten, die als Unter-Sammlung bezeichnet wird. Dies ist gut für die Strukturierung von Daten in einem „Eltern-Kind“- oder hierarchischen Muster.
Wenn Sie die Voraussetzungen im Abschnitt oben nicht befolgt haben, lesen Sie ihn noch einmal, um sicherzustellen, dass Sie eine Firestore-Datenbank erstellt haben, bevor Sie diesen Code selbst verwenden.
Ähnlich wie bei Auth müssen Sie zuerst Firestore oben importieren.
// This pen adds Firebase via the "Add External Scripts" option in codepen
// https://www.gstatic.com/firebasejs/8.2.10/firebase-app.js
// https://www.gstatic.com/firebasejs/8.2.10/firebase-auth.js
// https://www.gstatic.com/firebasejs/8.2.10/firebase-firestore.js
let firebaseConfig = { /* config */ };
let firebaseApp = firebase.initializeApp(firebaseConfig);
Dies teilt der Firebase-Client-Bibliothek mit, wie sie sich mit Ihrer Firestore-Datenbank verbindet. Mit dieser Einrichtung können Sie eine Referenz auf ein Datenelement in Ihrer Datenbank erstellen.
// Reference to collection stored at: '/expenses'
const expensesCol = firebaseApp.firestore('expenses');
// Retrieve a snapshot of data (not in realtime)
// Top level await is coming! (v8.dev/features/top-level-await)
const snapshot = await expensesCol.get();
const expenses = snapshot.docs.map(d => d.data());
Der obige Code erstellt eine „Collection Reference“ und ruft dann die Methode .get() auf, um den Daten-Snapshot abzurufen. Dies sind nicht die Daten selbst; es ist ein Wrapper, der viele hilfreiche Methoden und Metadaten zu den Daten enthält. Die letzte Zeile „entpackt“ den Snapshot, indem sie über das .docs-Array iteriert und die Funktion .data() für jeden „Document Snapshot“ aufruft. Beachten Sie, dass dies kein Echtzeit-Update ist, aber das kommt gleich!
Was hier wirklich wichtig zu verstehen ist, ist die Datenstruktur (manchmal Datenmodell genannt). Diese App speichert die „Ausgaben“ eines Benutzers. Nehmen wir an, das Dokument hat die folgende Struktur.
{
uid: '1234',
items: [
{ label: "Food", value: 10 },
{ label: "Services", value: 24 },
{ label: "Rent", value: 30 },
{ label: "Oops", value: 38 }
]
}
Die Eigenschaften eines Dokuments werden als Feld bezeichnet. Dieses Dokument hat ein Array-Feld mit items. Jeder Artikel enthält eine label-Zeichenkette und eine value-Zahl. Es gibt auch ein Zeichenkettenfeld namens uid, das die id des Benutzers speichert, dem die Daten gehören. Diese Struktur vereinfacht den Prozess des Iterierens über die Werte zur Erstellung des Tortendiagramms. Dieser Teil ist gelöst, aber wie finden wir heraus, wie wir zu den Ausgaben eines bestimmten Benutzers gelangen?
Eine traditionelle Methode zum Abrufen von Daten basierend auf einer Einschränkung ist die Verwendung einer Abfrage. Das können Sie in Firestore mit einer .where()-Methode tun.
// Let's pretend currentUser.uid === '1234'
const currentUser = firebaseApp.auth().currentUser;
// Reference to collection stored at: '/expenses'
const expensesCol = firebaseApp.firestore('expenses');
// Query for the expenses belonging to uid == 1234
const userQuery = expensesCol.where('uid', '==', currentUser.uid);
const snapshot = await userQuery.get();
Diese Struktur ist in Ordnung, nutzt aber nicht die Hierarchie von Sammlungen und vor allem von Unter-Sammlungen voll aus. Stattdessen können Sie Ihre Daten in einer „Eltern-Kind“-Beziehung strukturieren. Strukturen in Firestore funktionieren ähnlich wie URLs für eine Website. Sie können Pfade so gestalten, dass sie Route-Parameter-ähnliche Wildcards enthalten.
/users/:uid/expenses/month-year
Der obige Pfad strukturiert die Daten mit einer Top-Level-Sammlung von /users, dann einem Dokument, das einer uid zugeordnet ist, gefolgt von einer Unter-Sammlung. Unter-Sammlungen können existieren, auch wenn kein übergeordnetes Dokument vorhanden ist. Jede Unter-Sammlung enthält ein Dokument, in dem Sie die Ausgaben abrufen können, indem Sie das Jahr als Zahl (z. B. 3 für März) und das Jahr (2021) angeben.
// Let's pretend currentUser.uid === '1234'
const currentUser = firebaseApp.auth().currentUser;
// Reference to collection stored at: '/users'
const usersCol = firebaseApp.firestore().collection('users');
// Reference to document stored at: '/users/1234';
const userDoc = usersCol.doc(currentUser.uid);
// Reference to sub-collection stored at: '/users/1234/expenses'
const userExpensesCol = userDoc.collection('expenses');
// Reference to document stored at: '/users/1234/expenses/3-2021';
const marchDoc = userExpensesCol.doc('3-2021');
// Alternatively, you could express a full path:
const fullPathDoc = firebaseApp.firestore().doc('/users/1234/expenses/3-2021');
Das obige Beispiel zeigt, dass Sie mit ein wenig Modellierung ein Datenelement abrufen können, ohne eine Abfrage schreiben zu müssen. Dies wird nicht immer für jede beliebige Datenstruktur gelten. In vielen Fällen ist es sinnvoll, eine Top-Level-Sammlung zu haben. Es kommt auf die Art der Abfragen an, die Sie schreiben möchten, und wie Sie Ihre Daten sichern möchten. Es ist jedoch gut, Ihre Optionen beim Modellieren der Daten zu kennen. Wenn Sie mehr über dieses Thema erfahren möchten, hat mein Kollege Todd Kerpelman eine umfassende Serie über Firestore aufgenommen.
Wir werden in dieser App den hierarchischen Ansatz verfolgen. Mit diesen strukturierten Daten streamen wir in Echtzeit.
Daten an die Visualisierung streamen
Der obige Abschnitt beschreibt, wie Daten „einmalig“ mit .get() abgerufen werden. Sowohl Dokumente als auch Sammlungen haben auch eine Methode .onSnapshot(), die es Ihnen ermöglicht, die Daten in Echtzeit zu streamen.
const fullPathDoc = firebaseApp.firestore().doc('/users/1234/expenses/3-2021');
fullPathDoc.onSnapshot(snap => {
const { items } = doc.data();
items.forEach((item, index) => {
console.log(item);
});
});
Wenn eine Aktualisierung für die unter fullPathDoc gespeicherten Daten stattfindet, streamt Firestore die Aktualisierung an alle verbundenen Clients. Mit dieser Datensynchronisation können Sie alle CSS Custom Properties für das Tortendiagramm einstellen.
let db = firebaseApp.firestore();
let { uid } = firebaseApp.auth().currentUser;
let marchDoc = db.doc(`users/${uid}/expenses/3-2021`);
marchDoc.onSnapshot(snap => {
let { factors } = snap.data();
factors.forEach((factor, index) => {
root.style.setProperty(`--pie-${index+1}__value`, `${factor.value}%`);
});
});
Jetzt zum spaßigen Teil! Aktualisieren Sie die Daten in der Datenbank und sehen Sie, wie sich die Tortenscheiben bewegen.

Ehrlich gesagt, das macht so viel Spaß. Ich arbeite seit fast sieben Jahren mit Firebase und werde nie müde, die blitzschnellen Datenaktualisierungen zu sehen. Aber die Arbeit ist noch nicht getan! Die Datenbank ist unsicher, da sie von jedem und überall aktualisiert werden kann. Es ist Zeit, sicherzustellen, dass sie nur für den Benutzer sicher ist, dem die Daten gehören.
Datenbank sichern
Wenn Sie neu bei Firebase oder der Backend-Entwicklung sind, fragen Sie sich vielleicht, warum die Datenbank im Moment unsicher ist. Firebase ermöglicht es Ihnen, Apps zu erstellen, ohne Ihren eigenen Server auszuführen. Das bedeutet, dass Sie direkt aus dem Browser auf eine Datenbank zugreifen können. Wenn es also so einfach ist, auf die Datenbank zuzugreifen, was hindert jemanden daran, etwas Böses zu tun? Die Antwort sind Firebase Security Rules.
Security Rules sind die Methode, mit der Sie den Zugriff auf Ihre Firebase-Dienste sichern. Sie schreiben eine Reihe von Regeln, die festlegen, wie auf Daten in Ihrem Backend zugegriffen wird. Firebase wertet diese Regeln für jede Anfrage aus, die an Ihr Backend gesendet wird, und erlaubt die Anfrage nur, wenn sie die Regel besteht. Mit anderen Worten: Sie schreiben eine Reihe von Regeln und Firebase führt diese auf dem Server aus, um den Zugriff auf Ihre Dienste zu sichern.
Security Rules sind wie ein Router
Security Rules sind eine eigene Sprache, die stark wie ein Router funktioniert.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// When a request comes in for a "user/:userId"
// let's allow the read or write (not very secure)
// Don't copy this in your code plz!
match /users/{userId} {
allow read, write: if userId == "david";
}
}
}
Das obige Beispiel beginnt mit einer rules_version-Anweisung. Machen Sie sich darüber nicht zu viele Gedanken, aber so teilen Sie Firebase die Version der Security Rules-Sprache mit, die Sie verwenden möchten. Derzeit wird empfohlen, Version 2 zu verwenden. Dann erstellt das Beispiel eine Service-Deklaration. Dies teilt Firebase mit, welchen Dienst Sie sichern möchten, in diesem Fall Firestore. Nun zum wichtigen Teil: den match-Anweisungen.
Eine match-Anweisung ist der Teil, der Regeln wie einen Router funktionieren lässt. Die erste match-Anweisung im Beispiel legt fest, dass Sie Dokumente in der Datenbank abgleichen. Es ist eine sehr allgemeine Aussage, die besagt: „Hey, schau im Dokumentenbereich nach.“ Die nächste match-Anweisung ist spezifischer. Sie versucht, ein Dokument in der users-Sammlung abzugleichen. Die Pfadsyntax von /users/{userId} ähnelt der Routing-Syntax von /users/:userId, wobei die :userId-Syntax einen Routenparameter angibt. In Security Rules funktioniert die {userId}-Syntax genauso wie ein Routenparameter, außer dass sie hier „Wildcard“ genannt wird. Jede Benutzer innerhalb der Sammlung kann mit dieser Anweisung abgeglichen werden. Was passiert, wenn der Benutzer abgeglichen wird? Sie verwenden die allow-Anweisung, um den Zugriff zu steuern.
Die allow-Anweisung wertet einen Ausdruck aus und, wenn das Ergebnis true ist, erlaubt sie die Operation. Wenn es false ist, wird die Operation abgelehnt. Das Nützliche an der allow-Anweisung ist, dass viele nützliche Informationen im umschließenden match-Block verfügbar sind. Eine nützliche Information ist die Wildcard selbst. Das obige Beispiel verwendet die userId-Wildcard wie eine Variable und testet, ob sie mit dem Wert "``david``" übereinstimmt. Nur eine userId von "``david``" erlaubt die read- oder write-Operation.
Das ist keine sehr nützliche Regel, aber sie hilft, einfach anzufangen. Nehmen wir uns einen Moment Zeit, um uns an die Struktur der Datenbank zu erinnern. Security Rules sind sehr ähnlich zu Annotationen über Ihrer Datenstruktur. Sie können an Dokumentpfaden Notizen machen, die Ihren Datenzugriff erzwingen. Diese App speichert Daten in einer /users/{userId}-Sammlung und Ausgaben in einer /users/{userId}/expenses/month-year-Unter-Sammlung. Die Sicherheitsstrategie besteht darin, sicherzustellen, dass nur der authentifizierte Benutzer seine Daten lesen oder schreiben kann.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{documents=**} {
allow read, write: if request.auth.uid == userId;
}
}
}
Das obige Beispiel beginnt gleich, ändert sich aber, wenn es den /users/{userId}-Pfad abgleicht. Am Ende hängt diese seltsame {documents=**}-Syntax. Dies wird als rekursive Wildcard bezeichnet und ist eine Möglichkeit, eine Regel auf Unter-Sammlungen zu kaskadieren – was bedeutet, dass auf jede Unter-Sammlung von /users/{userId} die gleichen Regeln angewendet werden. Dies ist großartig für den aktuellen Anwendungsfall, da sowohl /users/{userId} als auch /users/{userId}/expenses/month-year derselben Regel folgen sollten.
Innerhalb dieses match wurde die allow-Anweisung mit einer neuen Variablen namens request aktualisiert. Security Rules werden mit einem ganzen Satz von Variablen geliefert, die Ihnen helfen, ausgefeilte Regeln zu schreiben. Diese Variable dient dazu, zu bewerten, ob die Anfrage von einem authentifizierten Benutzer stammt. Die allow-Anweisung wertet aus, ob der authentifizierte Benutzer eine uid hat, die mit der {userId}-Wildcard übereinstimmt. Wenn diese Anweisung true ergibt, wird das Lesen oder Schreiben erlaubt. Wenn der Benutzer nicht authentifiziert ist oder nicht mit der {userId}-Wildcard übereinstimmt, ist keine Operation erlaubt. Daher ist es sicher!
Der folgende Ausschnitt zeigt zwei Anfragen von einem authentifizierten Benutzer.
// Let's pretend currentUser.uid === '1234'
const currentUser = firebaseApp.auth().currentUser;
// The authenticated user owns this sub-collection
const ownedDoc = firebaseApp.firestore().doc('/users/1234/expenses/3-2021');
// The authenticated user DOES NOT own this sub-collection
const notOwnedDoc = firebaseApp.firestore().doc('/users/abcxyz/expenses/3-2021');
try {
const ownedSnapshot = await ownedDoc.get();
const notOwnedSnapshot = await notOwnedDoc.get();
} catch (error) {
// This will result in an error because the `notOwnedDoc` request will fail the security rule
}
Damit haben Sie eine Sammlung und eine Unter-Sammlung gesichert. Aber was ist mit dem Rest der Daten in der Datenbank? Was passiert, wenn Sie keine Regeln für Daten an diesen Pfaden schreiben? Das obige Beispiel erlaubt nur den Zugriff, der mit der allow-Anweisung für die /users-Sammlung und ihre Unter-Sammlungen übereinstimmt. Keine anderen Lese- oder Schreibvorgänge funktionieren überhaupt für andere Sammlungen oder Unter-Sammlungen. Mit anderen Worten: Wenn Sie keine allow-Anweisung für einen Pfad schreiben, werden keine Lese- oder Schreibvorgänge zugelassen. Dies ist eine großartige Standardeinstellung für die Sicherheit, da Sie Ihren Zugriff an den entsprechenden Pfaden explizit erzwingen müssen. Sie können das jedoch auch vermasseln!
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Ahh!!! Never do this in a production app!!!
// This will negate any rule you write below!!
// Don't copy and paste this into your rules!!
match /{document=**} {
allow read, write: if true;
}
match /users/{userId}/{documents=**} {
allow read, write: if request.auth.uid == userId;
}
}
}
Das obige Beispiel fügt einen match-Block hinzu, der dem Pfad /{document=**} entspricht. Dies ist ein rekursiver Wildcard-Pfad, der jedem Dokument in der gesamten Datenbank entspricht. Die allow-Anweisung ergibt immer true, weil sie wahr ist. Dieser match-Block erstellt eine überlappende match-Anweisung, d.h. zwei oder mehr match-Blöcke, die auf denselben Pfad zutreffen. Dies ist nicht wie bei CSS, wo die letzte Regel gewinnt. Security Rules werten jede passende Regel aus und wenn eine davon true ergibt, wird die Operation erlaubt. Daher negiert die globale rekursive Wildcard jede Ihrer darunter liegenden sicheren Regeln. Die globale rekursive Wildcard ist eine Strategie, um Ihre Datenbank für einen kurzfristigen „Testmodus“ zu öffnen, in dem keine wichtigen, nicht öffentlich zugänglichen Daten (nichts Privates oder Wichtiges) gespeichert sind. Außerhalb dessen empfehle ich die Verwendung nicht.
Regeln lokal oder in der Konsole schreiben
Das letzte Thema, das wir ansprechen möchten, ist, wo Sie Ihre Regeln schreiben und speichern. Sie haben zwei Möglichkeiten. Die erste ist innerhalb der Firebase-Konsole. Innerhalb des Firestore-Datenviewers sehen Sie die Option „Rules“. Diese Registerkarte zeigt Ihnen die aktiven Regeln für Ihre Datenbank. Von hier aus können Sie Szenarien gegen Ihre Regeln schreiben und sogar testen. Dieser Ansatz wird für diejenigen empfohlen, die gerade erst anfangen und sich mit Security Rules vertraut machen möchten.

Eine andere Möglichkeit ist, Regeln lokal auf Ihrem Computer zu schreiben und die Firebase CLI zu verwenden, um sie in die Konsole zu deployen. Dies ermöglicht es Ihnen, sie im Quellcodeverwaltungssystem zu behalten und Tests dafür zu schreiben, um sicherzustellen, dass sie mit der Weiterentwicklung Ihrer Codebasis weiterhin funktionieren. Dies ist der empfohlene Ansatz für Produktions-Apps und Teams.
Es ist erwähnenswert, dass Ihre Firebase-Konfiguration, die Sie zur Erstellung einer Firebase-App verwenden, *nicht* unsicher ist. Es ist das Äquivalent dazu, wenn jemand den Domainnamen Ihrer Website kennt. Wenn jemand Ihren Domainnamen kennt, macht das Ihre Website nicht unsicher. Security Rules sind die Art und Weise, wie Firebase einen sicheren Zugriff auf Ihre Daten und Ihre Dienste bietet.
Zusammenfassung
Das war viel Firebase-Information, besonders über all die Regeln (Sicherheit ist wichtig!). Die Informationen in diesem Artikel melden Benutzer an, führen Gastkonten zusammen, strukturieren Daten, streamen sie in Echtzeit an eine Visualisierung und stellen sicher, dass alles sicher ist. Sie können diese Konzepte verwenden, um viele verschiedene Anwendungen zu erstellen.
Es gibt so viele Dinge, die ich Sie wissen lassen möchte, wenn Sie weiterhin mit Firebase erstellen möchten, wie die Emulator Suite. Die in diesem Artikel erstellte App kann lokal auf Ihrem Computer ausgeführt werden, was eine viel einfachere Entwicklungserfahrung bietet und sich hervorragend zum Testen in CI/CD-Umgebungen eignet. Es gibt auch viele großartige Firebase-Tools und Framework-Bibliotheken. Hier sind einige Links, die sich zu überprüfen lohnen.
- Firebase YouTube-Kanal
- Firebase Codelabs
- Die Firebase CLI
- Firebase lokal mit der Emulator Suite ausführen
- Der Firebase Podcast
- Framework-Bibliotheken, einschließlich AngularFire, ReactFire, VueFire, RxFire
Wenn es eine Sache gibt, die Sie in diesem Artikel gesehen haben sollten, dann ist es, dass es nicht zu viele Zeilen an Frontend-Firebase-Code gibt. Hier eine Zeile zum Anmelden eines Benutzers, dort ein paar Zeilen zum Abrufen der Daten, aber hauptsächlich Code, der spezifisch für die App selbst ist. Das Ziel von Firebase ist es, Ihnen zu ermöglichen, schnell zu erstellen. Entfernen Sie die Verantwortung für die Verwaltung der Backend-Infrastruktur. Konzentrieren Sie sich auf das Frontend.
Ausgezeichnete Zusammenfassung, danke für den Verweis auf den Artikel :pray
Fantastische Zusammenfassung, vielen Dank. Es wäre großartig, wenn Sie eine Schritt-für-Schritt-Anleitung zum Einrichten unserer ersten Firebase-App hinzufügen könnten. Es wäre interessant, einem solchen Tutorial zu folgen, um genau zu wissen, was zu tun ist und wie es zu tun ist.
Danke
Ein weiterer Wunsch nach einer Schritt-für-Schritt-Anleitung. Danke!
Mann, das war großartig. Können Sie die Regeln mit verschiedenen Szenarien aktualisieren, z.B. möchte ich, dass Leute online zu einem bestimmten Dokument lesen können.
Also ist es ein Framework (wie Laravel, Symfony), aber in Javascript statt PHP und die Datenbank ist in irgendeinem Cloud...?
Und die Datenbank ist keine Datenbank, sondern eine dateibasierte Speicherung (wie Grav)...?
Ich entwickle seit über einem Jahrzehnt Webanwendungen und habe so viel Zeit damit verbracht, das Backend mit Servercode und Datenbanken zu erstellen. Firebase ersetzt das nicht vollständig, aber ich habe kürzlich angefangen, es zu nutzen, und was für eine Erfrischung. Alles ist einfacher und schneller, wenn man Apps auf diese Weise entwickelt, und alles ist standardmäßig in Echtzeit. Ich muss immer noch Cloud-Funktionen und andere Dienste nutzen, wo Firebase zu kurz greift, aber insgesamt ist Firebase ein riesiger Gewinn für Entwickler.
Würde gerne Ihre Meinung zu folgenden Punkten hören:
1. Reduzierung von Aufrufen an Firebase zur Steigerung der Effizienz und Senkung der Kosten pro Nutzung
Beste Methoden für die Integration von Benutzerzahlungen zwischen der App und FB.
Vielen Dank,
C
Glückwunsch an CSS-Tricks für das hier. Ich bin in das „Kaninchenloch“ gefallen und habe erfahren, dass es viele Falschinformationen bezüglich Unter-Sammlungen gibt
Nachdem ich viele Dokumentationen und Videos von Firebase gelesen und gesehen hatte, fühlte es sich ein wenig verstreut an und ich konnte das Gesamtbild nicht erkennen, um weiterzukommen. Endlich habe ich beschlossen, diesem Artikel zu folgen und langsam fängt alles an, Sinn zu ergeben. Vielen Dank, Kumpel.