Com o Cloud Functions, você pode gerenciar eventos no Cloud Firestore sem precisar atualizar o código do cliente. Você pode fazer alterações no Cloud Firestore por meio da interface de snapshot de documentos ou do Admin SDK .
Em um ciclo de vida típico, uma função do Cloud Firestore faz o seguinte:
- Aguarda alterações em um documento específico.
- É acionado quando um evento ocorre e executa suas tarefas.
- Recebe um objeto de dados que contém um instantâneo dos dados armazenados no documento especificado. Para eventos de gravação ou atualização, o objeto de dados contém dois instantâneos que representam o estado dos dados antes e depois do evento acionador.
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, considere especificar o local da função quando aplicável.
Gatilhos de função do Cloud Firestore
O SDK do Cloud Functions para Firebase exporta um objeto functions.firestore
que permite criar manipuladores vinculados a eventos específicos do Cloud Firestore.
Tipo de evento | Acionar |
---|---|
onCreate | Acionado quando um documento é gravado pela primeira vez. |
onUpdate | Disparado 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 tem um projeto habilitado para Cloud Functions para Firebase, leia Primeiros passos: escreva e implante suas primeiras funções para configurar e configurar seu projeto do Cloud Functions para Firebase.
Escrevendo funções acionadas pelo Cloud Firestore
Defina um gatilho de função
Para definir um gatilho do Cloud Firestore, especifique um caminho de documento e um tipo de evento:
Node.js
const functions = require('firebase-functions');
exports.myFunction = functions.firestore
.document('my-collection/{docId}')
.onWrite((change, context) => { /* ... */ });
Os caminhos dos documentos podem fazer referência a um documento específico ou a um padrão curinga .
Especifique um único documento
Se quiser acionar um evento para qualquer alteração em um documento específico, você pode usar 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 });
Especifique um grupo de documentos usando curingas
Se você quiser anexar um gatilho a um grupo de documentos, como qualquer documento de uma determinada coleção, use um {wildcard}
no lugar do ID 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 em qualquer documento em users
é alterado, ele corresponde a um curinga chamado userId
.
Se um documento em users
tiver subcoleções e um campo em um dos documentos dessas subcoleções for alterado, o curinga userId
não será acionado.
As correspondências de curinga são extraídas do caminho do documento e armazenadas em context.params
. Você pode definir quantos curingas desejar para substituir IDs explícitos de coleções ou documentos, por exemplo:
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"} });
Gatilhos de eventos
Acione uma função quando um novo documento for criado
Você pode acionar uma função para disparar sempre que um novo documento for criado em uma coleção usando um manipulador onCreate()
com um 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 ... });
Acione uma função quando um documento for atualizado
Você também pode acionar uma função para disparar quando um documento é atualizado usando a função onUpdate()
com um curinga . Esta função de exemplo chama updateUser
se um usuário alterar seu perfil:
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 ... });
Acione uma função quando um documento for excluído
Você também pode acionar uma função quando um documento é excluído usando a função onDelete()
com um curinga . Este exemplo de função chama deleteUser
quando um usuário exclui seu perfil de usuário:
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 ... });
Acione uma função para todas as alterações em um documento
Se você não se importa com o tipo de evento que está sendo disparado, você pode ouvir todas as alterações em um documento do Cloud Firestore usando a função onWrite()
com um 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 ... });
Lendo e gravando dados
Quando uma função é acionada, ela fornece um instantâneo dos dados relacionados ao evento. Você pode usar esse snapshot para ler ou gravar no documento que acionou o evento ou usar o SDK Admin do Firebase para acessar outras partes do seu banco de dados.
Dados do Evento
Lendo dados
Quando uma função é acionada, você pode querer obter dados de um documento que foi atualizado ou obter os dados antes da atualização. Você pode obter 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.updateUser2 = 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(); });
Você pode acessar propriedades como faria em qualquer outro objeto. Alternativamente, você pode usar 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');
Gravando dados
Cada invocação de função está associada a um documento específico no banco de dados do Cloud Firestore. Você pode acessar esse documento como DocumentReference
na propriedade ref
do instantâneo retornado para sua função.
Este DocumentReference
vem do SDK Node.js do Cloud Firestore e inclui métodos como update()
, set()
e remove()
para que você possa modificar facilmente o documento que acionou 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 acionador
O Cloud Functions é executado em um ambiente confiável, o que significa que são autorizados como uma conta de serviço no seu projeto. Você pode realizar leituras e gravações usando 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
Observe as seguintes limitações para gatilhos do Cloud Firestore para Cloud Functions:
- O pedido não é garantido. Mudanças rápidas podem acionar invocações de funções em uma ordem inesperada.
- Os eventos são entregues pelo menos uma vez, mas um único evento pode resultar em múltiplas invocações de funções. Evite depender da mecânica exatamente uma vez e escreva funções idempotentes .
- O Cloud Firestore no modo Datastore requer Cloud Functions (2ª geração). O Cloud Functions (1ª geração) não é compatível com o modo Datastore.
- O Cloud Functions (1ª geração) funciona apenas com banco de dados "(padrão)" e não é compatível com bancos de dados nomeados do Cloud Firestore. Use o Cloud Functions (2ª geração) para configurar eventos para bancos de dados nomeados.
- Um gatilho está associado a um único banco de dados. Você não pode criar um gatilho que corresponda a vários bancos de dados.
- A exclusão de um banco de dados não exclui automaticamente nenhum acionador desse banco de dados. O gatilho para de entregar eventos, mas continua existindo até que você exclua o gatilho .
- Se um evento correspondente exceder o tamanho máximo da solicitação , o evento poderá não ser entregue ao Cloud Functions (1ª geração).
- Os eventos não entregues devido ao tamanho da solicitação são registrados nos logs da plataforma e contam para o uso do log do projeto.
- Você pode encontrar esses logs no Logs Explorer com a mensagem "O evento não pode ser entregue à função Cloud devido ao tamanho exceder o limite da 1ª geração..." de gravidade
error
. Você pode encontrar o nome da função no campofunctionName
. Se o camporeceiveTimestamp
ainda estiver dentro de uma hora, você poderá inferir o conteúdo real do evento lendo o documento em questão com um instantâneo antes e depois do carimbo de data/hora. - Para evitar essa cadência, você pode:
- Migrar e fazer upgrade para o Cloud Functions (2ª geração)
- Reduza o tamanho do documento
- Exclua o Cloud Functions em questão
- Você pode desativar o registro em log usando exclusões , mas observe que os eventos ofensivos ainda não serão entregues.