Ir para o console

Acionadores do Cloud Firestore

Com o Cloud Functions, é possível processar eventos no Cloud Firestore sem precisar atualizar o código do cliente, além de fazer alterações no Cloud Firestore por meio da interface do DocumentSnapshot ou do SDK Admin.

Em um ciclo de vida comum, uma função do Cloud Firestore realiza as seguintes tarefas:

  1. Espera por alterações em um documento específico.
  2. É acionada quando um evento ocorre e realiza as respectivas tarefas (consulte O que posso fazer com o Cloud Functions? para ver exemplos de casos de uso).
  3. Recebe um objeto de dados que contém um instantâneo dos dados armazenados no documento especificado. Para eventos onWrite ou onUpdate, o objeto de dados contém dois instantâneos que representam o estado de dados antes e depois do evento de acionamento.

A distância entre o local da instância do Firestore e o local da função pode criar uma latência de rede significativa. Para otimizar o desempenho, especifique o local da função, quando aplicável.

Acionadores da função Cloud Firestore

O SDK do Cloud Functions para Firebase exporta um objeto functions.firestore que permite a criação de gerenciadores relacionados a eventos específicos do Cloud Firestore.

Tipo de evento Acionador
onCreate Acionado quando um documento é gravado pela primeira vez.
onUpdate Acionado quando um documento já existe e tem algum valor alterado.
onDelete Acionado quando um documento com dados é excluído.
onWrite Acionado quando onCreate, onUpdate ou onDelete é acionado.

Se você ainda não ativou um projeto do Cloud Functions para Firebase, leia o documento Primeiros passos: gravar e implantar suas primeiras funções para configurar um projeto.

Como gravar funções acionadas pelo Cloud Firestore

Definir um acionador de função

Para definir um acionador do Cloud Firestore, especifique um caminho do documento e um tipo de evento:

Node.js

const functions = require('firebase-functions');

exports.myFunction = functions.firestore
  .document('...')
  .onWrite((change, context) => { /* ... */ });

Os caminhos do documento podem fazer referência a um documento específico ou a um padrão de caractere curinga.

Especificar um único documento

Se você quiser ativar um evento para qualquer alteração em um documento específico, use a seguinte função.

Node.js

// Listen for any change on document `marie` in collection `users`
exports.myFunctionName = functions.firestore
    .document('users/marie').onWrite((change, context) => {
      // ... Your code here
    });

Especificar um grupo de documentos com caracteres curinga

Para adicionar um acionador a um grupo de documentos, como qualquer documento em uma determinada coleção, use um {wildcard} no lugar do código do documento:

Node.js

// Listen for changes in all documents in the 'users' collection
exports.useWildcard = functions.firestore
    .document('users/{userId}')
    .onWrite((change, context) => {
      // If we set `/users/marie` to {name: "Marie"} then
      // context.params.userId == "marie"
      // ... and ...
      // change.after.data() == {name: "Marie"}
    });

Neste exemplo, quando qualquer campo de qualquer documento em users for alterado, ele corresponderá a um caractere curinga chamado userId.

Se um documento em users tiver subcoleções e um campo em um dos documentos dessas subcoleções for alterado, o caractere curinga userId não será acionado.

As correspondências de caractere curinga são extraídas do caminho do documento e armazenadas em context.params. É possível definir quantos caracteres curinga você quiser para substituir a coleção explícita ou os códigos do documento:

Node.js

// Listen for changes in all documents in the 'users' collection and all subcollections
exports.useMultipleWildcards = functions.firestore
    .document('users/{userId}/{messageCollectionId}/{messageId}')
    .onWrite((change, context) => {
      // If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
      // context.params.userId == "marie";
      // context.params.messageCollectionId == "incoming_messages";
      // context.params.messageId == "134";
      // ... and ...
      // change.after.data() == {body: "Hello"}
    });

Acionadores de evento

Acionar uma função quando um novo documento é criado

Será possível acionar o disparo de uma função sempre que um novo documento for criado em uma coleção. Para isso, use um gerenciador onCreate() com um caractere curinga. Esta função de exemplo chama createUser sempre que um novo perfil de usuário é adicionado:

Node.js

exports.createUser = functions.firestore
    .document('users/{userId}')
    .onCreate((snap, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = snap.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

Acionar uma função quando um documento é atualizado

Também será possível acionar o disparo de uma função quando um documento for atualizado. Para isso, use a função onUpdate() com um caractere curinga. Esta função de exemplo chamará updateUser se um usuário alterar o perfil dele:

Node.js

exports.updateUser = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

Acionar uma função quando um documento é excluído

Também será possível acionar uma função quando um documento for excluído. Para isso, use a função onDelete() com um caractere curinga. Esta função de exemplo chama deleteUser quando um usuário exclui o perfil de usuário dele:

Node.js

exports.deleteUser = functions.firestore
    .document('users/{userID}')
    .onDelete((snap, context) => {
      // Get an object representing the document prior to deletion
      // e.g. {'name': 'Marie', 'age': 66}
      const deletedValue = snap.data();

      // perform desired operations ...
    });

Acionar uma função para todas as alterações em um documento

Se o tipo de evento acionado não for relevante, será possível detectar todas as alterações em um documento do Cloud Firestore. Para isso, use a função onWrite() com um caractere curinga. Esta função de exemplo chama modifyUser se um usuário for criado, atualizado ou excluído:

Node.js

exports.modifyUser = functions.firestore
    .document('users/{userID}')
    .onWrite((change, context) => {
      // Get an object with the current document value.
      // If the document does not exist, it has been deleted.
      const document = change.after.exists ? change.after.data() : null;

      // Get an object with the previous document value (for update or delete)
      const oldDocument = change.before.data();

      // perform desired operations ...
    });

Como ler e gravar dados

Quando uma função é acionada, ela fornece um instantâneo dos dados relacionados ao evento. É possível usar esse instantâneo para ler ou gravar no documento usado para acionar o evento ou usar o SDK Admin do Firebase para acessar outras partes do seu banco de dados.

Dados do evento

Como ler dados

Quando uma função for acionada, veja os dados de um documento que foi atualizado ou colete-os antes da atualização. Veja os dados anteriores usando change.before.data(), que contém o instantâneo do documento antes da atualização. Da mesma forma, change.after.data() contém o estado do instantâneo do documento após a atualização.

Node.js

exports.updateUser = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the current document
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();
    });

Acesse as propriedades como faria em qualquer outro objeto. Se preferir, use a função get para acessar campos específicos:

Node.js

// Fetch data using standard accessors
const age = snap.data().age;
const name = snap.data()['name'];

// Fetch data using built in accessor
const experience = snap.get('experience');

Gravação de dados

Cada invocação de função está associada a um documento específico no seu banco de dados do Cloud Firestore. É possível acessar esse documento como um DocumentReference na propriedade ref do instantâneo retornado pela sua função.

Esse DocumentReference é originário do SDK do Cloud Firestore para Node.js e inclui métodos como update(), set() e remove(). Assim, fica fácil modificar o documento usado para acionar a função.

Node.js

// Listen for updates to any `user` document.
exports.countNameChanges = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Retrieve the current and previous value
      const data = change.after.data();
      const previousData = change.before.data();

      // We'll only update if the name has changed.
      // This is crucial to prevent infinite loops.
      if (data.name == previousData.name) return null;

      // Retrieve the current count of name changes
      let count = data.name_change_count;
      if (!count) {
        count = 0;
      }

      // Then return a promise of a set operation to update the count
      return change.after.ref.set({
        name_change_count: count + 1
      }, {merge: true});
    });

Dados fora do evento de acionador

O Cloud Functions é executado em um ambiente confiável, o que significa que ele é autorizado como uma conta de serviço em seu projeto. É possível executar leituras e gravações com o SDK Admin do Firebase:

Node.js

const admin = require('firebase-admin');
admin.initializeApp();

const db = admin.firestore();

exports.writeToFirestore = functions.firestore
  .document('some/doc')
  .onWrite((change, context) => {
    db.doc('some/otherdoc').set({ ... });
  });

Limitações e garantias

Ao desenvolver seus aplicativos, lembre-se de que os acionadores do Cloud Firestore estão atualmente na versão Beta, o que pode resultar em comportamentos inesperados.

Algumas limitações conhecidas incluem:

  • O acionamento de uma função pode levar até 10 segundos após uma alteração nos dados do Cloud Firestore.
  • Assim como em todas as funções de segundo plano, a ordenação de eventos não é garantida. Além disso, um único evento pode resultar em várias invocações do Cloud Functions. Portanto, para garantir funções de alta qualidade, grave-as usando o conceito de idempotência.