Activadores de Firebase Realtime Database

Con Cloud Functions, puedes controlar eventos en Firebase Realtime Database sin necesidad de actualizar el código del cliente. Cloud Functions te permite ejecutar operaciones de base de datos con privilegios administrativos completos y garantiza que cada cambio en la base de datos se procese de forma individual. Puedes realizar cambios en Firebase Realtime Database a través del SDK de Firebase Admin.

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

  1. Espera cambios en una ubicación de base de datos específica.

  2. Se activa cuando ocurre un evento y realiza sus tareas.

  3. Recibe un objeto de datos que contiene una instantánea de los datos almacenados en el documento especificado.

Tipos de eventos

Las funciones te permiten controlar los eventos de la base de datos en dos niveles de especificidad: puedes detectar específicamente solo eventos de creación, actualización o eliminación, o puedes detectar cambios de cualquier tipo en una ruta de acceso. Cloud Functions admite los siguientes tipos de eventos para Realtime Database:

Tipo de evento Activador
providers/google.firebase.database/eventTypes/ref.write Se activa en cualquier evento de mutación: cuando se crean, actualizan o borran datos en Realtime Database.
providers/google.firebase.database/eventTypes/ref.create (predeterminado) Se activa cuando se crean datos nuevos en Realtime Database.
providers/google.firebase.database/eventTypes/ref.update Se activa cuando se actualizan los datos en Realtime Database.
providers/google.firebase.database/eventTypes/ref.delete Se activa cuando se borran datos de Realtime Database.

Especifica la ruta de la base de datos y la instancia

Para controlar cuándo y dónde se debe activar tu función, tienes que especificar una ruta de acceso y, opcionalmente, una instancia de base de datos.

Ruta

Las especificaciones de la ruta de acceso coinciden con todas las escrituras que afectan una ruta, incluidas aquellas que ocurren en cualquier lugar debajo de ella. Si estableces la ruta de acceso para tu función como /foo/bar, se muestran coincidencias de eventos 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 los datos del evento son grandes, puedes usar 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.

Para especificar un componente de ruta de acceso como comodín, puedes ponerlo entre llaves. foo/{bar} coincide con cualquier elemento secundario de /foo. Los valores de estos componentes de ruta de acceso comodín están disponibles dentro del objeto event.params de la función. En este ejemplo, el valor está disponible como event.params.bar.

Las rutas de acceso con comodines pueden coincidir con varios eventos de una misma escritura. La inserción de

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

coincide con la ruta de acceso /foo/{bar} dos veces: una vez con "hello": "world" y otra vez con "firebase": "functions".

Instancia

Cuando usas Cloud Console, si no especificas una instancia, la función se implementa en la instancia de base de datos predeterminada del proyecto.

Cuando se usa la herramienta de línea de comandos de gcloud, la instancia debe especificarse como parte de la string --trigger-resource. Por lo general, el nombre de la instancia predeterminado es el mismo que el ID del proyecto.

.

Por ejemplo, si implementas una función en un proyecto con el ID my-project-id, usarás lo siguiente en tu string --trigger-resource:

--trigger-resource projects/_/instances/my-project-id/refs/PATH

Estructura de eventos

Cuando se controla un evento de Realtime Database, el objeto data contiene dos propiedades que se proporcionan en formato de objeto JSON:

  • data: es una instantánea de los datos tomada antes del evento que activó la función.

  • delta: es una instantánea de los datos tomados después del evento que activó la función.

.

Muestra de código

Node.js

/**
 * Triggered by a change to a Firebase RTDB reference.
 *
 * @param {!Object} event The Cloud Functions event.
 */
exports.helloRTDB = event => {
  const triggerResource = event.resource;

  const pathParams = event.params;
  if (pathParams) {
    console.log('Path parameters:');
    Object.keys(pathParams).forEach(key => {
      console.log(`  ${key}: ${pathParams[key]}`);
    });
  }

  console.log(`Function triggered by change to: ${triggerResource}`);
  console.log(`Admin?: ${!!event.auth.admin}`);
  console.log('Delta:');
  console.log(JSON.stringify(event.delta, null, 2));
};

Python

import json
def hello_rtdb(data, context):
    """ Triggered by a change to a Firebase RTDB reference.
    Args:
        data (dict): The event payload.
        context (google.cloud.functions.Context): Metadata for the event.
    """
    trigger_resource = context.resource

    if 'params' in data:
        print('Path parameters:')
        for param, value in data['params'].items():
            print(f'  {param}: {value}')

    print('Function triggered by change to: %s' % trigger_resource)
    print('Admin?: %s' % data.get("admin", False))
    print('Delta:')
    print(json.dumps(data["delta"]))

Go


// Package p contains a Cloud Function triggered by a Firebase Realtime Database
// event.
package p

import (
	"context"
	"fmt"
	"log"

	"cloud.google.com/go/functions/metadata"
)

// RTDBEvent is the payload of a RTDB event.
type RTDBEvent struct {
	Data  interface{} `json:"data"`
	Delta interface{} `json:"delta"`
}

// HelloRTDB handles changes to a Firebase RTDB.
func HelloRTDB(ctx context.Context, e RTDBEvent) error {
	meta, err := metadata.FromContext(ctx)
	if err != nil {
		return fmt.Errorf("metadata.FromContext: %v", err)
	}
	log.Printf("Function triggered by change to: %v", meta.Resource)
	log.Printf("%+v", e)
	return nil
}

Java

import com.google.cloud.functions.Context;
import com.google.cloud.functions.RawBackgroundFunction;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.logging.Logger;

public class FirebaseRtdb implements RawBackgroundFunction {
  private static final Logger logger = Logger.getLogger(FirebaseRtdb.class.getName());

  // Use GSON (https://github.com/google/gson) to parse JSON content.
  private static final Gson gson = new Gson();

  @Override
  public void accept(String json, Context context) {
    logger.info("Function triggered by change to: " + context.resource());

    JsonObject body = gson.fromJson(json, JsonObject.class);

    boolean isAdmin = false;
    if (body != null && body.has("auth")) {
      JsonObject authObj = body.getAsJsonObject("auth");
      isAdmin = authObj.has("admin") && authObj.get("admin").getAsBoolean();
    }

    logger.info("Admin?: " + isAdmin);

    if (body != null && body.has("delta")) {
      logger.info("Delta:");
      logger.info(body.get("delta").toString());
    }
  }
}

C#

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Firebase.Database.V1;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace FirebaseRtdb
{
    public class Function : ICloudEventFunction<ReferenceEventData>
    {
        private readonly ILogger _logger;

        public Function(ILogger<Function> logger) =>
            _logger = logger;

        public Task HandleAsync(CloudEvent cloudEvent, ReferenceEventData data, CancellationToken cancellationToken)
        {
            _logger.LogInformation("Function triggered by change to {subject}", cloudEvent.Subject);
            _logger.LogInformation("Delta: {delta}", data.Delta);

            // In this example, we don't need to perform any asynchronous operations, so the
            // method doesn't need to be declared async.
            return Task.CompletedTask;
        }
    }
}

Implementa la función

Con el siguiente comando de gcloud, se implementa una función que se activará mediante eventos create en la ruta /messages/{pushId}/original:

gcloud functions deploy YOUR_FUNCTION_NAME \
  --trigger-event providers/google.firebase.database/eventTypes/ref.create \
  --trigger-resource projects/_/instances/DATABASE_INSTANCE/refs/messages/{pushId}/original \
  --runtime RUNTIME
Argumento Descripción
--trigger-event NAME El nombre del tipo de evento que la función desea recibir. En este caso, será uno de los siguientes: escribir, crear, actualizar o borrar.
--trigger-resource NAME Es la ruta de acceso de la base de datos completamente calificada a la que escuchará la función. Esto debe ajustarse al siguiente formato: projects/_/instances/DATABASE_INSTANCE/refs/PATH.
--runtime RUNTIME Es el nombre del entorno de ejecución que usas. Para obtener una lista completa, consulta la gcloudreferencia.