O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Cloud Firestore Web Codelab

Metas

Neste codelab, você vai construir um web app restaurante recomendação alimentado por Nuvem Firestore .

img5.png

O que você aprenderá

  • Ler e gravar dados no Cloud Firestore a partir de um aplicativo da web
  • Ouça as alterações nos dados do Cloud Firestore em tempo real
  • Use Firebase Authentication e regras de segurança para proteger os dados do Cloud Firestore
  • Escreva consultas complexas do Cloud Firestore

O que você precisará

Antes de iniciar este codelab, verifique se você instalou:

Crie um projeto Firebase

  1. Na consola Firebase , clique em Adicionar projeto, então nomear os FriendlyEats projeto Firebase.

Lembre-se do ID do projeto para seu projeto Firebase.

  1. Clique em Criar projeto.

O aplicativo que vamos construir usa alguns serviços do Firebase disponíveis na web:

  • Autenticação Firebase para identificar facilmente os seus usuários
  • Nuvem Firestore para salvar dados estruturados na nuvem e obter notificação instantânea quando os dados são atualizados
  • Firebase hospedagem para hospedar e servir seus ativos estáticos

Para este codelab específico, já configuramos o Firebase Hosting. No entanto, para Firebase Auth e Cloud Firestore, orientaremos você na configuração e ativação dos serviços usando o console do Firebase.

Habilitar autenticação anônima

Embora a autenticação não seja o foco deste codelab, é importante ter alguma forma de autenticação em nosso aplicativo. Vamos usar o login Anonymous - o que significa que o usuário será silenciosamente assinado em sem ser solicitado.

Você precisa ativar o login anônimo.

  1. No console Firebase, localize a seção Desenvolver na navegação à esquerda.
  2. Clique em Autenticação, clique no sinal-in guia método (ou clique aqui para ir diretamente lá).
  3. Ativar o Sign-in fornecedor anónimo, clique em Salvar.

img7.png

Isso permitirá que o aplicativo faça o login silencioso de seus usuários quando eles acessarem o aplicativo da web. Sinta-se livre para ler a documentação autenticação anônima para saber mais.

Ativar Cloud Firestore

O aplicativo usa o Cloud Firestore para salvar e receber informações e classificações de restaurantes.

Você precisará habilitar o Cloud Firestore. Na seção de construção do o Firebase console, clique Firestore banco de dados. Clique em Criar banco de dados no painel de Nuvem Firestore.

O acesso aos dados no Cloud Firestore é controlado por regras de segurança. Falaremos mais sobre regras posteriormente neste codelab, mas primeiro precisamos definir algumas regras básicas em nossos dados para começar. Na guia Regras do console Firebase adicione as seguintes regras e, em seguida, clique em Publicar.

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

As regras acima restringem o acesso aos dados para usuários que estão conectados, o que impede que usuários não autenticados leiam ou gravem. Isso é melhor do que permitir o acesso público, mas ainda está longe de ser seguro. Vamos aprimorar essas regras posteriormente no codelab.

Clonar o repositório GitHub a partir da linha de comando:

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

O código de exemplo deveria ter sido clonados no 📁 friendlyeats-web diretório. De agora em diante, certifique-se de executar todos os seus comandos a partir deste diretório:

cd friendlyeats-web

Importe o aplicativo inicial

Usando seu IDE (WebStorm, Atom, Sublime, Visual Código Estúdio ...) abrir ou importar o 📁 friendlyeats-web diretório. Este diretório contém o código inicial para o codelab, que consiste em um aplicativo de recomendação de restaurante ainda não funcional. Vamos torná-lo funcional em todo este codelab, portanto, você precisará editar o código nesse diretório em breve.

A Firebase Command Line Interface (CLI) permite que você veicule seu aplicativo da web localmente e implante-o no Firebase Hosting.

  1. Instale a CLI executando o seguinte comando npm:
npm -g install firebase-tools
  1. Verifique se a CLI foi instalada corretamente executando o seguinte comando:
firebase --version

Certifique-se de que a versão da Firebase CLI é v7.4.0 ou posterior.

  1. Autorize a Firebase CLI executando o seguinte comando:
firebase login

Configuramos o modelo de aplicativo da web para obter a configuração do seu aplicativo para Firebase Hosting do diretório local e dos arquivos do seu aplicativo. Mas, para fazer isso, precisamos associar seu aplicativo ao projeto Firebase.

  1. Certifique-se de que sua linha de comando está acessando o diretório local do seu aplicativo.
  2. Associe seu aplicativo ao projeto do Firebase executando o seguinte comando:
firebase use --add
  1. Quando solicitado, selecione o ID do projeto, em seguida, dar o seu projeto Firebase um alias.

Um alias é útil se você tiver vários ambientes (produção, teste, etc). No entanto, para este codelab, vamos apenas usar o alias default .

  1. Siga as instruções restantes em sua linha de comando.

Estamos prontos para realmente começar a trabalhar em nosso aplicativo! Vamos executar nosso aplicativo localmente!

  1. Execute o seguinte comando Firebase CLI:
firebase emulators:start --only hosting
  1. Sua linha de comando deve exibir a seguinte resposta:
hosting: Local server: http://localhost:5000

Estamos usando o hosting Firebase emulador para servir nosso aplicativo localmente. O aplicativo web agora deve estar disponível a partir de http: // localhost: 5000 .

  1. Abra seu aplicativo em http: // localhost: 5000 .

Você deve ver sua cópia do FriendlyEats, que foi conectada ao seu projeto Firebase.

O aplicativo foi conectado automaticamente ao seu projeto Firebase e silenciosamente conectou você como um usuário anônimo.

img2.png

Nesta seção, escreveremos alguns dados no Cloud Firestore para que possamos preencher a IU do aplicativo. Isso pode ser feito manualmente através da consola Firebase , mas vamos fazê-lo no próprio aplicativo para demonstrar uma gravação básica Nuvem Firestore.

Modelo de dados

Os dados do Firestore são divididos em coleções, documentos, campos e subcoleções. Nós iremos guardar cada restaurante como um documento em uma coleção de nível superior chamada restaurants .

img3.png

Mais tarde, vamos armazenar cada revisão em um subcoleção chamado ratings abaixo de cada restaurante.

img4.png

Adicionar restaurantes ao Firestore

O principal objeto de modelo em nosso aplicativo é um restaurante. Vamos escrever algum código que adiciona um documento restaurante para a restaurants coleção.

  1. De seus arquivos baixados, aberto scripts/FriendlyEats.Data.js .
  2. Encontre a função FriendlyEats.prototype.addRestaurant .
  3. Substitua toda a função pelo código a seguir.

FriendlyEats.Data.js

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

O código acima adiciona um novo documento para a restaurants coleção. Os dados do documento vêm de um objeto JavaScript simples. Fazemos isso primeiro obter uma referência a uma nuvem firestore coleta restaurants , em seguida, add 'ing os dados.

Vamos adicionar restaurantes!

  1. Volte para o aplicativo FriendlyEats em seu navegador e atualize-o.
  2. Clique em Adicionar Mock dados.

O aplicativo irá gerar automaticamente um conjunto aleatório de objetos restaurantes, em seguida, chamar o seu addRestaurant função. No entanto, você não vai ainda ver os dados em seu aplicativo web real, porque ainda precisamos implementar recuperando os dados (a próxima seção do codelab).

Se você navegar até a guia Nuvem Firestore no console Firebase, porém, você deve ver agora novos documentos na restaurants coleção!

img6.png

Parabéns, você acabou de gravar dados no Cloud Firestore a partir de um aplicativo da web!

Na próxima seção, você aprenderá como recuperar dados do Cloud Firestore e exibi-los em seu aplicativo.

Nesta seção, você aprenderá como recuperar dados do Cloud Firestore e exibi-los em seu aplicativo. As duas etapas principais são criar uma consulta e adicionar um ouvinte de instantâneo. Este ouvinte será notificado de todos os dados existentes que correspondam à consulta e receberá atualizações em tempo real.

Primeiro, vamos construir a consulta que servirá a lista padrão não filtrada de restaurantes.

  1. Volte para o arquivo scripts/FriendlyEats.Data.js .
  2. Encontrar a função FriendlyEats.prototype.getAllRestaurants .
  3. Substitua toda a função pelo código a seguir.

FriendlyEats.Data.js

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

  this.getDocumentsInQuery(query, renderer);
};

No código acima, construímos uma consulta que irá recuperar até 50 restaurantes da coleção de nível superior chamados restaurants , que são ordenados pela classificação média (atualmente todos zero). Depois que declarou esta consulta, nós passá-lo para o getDocumentsInQuery() método que é responsável por carregar e processar os dados.

Faremos isso adicionando um ouvinte de instantâneo.

  1. Volte para o arquivo scripts/FriendlyEats.Data.js .
  2. Encontre a função FriendlyEats.prototype.getDocumentsInQuery .
  3. Substitua a função inteira com o código a seguir.

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

No código acima, query.onSnapshot irá acionar o seu retorno cada vez que há uma mudança no resultado da consulta.

  • Pela primeira vez, a chamada de retorno é acionado com todo o conjunto de resultados da consulta - ou seja, o inteiros restaurants coleção de Nuvem Firestore. Em seguida, passa todos os documentos individuais para o renderer.display função.
  • Quando um documento é excluído, change.type igual a removed . Portanto, neste caso, chamaremos uma função que remove o restaurante da IU.

Agora que implementamos os dois métodos, atualize o aplicativo e verifique se os restaurantes que vimos anteriormente no Firebase console agora estão visíveis no aplicativo. Se você concluiu esta seção com sucesso, seu aplicativo agora está lendo e gravando dados com o Cloud Firestore!

Conforme sua lista de restaurantes muda, esse ouvinte continuará atualizando automaticamente. Tente acessar o console do Firebase e excluir manualmente um restaurante ou alterar seu nome - você verá as alterações aparecerem no seu site imediatamente!

img5.png

Até agora, nós mostramos como usar onSnapshot para recuperar as atualizações em tempo real; no entanto, nem sempre é isso que queremos. Às vezes, faz mais sentido buscar os dados apenas uma vez.

Queremos implementar um método que é acionado quando um usuário clica em um restaurante específico em seu aplicativo.

  1. Volte ao seu arquivo de scripts/FriendlyEats.Data.js .
  2. Encontre a função FriendlyEats.prototype.getRestaurant .
  3. Substitua a função inteira com o código a seguir.

FriendlyEats.Data.js

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

Depois de implementar esse método, você poderá visualizar as páginas de cada restaurante. Basta clicar em um restaurante da lista e você deverá ver a página de detalhes do restaurante:

img1.png

Por enquanto, você não pode adicionar classificações, pois ainda precisamos implementar a adição de classificações posteriormente no codelab.

Atualmente, nosso aplicativo exibe uma lista de restaurantes, mas não há como o usuário filtrar com base em suas necessidades. Nesta seção, você usará a consulta avançada do Cloud Firestore para habilitar a filtragem.

Aqui está um exemplo de uma consulta simples para buscar todas as Dim Sum restaurantes:

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

Como o próprio nome indica, o where() método irá fazer o nosso download consulta apenas os membros da coleção cujos campos atender as restrições que estabelecemos. Neste caso, isso só vai baixar restaurantes onde category é Dim Sum .

Em nosso aplicativo, o usuário pode encadear vários filtros para criar consultas específicas, como "Pizza em São Francisco" ou "Frutos do mar em Los Angeles ordenados por popularidade".

Vamos criar um método que constrói uma consulta que filtrará nossos restaurantes com base em vários critérios selecionados por nossos usuários.

  1. Volte ao seu arquivo de scripts/FriendlyEats.Data.js .
  2. Encontrar a função FriendlyEats.prototype.getFilteredRestaurants .
  3. Substitua toda a função pelo código a seguir.

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

O código acima adiciona múltiplos where filtros e um único orderBy cláusula para construir uma consulta composto à base de entrada do usuário. Nossa consulta agora retornará apenas restaurantes que atendam aos requisitos do usuário.

Atualize seu aplicativo FriendlyEats no navegador e, em seguida, verifique se você pode filtrar por preço, cidade e categoria. Durante o teste, você verá erros no Console JavaScript do seu navegador semelhantes a este:

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

Esses erros ocorrem porque o Cloud Firestore requer índices para a maioria das consultas compostas. A exigência de índices em consultas mantém o Cloud Firestore rápido em escala.

Abrir o link da mensagem de erro abrirá automaticamente a IU de criação de índice no console do Firebase com os parâmetros corretos preenchidos. Na próxima seção, escreveremos e implantaremos os índices necessários para este aplicativo.

Se não quisermos explorar todos os caminhos em nosso aplicativo e seguir cada um dos links de criação de índice, podemos facilmente implantar muitos índices de uma vez usando a Firebase CLI.

  1. No diretório local baixado do seu aplicativo, você encontrará uma firestore.indexes.json arquivo.

Este arquivo descreve todos os índices necessários para todas as combinações possíveis de filtros.

firestore.indexes.json

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

   ...

 ]
}
  1. Implante esses índices com o seguinte comando:
firebase deploy --only firestore:indexes

Após alguns minutos, seus índices estarão ativos e as mensagens de erro desaparecerão.

Nesta seção, adicionaremos a capacidade de os usuários enviarem avaliações para restaurantes. Até agora, todas as nossas gravações foram atômicas e relativamente simples. Se algum deles apresentasse um erro, provavelmente apenas solicitaríamos ao usuário que tentasse novamente ou nosso aplicativo tentaria novamente a gravação automaticamente.

Nosso aplicativo terá muitos usuários que desejam adicionar uma classificação para um restaurante, portanto, precisaremos coordenar várias leituras e gravações. Primeiro a revisão em si tem de ser apresentado, em seguida, a classificação do restaurante count e average rating necessidade de ser atualizado. Se um deles falhar, mas o outro não, ficamos em um estado inconsistente, em que os dados em uma parte do nosso banco de dados não correspondem aos dados em outra.

Felizmente, o Cloud Firestore oferece funcionalidade de transação que nos permite realizar várias leituras e gravações em uma única operação atômica, garantindo que nossos dados permaneçam consistentes.

  1. Volte ao seu arquivo de scripts/FriendlyEats.Data.js .
  2. Encontre a função FriendlyEats.prototype.addRating .
  3. Substitua a função inteira com o código a seguir.

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

No bloco acima, desencadear uma transação para atualizar os valores numéricos de avgRating e numRatings no documento restaurante. Ao mesmo tempo, nós adicionamos a nova rating ao ratings subcoleção.

No início deste codelab, definimos as regras de segurança do nosso aplicativo para abrir completamente o banco de dados para qualquer leitura ou gravação. Em um aplicativo real, gostaríamos de definir regras muito mais refinadas para evitar o acesso ou modificação de dados indesejáveis.

  1. Na seção de construção do o Firebase console, clique Firestore banco de dados.
  2. Clique na guia Regras na seção Nuvem Firestore (ou clique aqui para ir diretamente lá).
  3. Substitua os padrões com as seguintes regras, em seguida, clique em Publicar.

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

Essas regras restringem o acesso para garantir que os clientes apenas façam alterações seguras. Por exemplo:

  • As atualizações de um documento de restaurante podem apenas alterar as classificações, não o nome ou quaisquer outros dados imutáveis.
  • As classificações só podem ser criadas se o ID do usuário corresponder ao usuário conectado, o que evita spoofing.

Como alternativa ao console do Firebase, você pode usar a Firebase CLI para implantar regras no seu projeto do Firebase. O firestore.rules arquivo em seu diretório de trabalho já contém as regras de cima. Para implantar essas regras de seu sistema de arquivos local (em vez de usar o console do Firebase), você executaria o seguinte comando:

firebase deploy --only firestore:rules

Neste codelab, você aprendeu a realizar leituras e gravações básicas e avançadas com o Cloud Firestore, bem como proteger o acesso a dados com regras de segurança. Você pode encontrar a solução completa no repositório quickstarts-js .

Para saber mais sobre o Cloud Firestore, visite os seguintes recursos: