Tore
In diesem Codelab erstellen Sie eine Web-App für Restaurantempfehlungen, die von Cloud Firestore unterstützt wird .
Was du lernen wirst
- Lesen und Schreiben von Daten aus einer Web-App in den Cloud Firestore
- Hören Sie Änderungen in Cloud Firestore-Daten in Echtzeit ab
- Verwenden Sie Firebase-Authentifizierungs- und Sicherheitsregeln, um Cloud Firestore-Daten zu sichern
- Schreiben Sie komplexe Cloud Firestore-Abfragen
Was du brauchen wirst
Stellen Sie vor dem Starten dieses Codelabs sicher, dass Sie Folgendes installiert haben:
Erstellen Sie ein Firebase-Projekt
- Klicken Sie in der Firebase-Konsole auf Projekt hinzufügen und benennen Sie das Firebase-Projekt FriendlyEats .
Merken Sie sich die Projekt-ID für Ihr Firebase-Projekt.
- Klicken Sie auf Projekt erstellen .
Die Anwendung, die wir erstellen werden, verwendet einige im Web verfügbare Firebase-Dienste:
- Firebase-Authentifizierung zur einfachen Identifizierung Ihrer Benutzer
- Cloud Firestore zum Speichern strukturierter Daten in der Cloud und sofortige Benachrichtigung, wenn die Daten aktualisiert werden
- Firebase-Hosting zum Hosten und Bereitstellen Ihrer statischen Assets
Für dieses spezielle Codelab haben wir Firebase Hosting bereits konfiguriert. Für Firebase Auth und Cloud Firestore führen wir Sie jedoch durch die Konfiguration und Aktivierung der Dienste mithilfe der Firebase-Konsole.
Anonyme Authentifizierung aktivieren
Obwohl die Authentifizierung nicht im Mittelpunkt dieses Codelabs steht, ist es wichtig, eine Form der Authentifizierung in unserer App zu haben. Wir verwenden die anonyme Anmeldung. Dies bedeutet, dass der Benutzer ohne Aufforderung stillschweigend angemeldet wird.
Sie müssen die anonyme Anmeldung aktivieren .
- Suchen Sie in der Firebase-Konsole den Abschnitt Entwickeln im linken Navigationsbereich.
- Klicken Sie auf Authentifizierung, klicken Sie auf den Anmelde-Verfahren Registerkarte (oder klicken Sie hier um direkt dorthin zu gehen).
- Aktivieren Sie den anonymen Anmeldeanbieter und klicken Sie auf Speichern .
Auf diese Weise kann sich die Anwendung stillschweigend bei Ihren Benutzern anmelden, wenn diese auf die Webanwendung zugreifen. Weitere Informationen finden Sie in der Dokumentation zur anonymen Authentifizierung .
Cloud Firestore aktivieren
Die App verwendet Cloud Firestore, um Restaurantinformationen und Bewertungen zu speichern und zu empfangen.
Sie müssen den Cloud Firestore aktivieren. Klicken Sie im Abschnitt Entwickeln der Firebase-Konsole auf Firestore . Klicken Sie im Bereich Cloud Firestore auf Datenbank erstellen .
Der Zugriff auf Daten im Cloud Firestore wird durch Sicherheitsregeln gesteuert. Wir werden später in diesem Codelab mehr über Regeln sprechen, aber zuerst müssen wir einige Grundregeln für unsere Daten festlegen, um loszulegen. Fügen Sie auf der Registerkarte Regeln der Firebase-Konsole die folgenden Regeln hinzu und klicken Sie dann auf Veröffentlichen .
service cloud.firestore { match /databases/{database}/documents { match /{document=**} { // // WARNING: These rules are insecure! We will replace them with // more secure rules later in the codelab // allow read, write: if request.auth != null; } } }
Die oben genannten Regeln beschränken den Datenzugriff auf angemeldete Benutzer, wodurch verhindert wird, dass nicht authentifizierte Benutzer lesen oder schreiben. Dies ist besser als das Zulassen des öffentlichen Zugriffs, aber noch lange nicht sicher. Wir werden diese Regeln später im Codelab verbessern.
Klonen Sie das GitHub-Repository über die Befehlszeile:
git clone https://github.com/firebase/friendlyeats-web
Der Beispielcode sollte in das Verzeichnis 📁 friendlyeats-web
geklont worden sein. Stellen Sie sicher, dass Ihre Befehlszeile von nun an von diesem Verzeichnis aus ausgeführt wird:
cd friendlyeats-web
Importieren Sie die Starter-App
Öffnen oder importieren Sie mit Ihrer IDE (WebStorm, Atom, Sublime, Visual Studio Code ...) das Verzeichnis 📁 friendlyeats-web
. Dieses Verzeichnis enthält den Startcode für das Codelab, der aus einer noch nicht funktionierenden Restaurantempfehlungs-App besteht. Wir werden es in diesem Codelab funktionsfähig machen, sodass Sie den Code in diesem Verzeichnis bald bearbeiten müssen.
Über die Firebase-Befehlszeilenschnittstelle (CLI) können Sie Ihre Webanwendung lokal bereitstellen und Ihre Webanwendung für Firebase Hosting bereitstellen.
- Installieren Sie die CLI, indem Sie den folgenden Befehl npm ausführen:
npm -g install firebase-tools
- Stellen Sie sicher, dass die CLI korrekt installiert wurde, indem Sie den folgenden Befehl ausführen:
firebase --version
Stellen Sie sicher, dass die Version der Firebase-CLI Version 7.4.0 oder höher ist.
- Autorisieren Sie die Firebase-CLI, indem Sie den folgenden Befehl ausführen:
firebase login
Wir haben die Web-App-Vorlage so eingerichtet, dass die Konfiguration Ihrer App für Firebase Hosting aus dem lokalen Verzeichnis und den Dateien Ihrer App abgerufen wird. Dazu müssen wir Ihre App jedoch Ihrem Firebase-Projekt zuordnen.
- Stellen Sie sicher, dass Ihre Befehlszeile auf das lokale Verzeichnis Ihrer App zugreift.
- Verknüpfen Sie Ihre App mit Ihrem Firebase-Projekt, indem Sie den folgenden Befehl ausführen:
firebase use --add
- Wenn Sie dazu aufgefordert werden, wählen Sie Ihre Projekt-ID aus und geben Sie Ihrem Firebase-Projekt einen Alias.
Ein Alias ist nützlich, wenn Sie mehrere Umgebungen haben (Produktion, Staging usw.). Verwenden Sie für dieses Codelab jedoch nur den default
.
- Befolgen Sie die restlichen Anweisungen in Ihrer Befehlszeile.
Wir sind bereit, mit der Arbeit an unserer App zu beginnen! Lassen Sie uns unsere App lokal ausführen!
- Führen Sie den folgenden Firebase-CLI-Befehl aus:
firebase emulators:start --only hosting
- Ihre Befehlszeile sollte die folgende Antwort anzeigen:
hosting: Local server: http://localhost:5000
Wir verwenden den Firebase Hosting- Emulator, um unsere App lokal bereitzustellen. Die Web-App sollte jetzt unter http: // localhost: 5000 verfügbar sein.
- Öffnen Sie Ihre App unter http: // localhost: 5000 .
Sie sollten Ihre Kopie von FriendlyEats sehen, die mit Ihrem Firebase-Projekt verbunden wurde.
Die App hat sich automatisch mit Ihrem Firebase-Projekt verbunden und Sie stillschweigend als anonymer Benutzer angemeldet.
In diesem Abschnitt schreiben wir einige Daten in den Cloud Firestore, damit wir die Benutzeroberfläche der App füllen können. Dies kann manuell über die Firebase-Konsole erfolgen , wir werden dies jedoch in der App selbst tun, um ein grundlegendes Schreiben im Cloud Firestore zu demonstrieren.
Datenmodell
Firestore-Daten werden in Sammlungen, Dokumente, Felder und Untersammlungen aufgeteilt. Wir werden jedes Restaurant als Dokument in einer Sammlung der obersten Ebene speichern, die als restaurants
.
Später speichern wir jede Bewertung in einer Untersammlung, die als ratings
in jedem Restaurant bezeichnet wird.
Fügen Sie Restaurants zu Firestore hinzu
Das Hauptmodellobjekt in unserer App ist ein Restaurant. Lassen Sie uns schreiben einige Code, der ein Restaurant Dokument zum fügt restaurants
Sammlung.
- Öffnen Sie in Ihren heruntergeladenen Dateien
scripts/FriendlyEats.Data.js
. - Finden Sie die Funktion
FriendlyEats.prototype.addRestaurant
. - Ersetzen Sie die gesamte Funktion durch den folgenden Code.
FriendlyEats.Data.js
FriendlyEats.prototype.addRestaurant = function(data) { var collection = firebase.firestore().collection('restaurants'); return collection.add(data); };
Der obige Code fügt der restaurants
ein neues Dokument hinzu. Die Dokumentdaten stammen aus einem einfachen JavaScript-Objekt. Wir tun dies , indem man zuerst einen Verweis auf eine Wolke Firestor Sammlung bekommen restaurants
dann add
‚ing die Daten.
Fügen wir Restaurants hinzu!
- Kehren Sie in Ihrem Browser zu Ihrer FriendlyEats-App zurück und aktualisieren Sie sie.
- Klicken Sie auf Mock-Daten hinzufügen .
Die App generiert automatisch einen zufälligen Satz von Restaurantobjekten und ruft dann Ihre Funktion addRestaurant
. Sie werden die Daten jedoch noch nicht in Ihrer eigentlichen Web-App sehen, da das Abrufen der Daten noch implementiert werden muss (der nächste Abschnitt des Codelabs).
Wenn Sie jedoch in der Firebase-Konsole zur Registerkarte Cloud Firestore navigieren, sollten Sie jetzt neue Dokumente in der restaurants
!
Herzlichen Glückwunsch, Sie haben gerade Daten aus einer Web-App in den Cloud Firestore geschrieben!
Im nächsten Abschnitt erfahren Sie, wie Sie Daten aus dem Cloud Firestore abrufen und in Ihrer App anzeigen.
In diesem Abschnitt erfahren Sie, wie Sie Daten aus dem Cloud Firestore abrufen und in Ihrer App anzeigen. Die beiden wichtigsten Schritte sind das Erstellen einer Abfrage und das Hinzufügen eines Snapshot-Listeners. Dieser Listener wird über alle vorhandenen Daten benachrichtigt, die mit der Abfrage übereinstimmen, und erhält Aktualisierungen in Echtzeit.
Lassen Sie uns zunächst die Abfrage erstellen, die die standardmäßige, ungefilterte Liste der Restaurants liefert.
- Gehen Sie zurück zu den
scripts/FriendlyEats.Data.js
. - Finden Sie die Funktion
FriendlyEats.prototype.getAllRestaurants
. - Ersetzen Sie die gesamte Funktion durch den folgenden Code.
FriendlyEats.Data.js
FriendlyEats.prototype.getAllRestaurants = function(renderer) { var query = firebase.firestore() .collection('restaurants') .orderBy('avgRating', 'desc') .limit(50); this.getDocumentsInQuery(query, renderer); };
Im obigen Code erstellen wir eine Abfrage, mit der bis zu 50 Restaurants aus der Sammlung der obersten Ebene mit dem Namen " restaurants
abgerufen werden, die nach der Durchschnittsbewertung geordnet sind (derzeit alle Null). Nachdem wir diese Abfrage deklariert haben, übergeben wir sie an die Methode getDocumentsInQuery()
, die für das Laden und Rendern der Daten verantwortlich ist.
Dazu fügen wir einen Snapshot-Listener hinzu.
- Gehen Sie zurück zu den
scripts/FriendlyEats.Data.js
. - Suchen Sie die Funktion
FriendlyEats.prototype.getDocumentsInQuery
. - Ersetzen Sie die gesamte Funktion durch den folgenden Code.
FriendlyEats.Data.js
FriendlyEats.prototype.getDocumentsInQuery = function(query, renderer) { query.onSnapshot(function(snapshot) { if (!snapshot.size) return renderer.empty(); // Display "There are no restaurants". snapshot.docChanges().forEach(function(change) { if (change.type === 'removed') { renderer.remove(change.doc); } else { renderer.display(change.doc); } }); }); };
Im obigen Code löst query.onSnapshot
seinen Rückruf jedes Mal aus, query.onSnapshot
sich das Ergebnis der Abfrage ändert.
- Beim ersten Mal wird der Rückruf mit der gesamten Ergebnismenge der Abfrage ausgelöst, dh mit der gesamten
restaurants
von Cloud Firestore. Anschließend werden alle einzelnen Dokumente an die Funktionrenderer.display
. - Wenn ein Dokument gelöscht wird, entspricht
change.type
removed
. In diesem Fall rufen wir eine Funktion auf, mit der das Restaurant von der Benutzeroberfläche entfernt wird.
Nachdem wir beide Methoden implementiert haben, aktualisieren Sie die App und stellen Sie sicher, dass die Restaurants, die wir zuvor in der Firebase-Konsole gesehen haben, jetzt in der App sichtbar sind. Wenn Sie diesen Abschnitt erfolgreich abgeschlossen haben, liest und schreibt Ihre App jetzt Daten mit Cloud Firestore!
Wenn sich Ihre Liste der Restaurants ändert, wird dieser Listener automatisch aktualisiert. Gehen Sie zur Firebase-Konsole und löschen Sie ein Restaurant manuell oder ändern Sie seinen Namen. Die Änderungen werden sofort auf Ihrer Website angezeigt!
Bisher haben wir gezeigt, wie Sie mit onSnapshot
Updates in Echtzeit abrufen können. Das ist jedoch nicht immer das, was wir wollen. Manchmal ist es sinnvoller, die Daten nur einmal abzurufen.
Wir möchten eine Methode implementieren, die ausgelöst wird, wenn ein Benutzer in Ihrer App auf ein bestimmtes Restaurant klickt.
- Gehen Sie zurück zu Ihren
scripts/FriendlyEats.Data.js
. - Finden Sie die Funktion
FriendlyEats.prototype.getRestaurant
. - Ersetzen Sie die gesamte Funktion durch den folgenden Code.
FriendlyEats.Data.js
FriendlyEats.prototype.getRestaurant = function(id) { return firebase.firestore().collection('restaurants').doc(id).get(); };
Nachdem Sie diese Methode implementiert haben, können Sie Seiten für jedes Restaurant anzeigen. Klicken Sie einfach auf ein Restaurant in der Liste und Sie sollten die Detailseite des Restaurants sehen:
Derzeit können Sie keine Bewertungen hinzufügen, da wir das Hinzufügen von Bewertungen später im Codelab noch implementieren müssen.
Derzeit zeigt unsere App eine Liste von Restaurants an, aber der Benutzer kann nicht nach seinen Bedürfnissen filtern. In diesem Abschnitt verwenden Sie die erweiterte Abfrage von Cloud Firestore, um die Filterung zu aktivieren.
Hier ist ein Beispiel für eine einfache Abfrage zum Abrufen aller Dim Sum
Restaurants:
var filteredQuery = query.where('category', '==', 'Dim Sum')
Wie der Name schon sagt, lässt die where()
-Methode unsere Abfrage nur Mitglieder der Sammlung herunterladen, deren Felder den von uns festgelegten Einschränkungen entsprechen. In diesem Fall werden nur Restaurants heruntergeladen, deren category
Dim Sum
.
In unserer App kann der Benutzer mehrere Filter verketten, um bestimmte Abfragen zu erstellen, z. B. "Pizza in San Francisco" oder "Meeresfrüchte in Los Angeles, sortiert nach Beliebtheit".
Wir erstellen eine Methode, die eine Abfrage erstellt, die unsere Restaurants anhand mehrerer von unseren Benutzern ausgewählter Kriterien filtert.
- Gehen Sie zurück zu Ihren
scripts/FriendlyEats.Data.js
. - Suchen Sie die Funktion
FriendlyEats.prototype.getFilteredRestaurants
. - Ersetzen Sie die gesamte Funktion durch den folgenden Code.
FriendlyEats.Data.js
FriendlyEats.prototype.getFilteredRestaurants = function(filters, renderer) { var query = firebase.firestore().collection('restaurants'); if (filters.category !== 'Any') { query = query.where('category', '==', filters.category); } if (filters.city !== 'Any') { query = query.where('city', '==', filters.city); } if (filters.price !== 'Any') { query = query.where('price', '==', filters.price.length); } if (filters.sort === 'Rating') { query = query.orderBy('avgRating', 'desc'); } else if (filters.sort === 'Reviews') { query = query.orderBy('numRatings', 'desc'); } this.getDocumentsInQuery(query, renderer); };
Der obige Code fügt mehrere where
Filter und eine einzelne orderBy
Klausel hinzu, um eine zusammengesetzte Abfrage basierend auf Benutzereingaben zu erstellen. Unsere Abfrage gibt jetzt nur Restaurants zurück, die den Anforderungen des Benutzers entsprechen.
Aktualisieren Sie Ihre FriendlyEats-App in Ihrem Browser und stellen Sie sicher, dass Sie nach Preis, Stadt und Kategorie filtern können. Während des Testens werden in der JavaScript-Konsole Ihres Browsers folgende Fehler angezeigt:
The query requires an index. You can create it here: https://console.firebase.google.com/project/.../database/firestore/indexes?create_index=...
Diese Fehler sind darauf zurückzuführen, dass der Cloud Firestore für die meisten zusammengesetzten Abfragen Indizes benötigt. Durch das Erfordernis von Indizes für Abfragen bleibt der Cloud Firestore schnell skaliert.
Durch Öffnen des Links aus der Fehlermeldung wird automatisch die Benutzeroberfläche für die Indexerstellung in der Firebase-Konsole mit den richtigen Parametern geöffnet. Im nächsten Abschnitt werden die für diese Anwendung erforderlichen Indizes geschrieben und bereitgestellt.
Wenn wir nicht jeden Pfad in unserer App erkunden und den einzelnen Links zur Indexerstellung folgen möchten, können wir mithilfe der Firebase-CLI problemlos viele Indizes gleichzeitig bereitstellen.
- Im heruntergeladenen lokalen Verzeichnis Ihrer App finden Sie eine Datei
firestore.indexes.json
.
Diese Datei beschreibt alle Indizes, die für alle möglichen Filterkombinationen benötigt werden.
firestore.indexes.json
{ "indexes": [ { "collectionGroup": "restaurants", "queryScope": "COLLECTION", "fields": [ { "fieldPath": "city", "order": "ASCENDING" }, { "fieldPath": "avgRating", "order": "DESCENDING" } ] }, ... ] }
- Stellen Sie diese Indizes mit dem folgenden Befehl bereit:
firebase deploy --only firestore:indexes
Nach einigen Minuten sind Ihre Indizes aktiv und die Fehlermeldungen verschwinden.
In diesem Abschnitt können Benutzer Bewertungen an Restaurants senden. Bisher waren alle unsere Schriften atomar und relativ einfach. Wenn einer von ihnen fehlerhaft ist, werden wir den Benutzer wahrscheinlich nur auffordern, ihn erneut zu versuchen, oder unsere App würde den Schreibvorgang automatisch wiederholen.
Unsere App wird viele Benutzer haben, die eine Bewertung für ein Restaurant hinzufügen möchten, daher müssen wir mehrere Lese- und Schreibvorgänge koordinieren. Zunächst wird die Überprüfung selbst muss eingereicht werden, dann ist die Bewertung des Restaurants count
und average rating
aktualisiert werden müssen. Wenn einer dieser Fehler auftritt, der andere jedoch nicht, befinden wir uns in einem inkonsistenten Zustand, in dem die Daten in einem Teil unserer Datenbank nicht mit den Daten in einem anderen übereinstimmen.
Glücklicherweise bietet Cloud Firestore Transaktionsfunktionen, mit denen wir mehrere Lese- und Schreibvorgänge in einem einzigen atomaren Vorgang ausführen können, um sicherzustellen, dass unsere Daten konsistent bleiben.
- Gehen Sie zurück zu Ihren
scripts/FriendlyEats.Data.js
. - Suchen Sie die Funktion
FriendlyEats.prototype.addRating
. - Ersetzen Sie die gesamte Funktion durch den folgenden Code.
FriendlyEats.Data.js
FriendlyEats.prototype.addRating = function(restaurantID, rating) { var collection = firebase.firestore().collection('restaurants'); var document = collection.doc(restaurantID); var newRatingDocument = document.collection('ratings').doc(); return firebase.firestore().runTransaction(function(transaction) { return transaction.get(document).then(function(doc) { var data = doc.data(); var newAverage = (data.numRatings * data.avgRating + rating.rating) / (data.numRatings + 1); transaction.update(document, { numRatings: data.numRatings + 1, avgRating: newAverage }); return transaction.set(newRatingDocument, rating); }); }); };
Im obigen Block lösen wir eine Transaktion aus, um die numerischen Werte von avgRating
und numRatings
im Restaurantdokument zu aktualisieren. Gleichzeitig fügen wir die neue rating
der ratings
.
Zu Beginn dieses Codelabs haben wir die Sicherheitsregeln unserer App festgelegt, um die Datenbank vollständig für Lese- oder Schreibvorgänge zu öffnen. In einer realen Anwendung möchten wir viel detailliertere Regeln festlegen, um unerwünschten Datenzugriff oder unerwünschte Änderungen zu verhindern.
- Klicken Sie im Abschnitt Entwickeln der Firebase-Konsole auf Datenbank .
- Klicken Sie im Abschnitt Cloud Firestore auf die Registerkarte Regeln (oder klicken Sie hier , um direkt dorthin zu gelangen).
- Ersetzen Sie die Standardeinstellungen durch die folgenden Regeln und klicken Sie dann auf Veröffentlichen .
firestore.rules
rules_version = '2'; service cloud.firestore { // Determine if the value of the field "key" is the same // before and after the request. function unchanged(key) { return (key in resource.data) && (key in request.resource.data) && (resource.data[key] == request.resource.data[key]); } match /databases/{database}/documents { // Restaurants: // - Authenticated user can read // - Authenticated user can create/update (for demo purposes only) // - Updates are allowed if no fields are added and name is unchanged // - Deletes are not allowed (default) match /restaurants/{restaurantId} { allow read: if request.auth != null; allow create: if request.auth != null; allow update: if request.auth != null && (request.resource.data.keys() == resource.data.keys()) && unchanged("name"); // Ratings: // - Authenticated user can read // - Authenticated user can create if userId matches // - Deletes and updates are not allowed (default) match /ratings/{ratingId} { allow read: if request.auth != null; allow create: if request.auth != null && request.resource.data.userId == request.auth.uid; } } } }
Diese Regeln beschränken den Zugriff, um sicherzustellen, dass Clients nur sichere Änderungen vornehmen. Zum Beispiel:
- Aktualisierungen eines Restaurantdokuments können nur die Bewertungen ändern, nicht den Namen oder andere unveränderliche Daten.
- Bewertungen können nur erstellt werden, wenn die Benutzer-ID mit dem angemeldeten Benutzer übereinstimmt, wodurch Spoofing verhindert wird.
Alternativ zur Verwendung der Firebase-Konsole können Sie die Firebase-CLI verwenden, um Regeln für Ihr Firebase-Projekt bereitzustellen. Die Datei firestore.rules in Ihrem Arbeitsverzeichnis enthält bereits die oben genannten Regeln. Um diese Regeln von Ihrem lokalen Dateisystem aus bereitzustellen (anstatt die Firebase-Konsole zu verwenden), führen Sie den folgenden Befehl aus:
firebase deploy --only firestore:rules
In diesem Codelab haben Sie gelernt, wie Sie mit Cloud Firestore grundlegende und erweiterte Lese- und Schreibvorgänge ausführen und den Datenzugriff mit Sicherheitsregeln sichern. Die vollständige Lösung finden Sie im Repository von quickstarts-js .
Weitere Informationen zum Cloud Firestore finden Sie in den folgenden Ressourcen: