Cloud Firestore Web-Codelab

Ziele

In diesem Code - Lab finden Sie eine Empfehlung für ein Restaurant Web - App bereitgestellt bauen Wolke Firestor .

img5.png

Was du lernst

  • Daten aus einer Web-App in Cloud Firestore lesen und schreiben
  • Hören Sie sich Änderungen in Cloud Firestore-Daten in Echtzeit an
  • Verwenden Sie Firebase Authentication und Sicherheitsregeln, um Cloud Firestore-Daten zu schützen
  • 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

  1. In der Firebase - Konsole , klicken Sie auf Hinzufügen Projekt, dann das Projekt Firebase FriendlyEats nennen.

Merken Sie sich die Projekt-ID Ihres Firebase-Projekts.

  1. Klicken Sie auf Projekt.

Die Anwendung, die wir erstellen werden, verwendet einige im Web verfügbare Firebase-Dienste:

  • Firebase - Authentifizierung für Ihre Benutzer leicht zu identifizieren
  • Cloud Firestor zu strukturierte Daten in der Cloud zu speichern und sofort eine Benachrichtigung erhalten , wenn die Daten aktualisiert werden
  • Hosting Firebase zu Host und dienen Ihre statischen Vermögenswerte

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 werden Anonymous Login verwenden - was bedeutet , dass der Benutzer lautlos in unterzeichnet werden , ohne gefragt zu werden.

Sie müssen die anonyme Anmeldung aktivieren.

  1. In der Konsole Firebase, suchen Sie den Build - Abschnitt im linken Navigationsbereich .
  2. Klicken Sie auf Authentifizierung, klicken Sie auf den Anmelde-Verfahren Registerkarte (oder klicken Sie hier um direkt dorthin zu gehen).
  3. Aktivieren Sie die Anonymous-Anmeldung Provider, dann klicken Sie auf Speichern.

img7.png

Dadurch kann sich die Anwendung bei Ihren Benutzern im Hintergrund anmelden, wenn diese auf die Web-App zugreifen. Fühlen Sie sich frei , die lesen Anonyme Authentifizierung Dokumentation mehr zu erfahren.

Cloud Firestore aktivieren

Die App verwendet Cloud Firestore, um Restaurantinformationen und Bewertungen zu speichern und zu empfangen.

Sie müssen Cloud Firestore aktivieren. In der Aufbaubereich von Firebase Konsole auf Firestore - Datenbank. Klicken Sie auf Datenbank erstellen in dem Cloud Firestor Bereich.

Der Zugriff auf Daten in Cloud Firestore wird durch Sicherheitsregeln gesteuert. Wir werden später in diesem Codelab mehr über Regeln sprechen, aber zuerst müssen wir einige grundlegende Regeln für unsere Daten festlegen, um loszulegen. In der Registerkarte Regeln der Firebase - Konsole die folgenden Regeln hinzufügen , 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 nicht authentifizierte Benutzer lesen oder schreiben können. Das ist besser, als den öffentlichen Zugang zu erlauben, aber noch lange nicht sicher. Wir werden diese Regeln später im Codelab verbessern.

Klonen Sie die GitHub - Repository über die Befehlszeile:

git clone https://github.com/firebase/friendlyeats-web

Der Beispielcode sollte in die 📁 wurden kloniert friendlyeats-web - Verzeichnis. Stellen Sie von nun an sicher, dass Sie alle Ihre Befehle von diesem Verzeichnis aus ausführen:

cd friendlyeats-web

Importieren Sie die Starter-App

Verwenden Sie Ihre IDE (WebStorm, Atom, Sublime, Visual Studio - Code ...) öffnen oder importieren Sie die 📁 friendlyeats-web - Verzeichnis. Dieses Verzeichnis enthält den Startcode für das Codelab, das aus einer noch nicht funktionierenden Restaurantempfehlungs-App besteht. Wir werden es in diesem Codelab funktionsfähig machen, sodass Sie bald Code in diesem Verzeichnis bearbeiten müssen.

Mit der Firebase Command Line Interface (CLI) können Sie Ihre Web-App lokal bereitstellen und Ihre Web-App auf Firebase Hosting bereitstellen.

  1. Installieren Sie die CLI, indem Sie den folgenden npm-Befehl ausführen:
npm -g install firebase-tools
  1. Überprüfen Sie, ob die CLI ordnungsgemäß installiert wurde, indem Sie den folgenden Befehl ausführen:
firebase --version

Stellen Sie sicher, dass die Version der Firebase-CLI v7.4.0 oder höher ist.

  1. Autorisieren Sie die Firebase-CLI, indem Sie den folgenden Befehl ausführen:
firebase login

Wir haben die Web-App-Vorlage eingerichtet, um die Konfiguration Ihrer App für Firebase Hosting aus dem lokalen Verzeichnis und den Dateien Ihrer App abzurufen. Dazu müssen wir Ihre App jedoch mit Ihrem Firebase-Projekt verknüpfen.

  1. Stellen Sie sicher, dass Ihre Befehlszeile auf das lokale Verzeichnis Ihrer App zugreift.
  2. Verknüpfen Sie Ihre App mit Ihrem Firebase-Projekt, indem Sie den folgenden Befehl ausführen:
firebase use --add
  1. Wählen Sie bei Aufforderung Ihre ID - Projekt, dann geben Sie Ihrem Projekt Firebase einen Aliasnamen.

Ein Alias ​​ist nützlich, wenn Sie mehrere Umgebungen haben (Produktion, Staging usw.). Doch für diesen Codelab, lassen Sie sich einfach den Alias verwendet default .

  1. Folgen Sie den restlichen Anweisungen in Ihrer Befehlszeile.

Wir sind bereit, mit der Arbeit an unserer App zu beginnen! Lassen Sie uns unsere App lokal ausführen!

  1. Führen Sie den folgenden Firebase-CLI-Befehl aus:
firebase emulators:start --only hosting
  1. Ihre Befehlszeile sollte die folgende Antwort anzeigen:
hosting: Local server: http://localhost:5000

Wir verwenden die Firebase Hosting - Emulator unser App vor Ort zu bedienen. Der Web - App sollte jetzt verfügbar sein von http: // localhost: 5000 .

  1. Öffnen Sie Ihre App auf 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 im Hintergrund als anonymer Benutzer angemeldet.

img2.png

In diesem Abschnitt schreiben wir einige Daten in Cloud Firestore, damit wir die Benutzeroberfläche der App füllen können. Dies kann manuell über die getan wird Firebase - Konsole , aber wir werden es in der App selbst tun ein grundlegende Wolke Firestor schreiben zu demonstrieren.

Datenmodell

Firestore-Daten werden in Sammlungen, Dokumente, Felder und Untersammlungen unterteilt. Wir speichern jedes Restaurant als Dokument in einer Top-Level - Kollektion namens restaurants .

img3.png

Später werden wir jede Kritik in einer Untersammlung speichern genannt ratings unter jedem Restaurant.

img4.png

Restaurants zu Firestore hinzufügen

Das Hauptmodellobjekt in unserer App ist ein Restaurant. Lassen Sie uns schreiben einige Code, der ein Restaurant Dokument zum fügt restaurants Sammlung.

  1. Von Ihrer heruntergeladenen Dateien, öffnen scripts/FriendlyEats.Data.js .
  2. Hier finden Sie die Funktion FriendlyEats.prototype.addRestaurant .
  3. 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 ein neues Dokument an das restaurants Sammlung. 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.

Lassen Sie uns Restaurants hinzufügen!

  1. Gehen Sie zurück zu Ihrer FriendlyEats-App in Ihrem Browser und aktualisieren Sie sie.
  2. Klicken Sie auf Hinzufügen Mock Daten.

Die App wird automatisch eine zufällige Reihe von Restaurants Objekten erzeugt, dann ruft addRestaurant Funktion. Sie werden jedoch noch nicht die Daten in Ihrem aktuellen Web - App sehen , weil wir immer noch die Daten implementieren müssen Abrufen (der nächste Abschnitt des Code - Lab).

Wenn Sie auf das Ebene Wolke Firestor Registerkarte in der Konsole Firebase, obwohl, sollten Sie jetzt neue Dokumente in denen sehen restaurants Sammlung!

img6.png

Herzlichen Glückwunsch, Sie haben gerade Daten von einer Web-App in Cloud Firestore geschrieben!

