En un ciclo de vida típico, una función de Firebase Realtime Database hace lo siguiente:
- Espera cambios en una ruta de acceso de Realtime Database específica.
- 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 esa ruta.
Puedes activar una función en respuesta a la escritura, creación, actualización o eliminación de nodos de la base de datos en Firebase Realtime Database.
Activa una función cuando se realicen cambios en Firebase Realtime Database
Usa el subpaquete firebase-functions/v2/database
para crear una función que controle eventos de Firebase Realtime Database. Para
controlar cuándo se debe activar la función, especifica uno de los controladores de eventos y
la ruta de acceso de Realtime Database en la que se detectarán los eventos.
Configura la ubicación de la función
La distancia entre la ubicación de la instancia de Realtime Database y la ubicación de la función puede generar una latencia de red considerable. Además, la discrepancia entre las regiones puede provocar un error de implementación. Para evitar estas situaciones, especifica la ubicación de la función a fin de que coincida con la ubicación de la instancia de la base de datos.
Controla eventos de Realtime Database
Las funciones te permiten controlar los eventos de Realtime Database en dos niveles de especificidad: puedes detectar específicamente solo eventos de escritura, creación, actualización o eliminación, o puedes detectar cambios de cualquier tipo en cualquier referencia.
Estos son los controladores disponibles para responder a eventos de Realtime Database:
onValueWritten()
: Solo se activa cuando se escriben datos en Realtime Database.onValueCreated()
: Solo se activa cuando se crean datos en Realtime Database.onValueUpdated()
: Solo se activa cuando se actualizan datos en Realtime Database.onValueDeleted()
: Solo se activa cuando se borran datos en Realtime Database.
Especifica la instancia y la ruta
Para controlar cuándo y dónde se debe activar la función, configúrala con una ruta de acceso y, opcionalmente, una instancia de Realtime Database. Si no especificas una instancia, la función se implementa en todas las instancias de Realtime Database de la región de la función. También puedes especificar un patrón de instancias de Realtime Database para implementar en un subconjunto selectivo de instancias en la misma región.
Usemos onValueWritten()
a modo de ejemplo:
# 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 le indican a la función que realice las operaciones de escritura en una ruta de acceso específica dentro de la instancia de Realtime Database.
Las coincidencias de las especificaciones de la ruta de acceso se establecen con todas las escrituras que
afectan una ruta, incluidas las que ocurren por debajo de esa ruta. Si configuras la ruta
para la función como /foo/bar
, se establecerán coincidencias con los eventos que ocurren en estas dos ubicaciones:
/foo/bar
/foo/bar/baz/really/deep/path
En ambos casos, Firebase interpreta que el evento ocurre en /foo/bar
,
y los datos del evento incluyen los datos antiguos y nuevos en /foo/bar
. Si existe la posibilidad de que los eventos
generen un gran volumen de datos, es recomendable que uses varias funciones en rutas de acceso más profundas en lugar de
una sola función cerca de la raíz de la base de datos. Para obtener el mejor rendimiento,
solicita datos únicamente en el nivel más profundo posible.
Comodín y captura
Puedes usar {key}
, {key=*}
, {key=prefix*}
y {key=*suffix}
para la captura. y *
, prefix*
, *suffix
para el comodín de un solo segmento.
Nota: **
representa comodines de múltiples segmentos, lo que no admite RTDB.
Consulta Comprende los patrones de ruta de acceso.
Comodines de ruta de acceso. Puedes especificar un componente de ruta de acceso como comodín:
- Mediante el asterisco
*
. Por ejemplo,foo/*
coincide con cualquier elemento secundario de un nivel de la jerarquía de nodos debajo defoo/
. - Mediante un segmento que contenga exactamente el asterisco
*
. Por ejemplo,foo/app*-us
coincide con cualquier segmento secundario debajo defoo/
con el prefijoapp
y el sufijo-us
.
Pueden establecerse coincidencias entre las rutas de acceso con comodines y varios eventos, por ejemplo, de una misma escritura. En el caso de la inserción de
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
coincide con la ruta de acceso "/foo/*"
dos veces: una vez con "hello": "world"
y otra vez con "firebase": "functions"
.
Captura de rutas de acceso. Puedes capturar coincidencias de rutas de acceso en variables con nombre para usarlas
en el código de tu función (p. ej., /user/{uid}
y /user/{uid=*-us}
).
Los valores de las variables de captura están disponibles dentro del objeto database.DatabaseEvent.params de tu función.
Comodín de instancias. También puedes especificar un
componente de la instancia con comodines. Un comodín de instancia puede tener un prefijo, sufijo o ambos (p. ej., my-app-*-prod
).
Referencia de comodín y captura
Con Cloud Functions (2nd gen) y Realtime Database, se puede usar un patrón cuando se
especifican ref
y instance
. Cada interfaz de activador tendrá las siguientes
opciones para establecer el alcance de una función:
Especifica ref |
Especifica instance |
Comportamiento |
---|---|---|
Único (/foo/bar ) |
No se especifica | Orienta al controlador a todas las instancias en la región de la función. |
Único (/foo/bar ) |
Único (‘my-new-db' ) |
Orienta el controlador a la instancia específica en la región de la función. |
Único (/foo/bar ) |
Patrón (‘inst-prefix*' ) |
Orienta al controlador a todas las instancias que coinciden con el patrón de la región de la función. |
Patrón (/foo/{bar} ) |
No se especifica | Orienta al controlador a todas las instancias en la región de la función. |
Patrón (/foo/{bar} ) |
Único (‘my-new-db' ) |
Orienta el controlador a la instancia específica en la región de la función. |
Patrón (/foo/{bar} ) |
Patrón (‘inst-prefix*' ) |
Orienta al controlador a todas las instancias que coinciden con el patrón de la región de la función. |
Administra datos de eventos
Cuando se controla un evento de Realtime Database, el objeto de datos que se muestra es una
DataSnapshot
.
En el caso de los eventos onValueWritten
o onValueUpdated
, el
primer parámetro es un objeto Change
que contiene dos instantáneas,
las cuales representan el estado de los datos antes y después del evento de activación.
En el caso de los eventos onValueCreated
y onValueDeleted
,
el objeto de datos que se muestra es una instantánea de los datos creados o borrados.
En este ejemplo, la función recupera la instantánea de
la ruta de acceso foo/bar
especificada como snap
, convierte a
mayúsculas la string que se encuentra en esa ubicación y escribe la string 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); });
Lee el valor anterior
El objeto Change
tiene una propiedad before
que te permite inspeccionar lo que se
guardó en Realtime Database antes del evento. La propiedad before
muestra una
DataSnapshot
en la que todos los métodos (por ejemplo,
val()
y
exists()
)
hacen referencia al valor anterior. Puedes volver a leer el valor nuevo si usas
la DataSnapshot
original o lees la
propiedad after
. Esta propiedad, presente en todo Change
, es otra DataSnapshot
que representa
el estado de los datos después del evento.
Por ejemplo, se puede usar la propiedad before
para garantizar que la función solo transforme el texto a mayúsculas 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); });