Con Cloud Functions, puedes manejar eventos en Cloud Firestore sin necesidad de actualizar el código del cliente. Puede realizar cambios en Cloud Firestore a través de la interfaz de instantáneas del documento o mediante el SDK de administración .
En un ciclo de vida típico, una función de Cloud Firestore hace lo siguiente:
- Espera cambios en un documento en particular.
- Se activa cuando ocurre un evento y realiza sus tareas.
- Recibe un objeto de datos que contiene una instantánea de los datos almacenados en el documento especificado. Para eventos de escritura o actualización, el objeto de datos contiene dos instantáneas que representan el estado de los datos antes y después del evento desencadenante.
La distancia entre la ubicación de la instancia de Firestore y la ubicación de la función puede crear una latencia de red significativa. Para optimizar el rendimiento, considere especificar la ubicación de la función cuando corresponda.
Activadores de la función Cloud Firestore
El SDK de Cloud Functions para Firebase exporta un objeto functions.firestore
que le permite crear controladores vinculados a eventos específicos de Cloud Firestore.
Tipo de evento | Desencadenar |
---|---|
onCreate | Se activa cuando se escribe en un documento por primera vez. |
onUpdate | Se activa cuando un documento ya existe y tiene algún valor modificado. |
onDelete | Se activa cuando se elimina un documento con datos. |
onWrite | Se activa cuando se activa onCreate , onUpdate o onDelete . |
Si aún no tiene un proyecto habilitado para Cloud Functions para Firebase, lea Primeros pasos: escriba e implemente sus primeras funciones para configurar y configurar su proyecto de Cloud Functions para Firebase.
Escribir funciones activadas por Cloud Firestore
Definir un disparador de función
Para definir un activador de Cloud Firestore, especifica una ruta de documento y un tipo de evento:
Nodo.js
const functions = require('firebase-functions');
exports.myFunction = functions.firestore
.document('my-collection/{docId}')
.onWrite((change, context) => { /* ... */ });
Las rutas de documentos pueden hacer referencia a un documento específico o a un patrón comodín .
Especificar un solo documento
Si desea activar un evento para cualquier cambio en un documento específico, puede utilizar la siguiente función.
Nodo.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 un grupo de documentos usando comodines
Si desea adjuntar un activador a un grupo de documentos, como cualquier documento de una colección determinada, utilice un {wildcard}
en lugar del ID del documento:
Nodo.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"} });
En este ejemplo, cuando se cambia cualquier campo de cualquier documento en users
, coincide con un comodín llamado userId
.
Si un documento en users
tiene subcolecciones y se cambia un campo en uno de los documentos de esas subcolecciones, el comodín userId
no se activa.
Las coincidencias con comodines se extraen de la ruta del documento y se almacenan en context.params
. Puede definir tantos comodines como desee para sustituir ID de documentos o colecciones explícitas, por ejemplo:
Nodo.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"} });
Activadores de eventos
Activar una función cuando se crea un nuevo documento
Puede activar una función para que se active cada vez que se crea un nuevo documento en una colección utilizando un controlador onCreate()
con un comodín . Esta función de ejemplo llama a createUser
cada vez que se agrega un nuevo perfil de usuario:
Nodo.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 ... });
Activar una función cuando se actualiza un documento
También puede activar una función para que se active cuando se actualiza un documento utilizando la función onUpdate()
con un comodín . Esta función de ejemplo llama updateUser
si un usuario cambia su perfil:
Nodo.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 ... });
Activar una función cuando se elimina un documento
También puede activar una función cuando se elimina un documento usando la función onDelete()
con un comodín . Esta función de ejemplo llama a deleteUser
cuando un usuario elimina su perfil de usuario:
Nodo.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 ... });
Activar una función para todos los cambios en un documento
Si no te importa el tipo de evento que se activa, puedes escuchar todos los cambios en un documento de Cloud Firestore usando la función onWrite()
con un comodín . Esta función de ejemplo llama a modifyUser
si se crea, actualiza o elimina un usuario:
Nodo.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 ... });
Lectura y escritura de datos
Cuando se activa una función, proporciona una instantánea de los datos relacionados con el evento. Puede usar esta instantánea para leer o escribir en el documento que desencadenó el evento, o usar el SDK de Firebase Admin para acceder a otras partes de su base de datos.
Datos del evento
Lectura de datos
Cuando se activa una función, es posible que desee obtener datos de un documento que se actualizó u obtener los datos antes de la actualización. Puede obtener los datos anteriores utilizando change.before.data()
, que contiene la instantánea del documento antes de la actualización. De manera similar, change.after.data()
contiene el estado de la instantánea del documento después de la actualización.
Nodo.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(); });
Puede acceder a las propiedades como lo haría en cualquier otro objeto. Alternativamente, puede utilizar la función get
para acceder a campos específicos:
Nodo.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');
Escribir datos
Cada invocación de función está asociada con un documento específico en su base de datos de Cloud Firestore. Puede acceder a ese documento como DocumentReference
en la propiedad ref
de la instantánea devuelta a su función.
Esta DocumentReference
proviene del SDK de Cloud Firestore Node.js e incluye métodos como update()
, set()
y remove()
para que puedas modificar fácilmente el documento que activó la función.
Nodo.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}); });
Datos fuera del evento desencadenante
Las funciones de la nube se ejecutan en un entorno confiable, lo que significa que están autorizadas como una cuenta de servicio en su proyecto. Puedes realizar lecturas y escrituras usando el SDK de Firebase Admin :
Nodo.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({ ... });
});
Limitaciones
Tenga en cuenta las siguientes limitaciones para los activadores de Cloud Firestore para Cloud Functions:
- El pedido no está garantizado. Los cambios rápidos pueden desencadenar invocaciones de funciones en un orden inesperado.
- Los eventos se entregan al menos una vez, pero un solo evento puede dar lugar a múltiples invocaciones de funciones. Evite depender de mecánicas de una sola vez y escriba funciones idempotentes .
- Cloud Firestore en modo Datastore requiere Cloud Functions (segunda generación). Cloud Functions (1.ª generación) no admite el modo Datastore.
- Cloud Functions (1.ª generación) solo funciona con la base de datos "(predeterminada)" y no admite bases de datos con nombre de Cloud Firestore. Utilice Cloud Functions (segunda generación) para configurar eventos para bases de datos con nombre.
- Un disparador está asociado con una única base de datos. No puede crear un activador que coincida con varias bases de datos.
- Eliminar una base de datos no elimina automáticamente ningún desencadenante de esa base de datos. El desencadenador deja de entregar eventos pero continúa existiendo hasta que lo elimina .
- Si un evento coincidente excede el tamaño máximo de solicitud , es posible que el evento no se entregue a Cloud Functions (1.ª generación).
- Los eventos que no se entregan debido al tamaño de la solicitud se registran en los registros de la plataforma y cuentan para el uso del registro del proyecto.
- Puede encontrar estos registros en el Explorador de registros con el mensaje "El evento no se puede entregar a la función de la nube debido a que el tamaño excede el límite para la 1.ª generación..." de gravedad del
error
. Puede encontrar el nombre de la función en el campofunctionName
. Si el camporeceiveTimestamp
todavía está dentro de una hora a partir de ahora, puede inferir el contenido real del evento leyendo el documento en cuestión con una instantánea antes y después de la marca de tiempo. - Para evitar esa cadencia, puedes:
- Migrar y actualizar a Cloud Functions (segunda generación)
- Reducir el tamaño del documento
- Eliminar las funciones de la nube en cuestión
- Puede desactivar el registro mediante exclusiones , pero tenga en cuenta que los eventos infractores aún no se entregarán.