Atelier de programmation Web Cloud Firestore

1. Vue d'ensemble

Buts

Dans ce codelab, vous allez construire une application web recommandation de restaurant alimenté par Nuage Firestore .

img5.png

Ce que vous apprendrez

  • Lire et écrire des données dans Cloud Firestore à partir d'une application Web
  • Écoutez les changements dans les données Cloud Firestore en temps réel
  • Utiliser l'authentification Firebase et les règles de sécurité pour sécuriser les données Cloud Firestore
  • Écrire des requêtes Cloud Firestore complexes

Ce dont vous aurez besoin

Avant de commencer cet atelier de programmation, assurez-vous d'avoir installé :

2. Créer et configurer un projet Firebase

Créer un projet Firebase

  1. Dans la console Firebase , cliquez sur Ajouter un projet, puis nommez le projet Firebase FriendlyEats.

N'oubliez pas l'ID de projet de votre projet Firebase.

  1. Cliquez sur Créer un projet.

L'application que nous allons créer utilise quelques services Firebase disponibles sur le Web :

  • Firebase authentification pour identifier facilement vos utilisateurs
  • Cloud Firestore pour enregistrer des données structurées sur le Cloud et la notification instantanée obtenir lorsque les données sont mises à jour
  • Hébergement Firebase à l' hôte et de servir vos actifs statiques

Pour cet atelier de programmation spécifique, nous avons déjà configuré Firebase Hosting. Cependant, pour Firebase Auth et Cloud Firestore, nous vous expliquerons la configuration et l'activation des services à l'aide de la console Firebase.

Activer l'authentification anonyme

Bien que l'authentification ne soit pas l'objet de cet atelier de programmation, il est important d'avoir une certaine forme d'authentification dans notre application. Nous allons utiliser l' accès anonyme - ce qui signifie que l'utilisateur sera signé en silence sans être invité.

Vous devez activer l' accès anonyme.

  1. Dans la console Firebase, recherchez la section de construction dans la navigation de gauche.
  2. Cliquez sur Authentification, puis cliquez sur le signe dans l' onglet méthode (ou cliquez ici pour aller directement là - bas).
  3. Activez le Anonymous Sign-in Provider, puis cliquez sur Enregistrer.

img7.png

Cela permettra à l'application de se connecter silencieusement à vos utilisateurs lorsqu'ils accèdent à l'application Web. Ne hésitez pas à lire la documentation de l' authentification anonyme pour en savoir plus.

Activer Cloud Firestore

L'application utilise Cloud Firestore pour enregistrer et recevoir des informations et des évaluations sur les restaurants.

Vous devez activer Cloud Firestore. Dans la section de construction de la console Firebase, cliquez sur la base de données Firestore. Cliquez sur Créer la base de données dans le volet Nuage Firestore.

L'accès aux données dans Cloud Firestore est contrôlé par des règles de sécurité. Nous parlerons plus en détail des règles plus tard dans cet atelier de programmation, mais nous devons d'abord définir quelques règles de base sur nos données pour commencer. Dans l' onglet Règles de la console Firebase ajouter les règles suivantes puis cliquez sur Publier.

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

Les règles ci-dessus limitent l'accès aux données aux utilisateurs connectés, ce qui empêche les utilisateurs non authentifiés de lire ou d'écrire. C'est mieux que d'autoriser l'accès public mais c'est encore loin d'être sécurisé, nous améliorerons ces règles plus tard dans le labo.

3. Obtenez l'exemple de code

Cloner le dépôt GitHub à partir de la ligne de commande:

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

L'exemple de code aurait été cloné dans le 📁 friendlyeats-web répertoire. A partir de maintenant, assurez-vous d'exécuter toutes vos commandes depuis ce répertoire :

cd friendlyeats-web

Importer l'application de démarrage

Utilisation de votre IDE (WebStorm, Atom, Sublime, Code Visual Studio ...) ouvrir ou importer le 📁 friendlyeats-web répertoire. Ce répertoire contient le code de démarrage du laboratoire de programmation qui consiste en une application de recommandation de restaurants pas encore fonctionnelle. Nous le rendrons fonctionnel tout au long de cet atelier de programmation, vous devrez donc bientôt modifier le code dans ce répertoire.

4. Installez l'interface de ligne de commande Firebase

L'interface de ligne de commande (CLI) de Firebase vous permet de servir votre application Web localement et de déployer votre application Web sur Firebase Hosting.

  1. Installez la CLI en exécutant la commande npm suivante :
npm -g install firebase-tools
  1. Vérifiez que la CLI a été correctement installée en exécutant la commande suivante :
firebase --version

Assurez-vous que la version de Firebase CLI est la v7.4.0 ou une version ultérieure.

  1. Autorisez la CLI Firebase en exécutant la commande suivante :
firebase login

Nous avons configuré le modèle d'application Web pour extraire la configuration de votre application pour l'hébergement Firebase à partir du répertoire et des fichiers locaux de votre application. Mais pour ce faire, nous devons associer votre application à votre projet Firebase.

  1. Assurez-vous que votre ligne de commande accède au répertoire local de votre application.
  2. Associez votre application à votre projet Firebase en exécutant la commande suivante :
firebase use --add
  1. Lorsque vous êtes invité, sélectionnez votre ID projet, puis donnez votre projet Firebase un alias.

Un alias est utile si vous avez plusieurs environnements (production, staging, etc.). Cependant, pour ce codelab, nous allons simplement utiliser l'alias de default .

  1. Suivez les instructions restantes dans votre ligne de commande.

5. Exécutez le serveur local

Nous sommes prêts à commencer à travailler sur notre application ! Exécutons notre application localement !

  1. Exécutez la commande CLI Firebase suivante :
firebase emulators:start --only hosting
  1. Votre ligne de commande devrait afficher la réponse suivante :
hosting: Local server: http://localhost:5000

Nous utilisons l' hébergement Firebase émulateur pour servir notre application localement. L'application Web doit maintenant être disponible à partir de http: // localhost: 5000 .

  1. Ouvrez votre application à http: // localhost: 5000 .

Vous devriez voir votre copie de FriendlyEats qui a été connectée à votre projet Firebase.

L'application s'est automatiquement connectée à votre projet Firebase et vous a connecté silencieusement en tant qu'utilisateur anonyme.

img2.png

6. Écrire des données dans Cloud Firestore

Dans cette section, nous allons écrire des données dans Cloud Firestore afin de pouvoir remplir l'interface utilisateur de l'application. Cela peut se faire manuellement via la console Firebase , mais nous allons le faire dans l'application elle - même pour démontrer un nuage Firestore écriture de base.

Modèle de données

Les données Firestore sont divisées en collections, documents, champs et sous-collections. Nous enregistrons chaque restaurant comme un document dans une collection de niveau supérieur appelé les restaurants .

img3.png

Plus tard, nous enregistrons chaque examen dans une sous - collection appelée ratings sous chaque restaurant.

img4.png

Ajouter des restaurants à Firestore

L'objet modèle principal de notre application est un restaurant. Écrivons un code qui ajoute un document de restaurants à la restaurants collection.

  1. A partir de vos fichiers téléchargés, ouvrez les scripts/FriendlyEats.Data.js .
  2. Trouvez la fonction FriendlyEats.prototype.addRestaurant .
  3. Remplacez la fonction entière par le code suivant.

FriendlyEats.Data.js

FriendlyEats.prototype.addRestaurant = function(data) {
  var collection = firebase.firestore().collection('restaurants');
  return collection.add(data);
};

Le code ci - dessus ajoute un nouveau document à la restaurants collection. Les données du document proviennent d'un objet JavaScript simple. Nous le faisons d'abord obtenir une référence à une collection Nuage FireStore restaurants puis add « ing les données.

Ajoutons les restaurants !

  1. Retournez à votre application FriendlyEats dans votre navigateur et actualisez-la.
  2. Cliquez sur Ajouter Mock de données.

L'application génère automatiquement un ensemble aléatoire d'objets de restaurants, puis appelez votre addRestaurant fonction. Cependant, vous ne verrez pas encore les données dans votre application Web réelle parce que nous avons encore besoin de mettre en œuvre la récupération des données (la section suivante du codelab).

Si vous accédez à l' onglet Nuage Firestore dans la console Firebase, cependant, vous devriez voir de nouveaux documents dans les restaurants collection!

img6.png

Félicitations, vous venez d'écrire des données dans Cloud Firestore à partir d'une application Web !

Dans la section suivante, vous apprendrez à récupérer des données depuis Cloud Firestore et à les afficher dans votre application.

7. Afficher les données de Cloud Firestore

Dans cette section, vous apprendrez à récupérer des données depuis Cloud Firestore et à les afficher dans votre application. Les deux étapes clés sont la création d'une requête et l'ajout d'un écouteur d'instantané. Cet écouteur sera informé de toutes les données existantes qui correspondent à la requête et recevra des mises à jour en temps réel.

Tout d'abord, construisons la requête qui servira la liste de restaurants par défaut et non filtrée.

  1. Retour aux fichiers scripts/FriendlyEats.Data.js .
  2. Trouver la fonction FriendlyEats.prototype.getAllRestaurants .
  3. Remplacez la fonction entière par le code suivant.

FriendlyEats.Data.js

FriendlyEats.prototype.getAllRestaurants = function(renderer) {
  var query = firebase.firestore()
      .collection('restaurants')
      .orderBy('avgRating', 'desc')
      .limit(50);

  this.getDocumentsInQuery(query, renderer);
};

Dans le code ci - dessus, on construit une requête qui récupérera jusqu'à 50 restaurants de la collection de niveau supérieur nommé restaurants , qui sont commandés par la note moyenne (actuellement tous nuls). Après avoir déclaré cette requête, nous passons à la getDocumentsInQuery() méthode qui est responsable du chargement et de rendre les données.

Nous allons le faire en ajoutant un écouteur d'instantané.

  1. Retour aux fichiers scripts/FriendlyEats.Data.js .
  2. Trouvez la fonction FriendlyEats.prototype.getDocumentsInQuery .
  3. Remplacez la fonction entière par le code suivant.

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

Dans le code ci - dessus, query.onSnapshot déclenchera son rappel à chaque fois qu'il ya un changement au résultat de la requête.

  • La première fois, le rappel est déclenché avec l'ensemble de résultat de la requête - ce qui signifie l'ensemble des restaurants collection de nuage Firestore. Il passe ensuite tous les documents individuels à la renderer.display fonction.
  • Lorsqu'un document est supprimé, change.type est égal à removed . Donc, dans ce cas, nous appellerons une fonction qui supprime le restaurant de l'interface utilisateur.

Maintenant que nous avons implémenté les deux méthodes, actualisez l'application et vérifiez que les restaurants que nous avons vus précédemment dans la console Firebase sont désormais visibles dans l'application. Si vous avez terminé cette section avec succès, votre application lit et écrit désormais des données avec Cloud Firestore !

Au fur et à mesure que votre liste de restaurants change, cet écouteur continuera à se mettre à jour automatiquement. Essayez d'accéder à la console Firebase et de supprimer manuellement un restaurant ou de changer son nom - vous verrez les changements apparaître immédiatement sur votre site !

img5.png

8. Obtenir () les données

Jusqu'à présent, nous avons montré comment utiliser onSnapshot pour récupérer les mises à jour en temps réel; cependant, ce n'est pas toujours ce que nous voulons. Parfois, il est plus logique de ne récupérer les données qu'une seule fois.

Nous souhaitons implémenter une méthode qui se déclenche lorsqu'un utilisateur clique sur un restaurant spécifique dans votre application.

  1. Retour à vos fichiers scripts/FriendlyEats.Data.js .
  2. Trouvez la fonction FriendlyEats.prototype.getRestaurant .
  3. Remplacez la fonction entière par le code suivant.

FriendlyEats.Data.js

FriendlyEats.prototype.getRestaurant = function(id) {
  return firebase.firestore().collection('restaurants').doc(id).get();
};

Après avoir implémenté cette méthode, vous pourrez afficher les pages de chaque restaurant. Cliquez simplement sur un restaurant dans la liste et vous devriez voir la page des détails du restaurant :

img1.png

Pour l'instant, vous ne pouvez pas ajouter de notes car nous devons encore implémenter l'ajout de notes plus tard dans le laboratoire de programmation.

9. Trier et filtrer les données

Actuellement, notre application affiche une liste de restaurants, mais il n'y a aucun moyen pour l'utilisateur de filtrer en fonction de ses besoins. Dans cette section, vous utiliserez les requêtes avancées de Cloud Firestore pour activer le filtrage.

Voici un exemple d'une requête simple pour aller chercher tous les Dim Sum restaurants:

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

Comme son nom l' indique, where() méthode fera notre téléchargement de requête que les membres de la collection dont les champs répondent aux restrictions que nous fixons. Dans ce cas, il ne fera que télécharger des restaurants où la category est Dim Sum .

Dans notre application, l'utilisateur peut enchaîner plusieurs filtres pour créer des requêtes spécifiques, comme "Pizza à San Francisco" ou "Fruits de mer à Los Angeles commandés par popularité".

Nous allons créer une méthode qui construit une requête qui filtrera nos restaurants en fonction de plusieurs critères sélectionnés par nos utilisateurs.

  1. Retour à vos fichiers scripts/FriendlyEats.Data.js .
  2. Trouver la fonction FriendlyEats.prototype.getFilteredRestaurants .
  3. Remplacez la fonction entière par le code suivant.

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

Le code ci - dessus ajoute multiple where les filtres et une seule orderBy clause pour créer une requête de composé à base d' une entrée utilisateur. Notre requête ne renverra désormais que les restaurants qui correspondent aux besoins de l'utilisateur.

Actualisez votre application FriendlyEats dans votre navigateur, puis vérifiez que vous pouvez filtrer par prix, ville et catégorie. Pendant le test, vous verrez des erreurs dans la console JavaScript de votre navigateur qui ressemblent à ceci :

The query requires an index. You can create it here: https://console.firebase.google.com/project/.../database/firestore/indexes?create_index=...

Ces erreurs sont dues au fait que Cloud Firestore requiert des index pour la plupart des requêtes composées. L'exigence d'index sur les requêtes permet à Cloud Firestore de rester rapide à grande échelle.

L'ouverture du lien à partir du message d'erreur ouvrira automatiquement l'interface utilisateur de création d'index dans la console Firebase avec les paramètres corrects renseignés. Dans la section suivante, nous écrirons et déploierons les index nécessaires pour cette application.

10. Déployer les index

Si nous ne voulons pas explorer tous les chemins de notre application et suivre chacun des liens de création d'index, nous pouvons facilement déployer plusieurs index à la fois à l'aide de la CLI Firebase.

  1. Dans le répertoire local téléchargé de votre application, vous trouverez un firestore.indexes.json fichier.

Ce fichier décrit tous les index nécessaires pour toutes les combinaisons possibles de filtres.

firestore.indexes.json

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

   ...

 ]
}
  1. Déployez ces index avec la commande suivante :
firebase deploy --only firestore:indexes

Après quelques minutes, vos index seront en ligne et les messages d'erreur disparaîtront.

11. Écrire des données dans une transaction

Dans cette section, nous ajouterons la possibilité pour les utilisateurs de soumettre des avis aux restaurants. Jusqu'à présent, toutes nos écritures ont été atomiques et relativement simples. En cas d'erreur, nous inviterions probablement l'utilisateur à les réessayer ou notre application réessayerait l'écriture automatiquement.

Notre application aura de nombreux utilisateurs qui souhaitent ajouter une note pour un restaurant, nous devrons donc coordonner plusieurs lectures et écritures. Tout d' abord l'examen lui - même doit être soumis, puis note du restaurant count et average rating ont besoin d'être mis à jour. Si l'un d'entre eux échoue mais pas l'autre, nous nous retrouvons dans un état incohérent où les données d'une partie de notre base de données ne correspondent pas aux données d'une autre.

Heureusement, Cloud Firestore fournit une fonctionnalité de transaction qui nous permet d'effectuer plusieurs lectures et écritures en une seule opération atomique, garantissant ainsi la cohérence de nos données.

  1. Retour à vos fichiers scripts/FriendlyEats.Data.js .
  2. Trouvez la fonction FriendlyEats.prototype.addRating .
  3. Remplacez la fonction entière par le code suivant.

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

Dans le bloc ci - dessus, nous déclenchons une transaction pour mettre à jour les valeurs numériques de avgRating et numRatings dans le document de restaurant. En même temps, nous ajoutons la nouvelle rating à la ratings subcollection.

12. Sécurisez vos données

Au début de cet atelier de programmation, nous avons défini les règles de sécurité de notre application pour ouvrir complètement la base de données à toute lecture ou écriture. Dans une application réelle, nous voudrions définir des règles beaucoup plus fines pour empêcher l'accès ou la modification de données indésirables.

  1. Dans la section de construction de la console Firebase, cliquez sur la base de données Firestore.
  2. Cliquez sur l'onglet Règles dans la section Nuage Firestore (ou cliquez ici pour aller directement là - bas).
  3. Remplacer les valeurs par défaut avec les règles suivantes, puis cliquez sur Publier.

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

Ces règles restreignent l'accès pour garantir que les clients n'effectuent que des modifications sûres. Par exemple:

  • Les mises à jour d'un document de restaurant ne peuvent modifier que les notes, pas le nom ou toute autre donnée immuable.
  • Les évaluations ne peuvent être créées que si l'ID utilisateur correspond à l'utilisateur connecté, ce qui empêche l'usurpation d'identité.

Au lieu d'utiliser la console Firebase, vous pouvez utiliser la CLI Firebase pour déployer des règles dans votre projet Firebase. Le firestore.rules fichier dans votre répertoire de travail contient déjà les règles d' en haut. Pour déployer ces règles à partir de votre système de fichiers local (plutôt que d'utiliser la console Firebase), vous devez exécuter la commande suivante :

firebase deploy --only firestore:rules

13. Conclusion

Dans cet atelier de programmation, vous avez appris à effectuer des lectures et des écritures de base et avancées avec Cloud Firestore, ainsi qu'à sécuriser l'accès aux données avec des règles de sécurité. Vous pouvez trouver la solution complète dans le référentiel QuickStart-js .

Pour en savoir plus sur Cloud Firestore, consultez les ressources suivantes :