Im nächsten Abschnitt erfahren Sie, wie Sie Daten aus Cloud Firestore abrufen und in Ihrer App anzeigen.

In diesem Abschnitt erfahren Sie, wie Sie Daten aus 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 der Abfrage entsprechen, und erhält Updates in Echtzeit.

Lassen Sie uns zunächst die Abfrage erstellen, die die standardmäßige, ungefilterte Liste von Restaurants bereitstellt.

  1. Gehen Sie auf die Datei zurück scripts/FriendlyEats.Data.js .
  2. Finden Sie die Funktion FriendlyEats.prototype.getAllRestaurants .
  3. 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);
};

In dem obigen Code konstruieren wir eine Abfrage , die von den Top-Level - Kollektion benannt 50 Restaurants abrufen up wird restaurants , die durch die durchschnittliche Bewertung geordnet (derzeit alle Nullen). Nachdem wir diese Abfrage erklären, geben wir es an die getDocumentsInQuery() Methode , die zum Laden und Rendern der Daten verantwortlich ist.

Dazu fügen wir einen Snapshot-Listener hinzu.

  1. Gehen Sie auf die Datei zurück scripts/FriendlyEats.Data.js .
  2. Hier finden Sie die Funktion FriendlyEats.prototype.getDocumentsInQuery .
  3. 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);
      }
    });
  });
};

In dem obigen Code, query.onSnapshot löst seinen Rückruf jedes Mal , wenn eine Änderung der Abfrage auf das Ergebnis da ist.

  • Das erste Mal, wird der Rückruf mit der gesamten Ergebnismenge der Abfrage ausgelöst - die ganzen Bedeutung restaurants Sammlung von Cloud - Firestor. Es geht dann alle einzelnen Dokumente an die renderer.display Funktion.
  • Wenn ein Dokument gelöscht wird, change.type gleich zu removed . In diesem Fall rufen wir also eine Funktion auf, die das Restaurant aus der Benutzeroberfläche entfernt.

Nachdem wir beide Methoden implementiert haben, aktualisieren Sie die App und überprüfen Sie, ob 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 Restaurantliste ändert, wird dieser Listener automatisch aktualisiert. Versuchen Sie, die Firebase-Konsole aufzurufen und ein Restaurant manuell zu löschen oder seinen Namen zu ändern. Die Änderungen werden sofort auf Ihrer Website angezeigt!

img5.png

Bisher haben wir gezeigt , wie man verwendet onSnapshot Updates in Echtzeit abzurufen; 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 Nutzer in Ihrer App auf ein bestimmtes Restaurant klickt.

  1. Gehen Sie zu Ihrer Datei zurück scripts/FriendlyEats.Data.js .
  2. Hier finden Sie die Funktion FriendlyEats.prototype.getRestaurant .
  3. 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:

img1.png

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 es gibt keine Möglichkeit für den Benutzer, nach seinen Bedürfnissen zu filtern. In diesem Abschnitt verwenden Sie die erweiterten Abfragen von Cloud Firestore, um die Filterung zu aktivieren.

Hier ist ein Beispiel für eine einfache Abfrage alle holen Dim Sum Restaurants:

var filteredQuery = query.where('category', '==', 'Dim Sum')

Wie der Name schon sagt, die where() wird Methode unsere Abfrage herunterladen machen nur Mitglieder der Sammlung , deren Felder erfüllen die Einschränkungen wir setzen. In diesem Fall wird es nur Restaurants herunterladen , wo category ist Dim Sum .

In unserer App kann der Benutzer mehrere Filter verketten, um spezifische Abfragen zu erstellen, wie "Pizza in San Francisco" oder "Seafood in Los Angeles, sortiert nach Beliebtheit".

Wir erstellen eine Methode, die eine Abfrage erstellt, die unsere Restaurants basierend auf mehreren von unseren Benutzern ausgewählten Kriterien filtert.

  1. Gehen Sie zu Ihrer Datei zurück scripts/FriendlyEats.Data.js .
  2. Finden Sie die Funktion FriendlyEats.prototype.getFilteredRestaurants .
  3. 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 eine Verbindung Abfrage Eingabe basierend auf Benutzer zu bauen. Unsere Abfrage gibt jetzt nur Restaurants zurück, die den Anforderungen des Benutzers entsprechen.

Aktualisieren Sie Ihre FriendlyEats-App in Ihrem Browser und überprüfen Sie dann, ob Sie nach Preis, Stadt und Kategorie filtern können. Während des Tests werden in der JavaScript-Konsole Ihres Browsers Fehler angezeigt, die wie folgt aussehen:

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 Cloud Firestore für die meisten zusammengesetzten Abfragen Indizes erfordert. Durch das Anfordern von Indizes für Abfragen bleibt Cloud Firestore schnell skaliert.

Wenn Sie den Link aus der Fehlermeldung öffnen, wird automatisch die Benutzeroberfläche zur Indexerstellung in der Firebase-Konsole mit den korrekten ausgefüllten Parametern geöffnet. Im nächsten Abschnitt werden wir die für diese Anwendung benötigten Indizes schreiben und bereitstellen.

Wenn wir nicht jeden Pfad in unserer App untersuchen und jedem der Links zur Indexerstellung folgen möchten, können wir mithilfe der Firebase-CLI problemlos viele Indizes gleichzeitig bereitstellen.

  1. In Ihrer App heruntergeladen lokale Verzeichnis, finden Sie eine finden firestore.indexes.json Datei.

Diese Datei beschreibt alle Indizes, die für alle möglichen Kombinationen von Filtern benötigt werden.

firestore.indexes.json

{
 "indexes": [
   {
     "collectionGroup": "restaurants",
     "queryScope": "COLLECTION",
     "fields": [
       { "fieldPath": "city", "order": "ASCENDING" },
       { "fieldPath": "avgRating", "order": "DESCENDING" }
     ]
   },

   ...

 ]
}
  1. Stellen Sie diese Indizes mit dem folgenden Befehl bereit:
firebase deploy --only firestore:indexes

Nach ein paar Minuten sind Ihre Indizes live und die Fehlermeldungen verschwinden.

In diesem Abschnitt fügen wir Benutzern die Möglichkeit hinzu, Bewertungen an Restaurants zu senden. Bisher waren alle unsere Schriften atomar und relativ einfach. Wenn einer von ihnen einen Fehler aufweist, werden wir den Benutzer wahrscheinlich einfach auffordern, ihn zu wiederholen, 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 Schritte fehlschlägt, 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, die es uns ermöglichen, mehrere Lese- und Schreibvorgänge in einem einzigen atomaren Vorgang durchzuführen, um sicherzustellen, dass unsere Daten konsistent bleiben.

  1. Gehen Sie zu Ihrer Datei zurück scripts/FriendlyEats.Data.js .
  2. Hier finden Sie die Funktion FriendlyEats.prototype.addRating .
  3. 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 Block oben, lösen wir eine Transaktion die numerischen Werte zu aktualisieren avgRating und numRatings im Restaurant Dokument. Zur gleichen Zeit, fügen wir die neue rating auf die ratings Untersammlung.

Zu Beginn dieses Codelabs legen wir die Sicherheitsregeln unserer App fest, um die Datenbank vollständig für Lese- oder Schreibvorgänge zu öffnen. In einer echten Anwendung möchten wir viel feinkörnigere Regeln festlegen, um unerwünschte Datenzugriffe oder -änderungen zu verhindern.

  1. In der Aufbaubereich von Firebase Konsole auf Firestore - Datenbank.
  2. Klicken Sie auf die Registerkarte Regeln in dem Cloud Firestor Abschnitt (oder klicken Sie hier um direkt dorthin zu gehen).
  3. Ersetzen Sie die Standardeinstellungen mit den folgenden Regeln, klicken Sie dann auf Veröffentlichen.

firestore.regeln

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 schränken den Zugriff ein, 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 firestore.rules Datei in Ihrem Arbeitsverzeichnis enthält bereits die Regeln von oben. Um diese Regeln über Ihr lokales Dateisystem 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 durchführen und den Datenzugriff mit Sicherheitsregeln sichern. Sie können die vollständige Lösung in der finden Quickstarts-js - Repository .

Weitere Informationen zu Cloud Firestore finden Sie in den folgenden Ressourcen: