Save the date - Google I/O returns May 18-20. Register to get the most out of the digital experience: Build your schedule, reserve space, participate in Q&As, earn Google Developer profile badges, and more. Register now
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Codelab Web Cloud Firestore

Obiettivi

In questo codelab, creerai un'app Web per i consigli sui ristoranti basata su Cloud Firestore .

img5.png

Cosa imparerai

  • Leggere e scrivere dati su Cloud Firestore da un'app Web
  • Ascolta le modifiche ai dati di Cloud Firestore in tempo reale
  • Utilizza l'autenticazione Firebase e le regole di sicurezza per proteggere i dati di Cloud Firestore
  • Scrivi query Cloud Firestore complesse

Di cosa avrai bisogno

Prima di avviare questo codelab, assicurati di aver installato:

Crea un progetto Firebase

  1. Nella console Firebase , fai clic su Aggiungi progetto , quindi assegna un nome al progetto Firebase FriendlyEats .

Ricorda l'ID progetto per il tuo progetto Firebase.

  1. Fare clic su Crea progetto .

L'applicazione che creeremo utilizza alcuni servizi Firebase disponibili sul Web:

  • Firebase Authentication per identificare facilmente i tuoi utenti
  • Cloud Firestore per salvare i dati strutturati sul Cloud e ricevere una notifica immediata quando i dati vengono aggiornati
  • Firebase Hosting per ospitare e servire le tue risorse statiche

Per questo specifico codelab, abbiamo già configurato Firebase Hosting. Tuttavia, per Firebase Auth e Cloud Firestore, ti guideremo attraverso la configurazione e l'abilitazione dei servizi utilizzando la console Firebase.

Abilita autenticazione anonima

Sebbene l'autenticazione non sia il fulcro di questo codelab, è importante avere una qualche forma di autenticazione nella nostra app. Useremo l' accesso anonimo , il che significa che l'utente accederà silenziosamente senza che venga richiesto.

Dovrai abilitare l' accesso anonimo.

  1. Nella console Firebase, individua la sezione Build nel menu di navigazione sinistro.
  2. Fare clic su Autenticazione , quindi sulla scheda Metodo di accesso (o fare clic qui per andare direttamente lì).
  3. Abilita il provider di accesso anonimo , quindi fai clic su Salva .

img7.png

Ciò consentirà all'applicazione di accedere in silenzio agli utenti quando accedono all'app Web. Sentiti libero di leggere la documentazione sull'autenticazione anonima per saperne di più.

Abilita Cloud Firestore

L'app utilizza Cloud Firestore per salvare e ricevere informazioni e valutazioni sui ristoranti.

Dovrai abilitare Cloud Firestore. Nella sezione Build della console Firebase, fai clic su Database Firestore . Fai clic su Crea database nel riquadro Cloud Firestore.

L'accesso ai dati in Cloud Firestore è controllato dalle regole di sicurezza. Parleremo di più delle regole più avanti in questo codelab, ma prima dobbiamo impostare alcune regole di base sui nostri dati per iniziare. Nella scheda Regole della console Firebase aggiungi le seguenti regole e fai clic su Pubblica .

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

Le regole precedenti limitano l'accesso ai dati agli utenti che hanno effettuato l'accesso, il che impedisce agli utenti non autenticati di leggere o scrivere. È meglio che consentire l'accesso pubblico, ma è ancora lontano dall'essere sicuro, miglioreremo queste regole più avanti nel codelab.

Clona il repository GitHub dalla riga di comando:

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

Il codice di esempio dovrebbe essere stato clonato nella directory 📁 friendlyeats-web , assicurati che la tua riga di comando venga eseguita da questa directory d'ora in poi:

cd friendlyeats-web

Importa l'app iniziale

Utilizzando il tuo IDE (WebStorm, Atom, Sublime, Visual Studio Code ...) apri o importa la directory 📁 friendlyeats-web . Questa directory contiene il codice di partenza per il codelab che consiste in un'app di raccomandazione di ristoranti non ancora funzionante. Lo renderemo funzionale in tutto questo codelab, quindi dovrai presto modificare il codice in quella directory.

L'interfaccia a riga di comando (CLI) di Firebase ti consente di servire la tua app web localmente e distribuire la tua app web su Firebase Hosting.

  1. Installa la CLI eseguendo il seguente comando npm:
npm -g install firebase-tools
  1. Verificare che la CLI sia stata installata correttamente eseguendo il seguente comando:
firebase --version

Assicurati che la versione della CLI di Firebase sia v7.4.0 o successiva.

  1. Autorizza la Firebase CLI eseguendo il seguente comando:
firebase login

Abbiamo impostato il modello di app web per estrarre la configurazione della tua app per Firebase Hosting dalla directory e dai file locali della tua app. Ma per fare ciò, dobbiamo associare la tua app al tuo progetto Firebase.

  1. Assicurati che la tua riga di comando acceda alla directory locale della tua app.
  2. Associa la tua app al tuo progetto Firebase eseguendo il seguente comando:
firebase use --add
  1. Quando richiesto, seleziona il tuo ID progetto , quindi assegna un alias al tuo progetto Firebase.

Un alias è utile se hai più ambienti (produzione, gestione temporanea, ecc.). Tuttavia, per questo codelab, usiamo solo l'alias di default .

  1. Segui le restanti istruzioni nella riga di comando.

Siamo pronti per iniziare effettivamente a lavorare sulla nostra app! Eseguiamo la nostra app in locale!

  1. Esegui il seguente comando della CLI di Firebase:
firebase emulators:start --only hosting
  1. La riga di comando dovrebbe visualizzare la seguente risposta:
hosting: Local server: http://localhost:5000

Stiamo utilizzando l'emulatore Firebase Hosting per servire la nostra app in locale. L'app Web dovrebbe ora essere disponibile da http: // localhost: 5000 .

  1. Apri la tua app su http: // localhost: 5000 .

Dovresti vedere la tua copia di FriendlyEats che è stata collegata al tuo progetto Firebase.

L'app si è connessa automaticamente al tuo progetto Firebase e ti ha eseguito l'accesso silenzioso come utente anonimo.

img2.png

In questa sezione, scriveremo alcuni dati in Cloud Firestore in modo da poter popolare l'interfaccia utente dell'app. Questo può essere fatto manualmente tramite la console Firebase , ma lo faremo nell'app stessa per dimostrare una scrittura di base su Cloud Firestore.

Modello di dati

I dati di Firestore sono suddivisi in raccolte, documenti, campi e sottoraccolte. Memorizzeremo ogni ristorante come documento in una raccolta di primo livello chiamata restaurants .

img3.png

Successivamente, memorizzeremo ciascuna recensione in una sottoraccolta chiamata ratings in ogni ristorante.

img4.png

Aggiungi ristoranti a Firestore

L'oggetto del modello principale nella nostra app è un ristorante. Scriviamo un codice che aggiunge un documento di restaurants raccolta di restaurants .

  1. Dai file scaricati, apri scripts/FriendlyEats.Data.js .
  2. Trova la funzione FriendlyEats.prototype.addRestaurant .
  3. Sostituisci l'intera funzione con il codice seguente.

FriendlyEats.Data.js

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

Il codice sopra aggiunge un nuovo documento alla raccolta dei restaurants . I dati del documento provengono da un semplice oggetto JavaScript. Lo facciamo ottenendo prima un riferimento a una raccolta di restaurants Cloud Firestore restaurants quindi add i dati.

Aggiungiamo i ristoranti!

  1. Torna alla tua app FriendlyEats nel tuo browser e aggiornala.
  2. Fare clic su Aggiungi dati fittizi .

L'app genererà automaticamente un set casuale di oggetti di ristoranti, quindi chiamerà la funzione addRestaurant . Tuttavia, non vedrai ancora i dati nella tua app Web effettiva perché dobbiamo ancora implementare il recupero dei dati (la sezione successiva del codelab).

Tuttavia, se accedi alla scheda Cloud Firestore nella console di Firebase, ora dovresti vedere nuovi documenti nella raccolta dei restaurants !

img6.png

Congratulazioni, hai appena scritto dati su Cloud Firestore da un'app web!

Nella sezione successiva imparerai come recuperare i dati da Cloud Firestore e visualizzarli nella tua app.

In questa sezione imparerai come recuperare i dati da Cloud Firestore e visualizzarli nella tua app. I due passaggi chiave sono la creazione di una query e l'aggiunta di un listener di istantanee. Questo listener riceverà una notifica di tutti i dati esistenti che corrispondono alla query e riceverà gli aggiornamenti in tempo reale.

Per prima cosa, costruiamo la query che servirà l'elenco di ristoranti predefinito e non filtrato.

  1. Torna al file scripts/FriendlyEats.Data.js .
  2. Trova la funzione FriendlyEats.prototype.getAllRestaurants .
  3. Sostituisci l'intera funzione con il codice seguente.

FriendlyEats.Data.js

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

  this.getDocumentsInQuery(query, renderer);
};

Nel codice precedente, costruiamo una query che recupererà fino a 50 ristoranti dalla raccolta di primo livello denominata restaurants , ordinati in base alla valutazione media (attualmente tutti zero). Dopo aver dichiarato questa query, la passiamo al metodo getDocumentsInQuery() che è responsabile del caricamento e del rendering dei dati.

Lo faremo aggiungendo un listener di istantanee.

  1. Torna al file scripts/FriendlyEats.Data.js .
  2. Trova la funzione FriendlyEats.prototype.getDocumentsInQuery .
  3. Sostituisci l'intera funzione con il codice seguente.

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

Nel codice precedente, query.onSnapshot attiverà il suo callback ogni volta che viene query.onSnapshot una modifica al risultato della query.

  • La prima volta, la richiamata viene attivata con l'intero set di risultati della query, ovvero l'intera raccolta di restaurants di Cloud Firestore. Quindi passa tutti i singoli documenti alla funzione renderer.display .
  • Quando un documento viene eliminato, change.type uguale a removed . Quindi, in questo caso, chiameremo una funzione che rimuove il ristorante dall'interfaccia utente.

Ora che abbiamo implementato entrambi i metodi, aggiorna l'app e verifica che i ristoranti che abbiamo visto in precedenza nella console Firebase siano ora visibili nell'app. Se hai completato correttamente questa sezione, la tua app ora sta leggendo e scrivendo dati con Cloud Firestore!

Man mano che il tuo elenco di ristoranti cambia, questo ascoltatore continuerà ad aggiornarsi automaticamente. Prova ad andare alla console Firebase ed eliminare manualmente un ristorante o cambiarne il nome: vedrai immediatamente le modifiche sul tuo sito!

img5.png

Finora abbiamo mostrato come utilizzare onSnapshot per recuperare gli aggiornamenti in tempo reale; tuttavia, non è sempre quello che vogliamo. A volte ha più senso recuperare i dati solo una volta.

Vorremo implementare un metodo che si attiva quando un utente fa clic in un ristorante specifico nella tua app.

  1. Torna al tuo file scripts/FriendlyEats.Data.js .
  2. Trova la funzione FriendlyEats.prototype.getRestaurant .
  3. Sostituisci l'intera funzione con il codice seguente.

FriendlyEats.Data.js

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

Dopo aver implementato questo metodo, sarai in grado di visualizzare le pagine di ogni ristorante. Basta fare clic su un ristorante nell'elenco e dovresti vedere la pagina dei dettagli del ristorante:

img1.png

Per ora, non è possibile aggiungere valutazioni poiché dobbiamo ancora implementare l'aggiunta di valutazioni in un secondo momento nel codelab.

Attualmente, la nostra app mostra un elenco di ristoranti, ma non c'è modo per l'utente di filtrare in base alle proprie esigenze. In questa sezione, utilizzerai le query avanzate di Cloud Firestore per abilitare il filtro.

Ecco un esempio di una semplice query per recuperare tutti i ristoranti Dim Sum :

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

Come suggerisce il nome, il metodo where() farà in modo che la nostra query scarichi solo i membri della raccolta i cui campi soddisfano le restrizioni che abbiamo impostato. In questo caso, scaricherà solo i ristoranti la cui category è Dim Sum .

Nella nostra app, l'utente può concatenare più filtri per creare query specifiche, come "Pizza a San Francisco" o "Frutti di mare a Los Angeles ordinati per popolarità".

Creeremo un metodo che costruisce una query che filtrerà i nostri ristoranti in base a più criteri selezionati dai nostri utenti.

  1. Torna al tuo file scripts/FriendlyEats.Data.js .
  2. Trova la funzione FriendlyEats.prototype.getFilteredRestaurants .
  3. Sostituisci l'intera funzione con il codice seguente.

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

Il codice precedente aggiunge più filtri where e una singola clausola orderBy per creare una query composta basata sull'input dell'utente. La nostra query ora restituirà solo i ristoranti che soddisfano i requisiti dell'utente.

Aggiorna la tua app FriendlyEats nel tuo browser, quindi verifica di poter filtrare per prezzo, città e categoria. Durante il test, vedrai errori nella console JavaScript del tuo browser che assomigliano a questo:

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

Questi errori sono dovuti al fatto che Cloud Firestore richiede indici per la maggior parte delle query composte. La richiesta di indici sulle query mantiene Cloud Firestore veloce su larga scala.

L'apertura del collegamento dal messaggio di errore aprirà automaticamente l'interfaccia utente di creazione dell'indice nella console Firebase con i parametri corretti inseriti. Nella sezione successiva, scriveremo e distribuiremo gli indici necessari per questa applicazione.

Se non vogliamo esplorare tutti i percorsi nella nostra app e seguire ciascuno dei collegamenti per la creazione degli indici, possiamo distribuire facilmente più indici contemporaneamente utilizzando la Firebase CLI.

  1. Nella directory locale scaricata della tua app troverai un file firestore.indexes.json .

Questo file descrive tutti gli indici necessari per tutte le possibili combinazioni di filtri.

firestore.indexes.json

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

   ...

 ]
}
  1. Distribuisci questi indici con il seguente comando:
firebase deploy --only firestore:indexes

Dopo alcuni minuti, i tuoi indici saranno attivi e i messaggi di errore scompariranno.

In questa sezione aggiungeremo la possibilità per gli utenti di inviare recensioni ai ristoranti. Finora, tutte le nostre scritture sono state atomiche e relativamente semplici. Se qualcuno di loro ha sbagliato, probabilmente chiederemo all'utente di riprovare o la nostra app ritenterà automaticamente la scrittura.

La nostra app avrà molti utenti che desiderano aggiungere una valutazione per un ristorante, quindi dovremo coordinare più letture e scritture. Per prima cosa è necessario inviare la recensione stessa, quindi è necessario aggiornare il count valutazioni del ristorante e la valutazione average rating . Se uno di questi fallisce ma non l'altro, ci troviamo in uno stato incoerente in cui i dati in una parte del nostro database non corrispondono ai dati in un'altra.

Fortunatamente, Cloud Firestore fornisce funzionalità di transazione che ci consentono di eseguire più letture e scritture in un'unica operazione atomica, assicurando che i nostri dati rimangano coerenti.

  1. Torna al tuo file scripts/FriendlyEats.Data.js .
  2. Trova la funzione FriendlyEats.prototype.addRating .
  3. Sostituisci l'intera funzione con il codice seguente.

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

Nel blocco sopra, avgRating una transazione per aggiornare i valori numerici di avgRating e numRatings nel documento del ristorante. Allo stesso tempo, aggiungiamo la nuova rating alla sottoraccolta di ratings .

All'inizio di questo codelab, abbiamo impostato le regole di sicurezza della nostra app per aprire completamente il database a qualsiasi lettura o scrittura. In un'applicazione reale, vorremmo impostare regole molto più dettagliate per impedire l'accesso o la modifica indesiderata dei dati.

  1. Nella sezione Build della console Firebase, fai clic su Database Firestore .
  2. Fai clic sulla scheda Regole nella sezione Cloud Firestore (o fai clic qui per andare direttamente lì).
  3. Sostituisci le impostazioni predefinite con le seguenti regole, quindi fai clic su Pubblica .

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

Queste regole limitano l'accesso per garantire che i client apportino solo modifiche sicure. Per esempio:

  • Gli aggiornamenti a un documento di un ristorante possono solo modificare le valutazioni, non il nome o altri dati immutabili.
  • Le valutazioni possono essere create solo se l'ID utente corrisponde all'utente connesso, il che impedisce lo spoofing.

In alternativa all'utilizzo della console Firebase, puoi utilizzare la CLI di Firebase per distribuire le regole al tuo progetto Firebase. Il file firestore.rules nella tua directory di lavoro contiene già le regole dall'alto. Per distribuire queste regole dal tuo file system locale (anziché utilizzare la console Firebase), devi eseguire il seguente comando:

firebase deploy --only firestore:rules

In questo codelab hai imparato come eseguire letture e scritture di base e avanzate con Cloud Firestore, nonché come proteggere l'accesso ai dati con regole di sicurezza. Puoi trovare la soluzione completa nel repository quickstarts-js .

Per ulteriori informazioni su Cloud Firestore, visita le seguenti risorse: