Entérate de todos los anuncios de Firebase Summit y descubre cómo Firebase puede ayudarte a acelerar el desarrollo de las apps y a ejecutarlas con confianza. Más información

Activadores de base de datos en tiempo real

En un ciclo de vida típico, una función de Firebase Realtime Database hace lo siguiente:

  1. Espera los cambios en una ruta particular de Realtime Database.
  2. Se dispara cuando ocurre un evento y realiza sus tareas.
  3. Recibe un objeto de datos que contiene una instantánea de los datos almacenados en esa ruta.

Puede activar una función en respuesta a la escritura, creación, actualización o eliminación de nodos de base de datos en Firebase Realtime Database.

Activar una función en los cambios de Firebase Realtime Database

Use el firebase-functions/v2/database para crear una función que maneje los eventos de Firebase Realtime Database. Para controlar cuándo se activa la función, especifique uno de los controladores de eventos y especifique la ruta de Realtime Database donde escuchará los eventos.

Configuración de la ubicación de la función

La distancia entre la ubicación de una instancia de Realtime Database y la ubicación de la función puede crear una latencia de red significativa. Además, una discrepancia entre regiones puede provocar un error de implementación. Para evitar estas situaciones, especifique la ubicación de la función para que coincida con la ubicación de la instancia de la base de datos.

Manejo de eventos de la base de datos en tiempo real

Las funciones le permiten manejar eventos de Realtime Database en dos niveles de especificidad; puede escuchar específicamente solo eventos de escritura, creación, actualización o eliminación, o puede escuchar cualquier cambio de cualquier tipo en una referencia.

Estos controladores para responder a eventos de Realtime Database están disponibles:

  • onValueWritten() Solo se activa cuando los datos se escriben en Realtime Database.
  • onValueCreated() Solo se activa cuando se crean datos en Realtime Database.
  • onValueUpdated() Solo se activa cuando los datos se actualizan en Realtime Database.
  • onValueDeleted() Solo se activa cuando se eliminan datos en Realtime Database.

Especificar instancia y ruta

Para controlar cuándo y dónde debe activarse su función, configure su función con una ruta y, opcionalmente, una instancia de Realtime Database. Si no especifica una instancia, la función se implementa en todas las instancias de Realtime Database en la región de la función. También puede especificar un patrón de instancia de Realtime Database para implementar en un subconjunto selectivo de instancias en la misma región.

Por ejemplo, usando onValueWritten() para ilustración:

# All Realtime Database instances in default function region us-central1 at path "/user/{uid}"
# There must be at least one Realtime Database present in us-central1.
const onwrittenfunctiondefault = onValueWritten("/user/{uid}", (event) => {
  // …
});

# Instance named "my-app-db-2", at path "/user/{uid}".
# The "my-app-db-2" instance must exist in this region.
const onwrittenfunctioninstance = onValueWritten(
  {
    ref: "/user/{uid}",
    instance: "my-app-db-2"
    // This example assumes us-central1, but to set location:
    // region: "europe-west1"
  },
  (event) => {
    // …
  }
);

# Instance with "my-app-db-" prefix, at path "/user/{uid}", where uid ends with @gmail.com.
# There must be at least one Realtime Database with "my-app-db-*" prefix in this region.
const onwrittenfunctioninstance = onValueWritten(
  {
    ref: "/user/{uid=*@gmail.com}",
    instance: "my-app-db-*"
    // This example assumes us-central1, but to set location:
    // region: "europe-west1"
  },
  (event) => {
    // …
  }
);

Estos parámetros dirigen su función para manejar escrituras en una determinada ruta dentro de la instancia de Realtime Database.

Las especificaciones de la ruta coinciden con todas las escrituras que tocan una ruta, incluidas las escrituras que ocurren en cualquier lugar debajo de ella. Si configura la ruta para su función como /foo/bar , coincide con los eventos en estas dos ubicaciones:

 /foo/bar
 /foo/bar/baz/really/deep/path

En cualquier caso, Firebase interpreta que el evento ocurre en /foo/bar y que los datos del evento incluyen los datos antiguos y nuevos en /foo/bar . Si los datos de eventos pueden ser grandes, considere usar múltiples funciones en rutas más profundas en lugar de una sola función cerca de la raíz de su base de datos. Para obtener el mejor rendimiento, solo solicite datos en el nivel más profundo posible.

Comodín y captura

Puede usar {key} , {key=*} , {key=prefix*} , {key=*suffix} para capturar. * , prefix* , *suffix para comodines de un solo segmento. Nota: ** representa comodines de varios segmentos, que RTDB no admite. Consulte Comprender los patrones de ruta .

Comodín de ruta. Puede especificar un componente de ruta como comodín:

  • Usando asterisco, * . Por ejemplo, foo/* coincide con cualquier elemento secundario que se encuentre en un nivel de la jerarquía de nodos por debajo de foo/ .
  • Usando un segmento que contiene exactamente un asterisco, * . Por ejemplo, foo/app*-us coincide con cualquier segmento secundario debajo de foo/ con el prefijo de la app y el sufijo -us .

Las rutas con comodines pueden coincidir con varios eventos de, por ejemplo, una sola escritura. un inserto de

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

coincide con la ruta "/foo/*" dos veces: una vez con "hello": "world" y otra vez con "firebase": "functions" .

Captura de rutas. Puede capturar coincidencias de ruta en variables nombradas para usarlas en su código de función (por ejemplo /user/{uid} , /user/{uid=*-us} ).

Los valores de las variables de captura están disponibles dentro del objeto base de datos.DatabaseEvent.params de su función.

Comodín de instancia. También puede especificar un componente de instancia mediante comodines. Un comodín de instancia puede tener un prefijo, un sufijo o ambos (por ejemplo my-app-*-prod ).

Comodín y referencia de captura

Con Cloud Functions (2.ª generación) y Realtime Database, se puede usar un patrón al especificar ref e instance . Cada interfaz de activación tendrá las siguientes opciones para determinar el alcance de una función:

Especificando ref Especificando instance Conducta
Soltero ( /foo/bar ) sin especificar Controlador de ámbitos para todas las instancias en la región de la función.
Soltero ( /foo/bar ) Single ( 'my-new-db' ) Controlador de ámbitos a la instancia específica en la región de la función.
Soltero ( /foo/bar ) Patrón ( 'inst-prefix*' ) Manejador de ámbitos a todas las instancias que coinciden con el patrón en la región de la función.
Patrón ( /foo/{bar} ) sin especificar Controlador de ámbitos para todas las instancias en la región de la función.
Patrón ( /foo/{bar} ) Single ( 'my-new-db' ) Controlador de ámbitos a la instancia específica en la región de la función.
Patrón ( /foo/{bar} ) Patrón ( 'inst-prefix*' ) Manejador de ámbitos a todas las instancias que coinciden con el patrón en la región de la función.

Manejar datos de eventos

Al manejar un evento de Realtime Database, el objeto de datos devuelto es un DataSnapshot .

Para los eventos onValueWritten o onValueUpdated , el primer parámetro es un objeto Change que contiene dos instantáneas que representan el estado de los datos antes y después del evento desencadenante.

Para los eventos onValueCreated y onValueDeleted , el objeto de datos devuelto es una instantánea de los datos creados o eliminados.

En este ejemplo, la función recupera la instantánea para la ruta especificada foo/bar como snap , convierte la cadena en esa ubicación a mayúsculas y escribe esa cadena modificada en la base de datos:

// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
export makeuppercase = onValueCreated("foo/bar", (event) => {
      // Grab the current value of what was written to the Realtime Database.
      const original = event.data.val();
      functions.logger.log('Uppercasing', event.params.pushId, original);
      const uppercase = original.toUpperCase();
      // You must return a Promise when performing asynchronous tasks inside a Functions such as
      // writing to the Firebase Realtime Database.
      // Setting an "uppercase" sibling in the Realtime Database returns a Promise.
      return event.data.ref.parent.child('uppercase').set(uppercase);
    });

Lectura del valor anterior

El objeto Change tiene una propiedad before que le permite inspeccionar lo que se guardó en Realtime Database antes del evento. La propiedad before devuelve una DataSnapshot donde todos los métodos (por ejemplo, val() y exists() ) hacen referencia al valor anterior. Puede volver a leer el nuevo valor utilizando la DataSnapshot original o leyendo la propiedad after . Esta propiedad en cualquier Change es otra DataSnapshot de datos que representa el estado de los datos después de que ocurrió el evento.

Por ejemplo, la propiedad before se puede usar para asegurarse de que la función solo escriba en mayúsculas el texto cuando se crea por primera vez:

    exports makeuppercase = onValueWritten("/messages/{pushId}/original", (event) => {
          // Only edit data when it is first created.
          if (event.data.before.exists()) {
            return null;
          }
          // Exit when the data is deleted.
          if (!event.data.after.exists()) {
            return null;
          }
          // Grab the current value of what was written to the Realtime Database.
          const original = event.data.after.val();
          console.log('Uppercasing', event.params.pushId, original);
          const uppercase = original.toUpperCase();
          // You must return a Promise when performing asynchronous tasks inside a Functions such as
          // writing to the Firebase Realtime Database.
          // Setting an "uppercase" sibling in the Realtime Database returns a Promise.
          return event.data.after.ref.parent.child('uppercase').set(uppercase);
        });