Ir a la consola

Amplía Cloud Firestore con Cloud Functions

Con Cloud Functions, puedes implementar código de Node.js para administrar eventos que se activan con los cambios en tu base de datos de Cloud Firestore. Esto te permite agregar con facilidad funciones del lado del servidor a tu app, sin ejecutar tus propios servidores.

Para ver ejemplos de casos prácticos, consulta ¿Qué puedo hacer con Cloud Functions? o las muestras de Functions en el repositorio de GitHub.

Activadores de funciones de Cloud Firestore

El SDK de Cloud Functions para Firebase exporta un objeto functions.firestore que te permite crear controladores vinculados con eventos específicos de Cloud Firestore.

Tipo de evento Activador
onCreate Se activa cuando se escribe en un documento por primera vez.
onUpdate Se activa cuando un documento ya existe y se cambia uno de sus valores.
onDelete Se activa cuando se borra un documento con datos.
onWrite Se activa cuando se inicia onCreate, onUpdate o onDelete.

Si aún no tienes un proyecto habilitado para Cloud Functions para Firebase, lee Primeros pasos: Cómo escribir y también implementar tus primeras funciones a fin de configurar el proyecto de Cloud Functions para Firebase.

Escribe funciones activadas por Cloud Firestore

Define un activador de función

Para definir un activador de Cloud Firestore, especifica la ruta de acceso de un documento y un tipo de evento:

Node.js

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

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

Las rutas de acceso de los documentos pueden hacer referencia a un documento específico o un patrón de comodín.

Especifica un solo documento

Si deseas activar un evento para cualquier cambio que se realice a un documento específico, puedes usar la siguiente función.

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

Especifica un grupo de documentos mediante comodines

Si deseas conectar un activador a un grupo de documentos, como cualquier documento de una colección determinada, utiliza un {wildcard} en lugar del ID del 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"}
    });

En este ejemplo, cuando se cambia algún campo en cualquier documento de users, coincide con un comodín denominado userId.

Si un documento de users tiene subcolecciones y se modifica un campo de uno de los documentos en ellas, el comodín userId no se activará.

Las coincidencias de comodines se extraen de la ruta del documento y se almacenan en context.params. Puedes definir tantos comodines como desees para sustituir los ID explícitos de colección o de documento, por ejemplo:

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

Activadores de eventos

Activa una función cuando se crea un documento nuevo

Puedes usar un controlador onCreate() con un comodín para que se active una función cada vez que se cree un documento nuevo en una colección. Esta función de ejemplo llama a createUser cada vez que se agrega un nuevo perfil de usuario:

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

Activa una función cuando se actualiza un documento

También puedes usar la función onUpdate() con un comodín para que se active una función cuando se actualice un documento. Esta función de ejemplo llama a updateUser cada vez que un usuario cambia su 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 ...
    });

Activa una función cuando se borra un documento

También puedes usar la función onDelete() con un comodín para que se active una función cuando se borre un documento. Esta función de ejemplo llama a deleteUser cuando un usuario borra su perfil:

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

Activa una función para todos los cambios en un documento

Si no te importa el tipo de evento que se activa, puedes detectar todos los cambios en un documento de Cloud Firestore. Para ello, usa la función onWrite() con un comodín. En esta función de ejemplo, se llama a modifyUser si se crea, actualiza o borra un usuario:

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

Lectura y escritura de datos

Cuando se activa una función, esta proporciona una instantánea de los datos relacionados con el evento. Puedes usar esta instantánea para leer el documento que activó el evento o escribir en él, o bien usar el SDK de Firebase Admin a fin de acceder a otras partes de tu base de datos.

Datos de eventos

Lee datos

Cuando se activa una función, es posible que desees obtener datos de un documento que se actualizó o que quieras obtenerlos antes de la actualización. Para obtener los datos previos, puedes usar 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.

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

Puedes acceder a las propiedades del mismo modo que con cualquier otro objeto. También puedes utilizar la función get para acceder a 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');

Escribe datos

Cada invocación de función está asociada a un documento específico en tu base de datos de Cloud Firestore. Puedes acceder a ese documento como una DocumentReference en la propiedad ref de la instantánea que se mostró a tu función.

Esta DocumentReference proviene del SDK de Cloud Firestore para Node.js que incluye métodos (como update(), set() y remove()) que te permiten modificar fácilmente el documento que activó la función.

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

Datos fuera del evento activador

Las funciones de Cloud Functions se ejecutan en entornos de confianza, lo que significa que están autorizadas como una cuenta de servicio en tu proyecto. Puedes realizar operaciones de lectura y escritura con el SDK de Firebase Admin:

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({ ... });
  });

Limitaciones y garantías

Los activadores de Cloud Firestore para Cloud Functions son una función Beta con algunas limitaciones conocidas:

  • Una función puede tardar hasta 10 segundos en responder a los cambios en Cloud Firestore.
  • No se garantiza el ordenamiento. Los cambios rápidos pueden activar invocaciones de funciones en un orden inesperado.
  • Los eventos se entregan al menos una vez, pero un solo evento puede dar lugar a varias invocaciones de funciones. Evita depender de la mecánica exacta de entrega de eventos una vez y escribe funciones idempotentes.
  • Los activadores de Cloud Firestore para Cloud Functions solo están disponibles para Cloud Firestore en modo nativo. No están disponibles para Cloud Firestore en modo Datastore.