Attivatori di Firebase Realtime Database

Con le funzioni Cloud Run, puoi gestire gli eventi in Firebase Realtime Database nello stesso progetto Google Cloud della funzione. Le funzioni Cloud Run ti consentono di eseguire operazioni di database con privilegi amministrativi completi e garantiscono che ogni modifica al database venga elaborata singolarmente. Puoi apportare modifiche al database Firebase Realtime tramite l'SDK Firebase Admin.

In un ciclo di vita tipico, una funzione di Firebase Realtime Database esegue le seguenti operazioni:

  1. Attende le modifiche a una determinata posizione del database.

  2. Si attiva quando si verifica un evento ed esegue le relative attività.

  3. Riceve un oggetto dati che contiene uno snapshot dei dati archiviati nel documento specificato.

Tipi di evento

Le funzioni ti consentono di gestire gli eventi del database a due livelli di specificità: puoi monitorare specificamente solo gli eventi di creazione, aggiornamento o eliminazione oppure puoi monitorare qualsiasi modifica di qualsiasi tipo a un percorso. Le funzioni Cloud Run supportano i seguenti tipi di eventi per il database in tempo reale:

Tipo di evento Trigger
providers/google.firebase.database/eventTypes/ref.write Attivato per qualsiasi evento di mutazione: quando i dati vengono creati, aggiornati o eliminati nel database in tempo reale.
providers/google.firebase.database/eventTypes/ref.create (valore predefinito) Viene attivato quando vengono creati nuovi dati nel database in tempo reale.
providers/google.firebase.database/eventTypes/ref.update Viene attivato quando i dati vengono aggiornati in Realtime Database.
providers/google.firebase.database/eventTypes/ref.delete Viene attivato quando i dati vengono eliminati dal Realtime Database.

Specifica del percorso e dell'istanza del database

Per controllare quando e dove deve essere attivata la funzione, devi specificare un percorso e, facoltativamente, un'istanza di database.

Percorso

Le specifiche del percorso corrispondono a tutte le scritture che toccano un percorso, incluse quelle che si verificano al di sotto. Se imposti il percorso della funzione su /foo/bar, viene associato agli eventi in entrambe le posizioni:

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

In entrambi i casi, Firebase interpreta che l'evento si verifica in /foo/bar e i dati dell'evento includono i dati vecchi e nuovi in /foo/bar. Se i dati sugli eventi potrebbero essere di grandi dimensioni, valuta la possibilità di utilizzare più funzioni in percorsi più profondi anziché una singola funzione vicino alla radice del database. Per ottenere le migliori prestazioni, richiedi solo i dati al livello più granulare possibile.

Puoi specificare un componente del percorso come carattere jolly racchiudendolo tra parentesi graffe. foo/{bar} corrisponde a qualsiasi elemento secondario di /foo. I valori di questi componenti del percorso con caratteri jolly sono disponibili nell'oggetto event.params della funzione. In questo esempio, il valore è disponibile come event.params.bar.

I percorsi con caratteri jolly possono corrispondere a più eventi da una singola scrittura. Un inserto di:

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

corrisponde al percorso /foo/{bar} due volte: una volta con "hello": "world" e di nuovo con "firebase": "functions".

Istanza

Quando utilizzi la console Google Cloud, devi specificare l'istanza del database.

Quando utilizzi Google Cloud CLI, l'istanza deve essere specificata come parte della stringa --trigger-resource.

Ad esempio, nella stringa --trigger-resource verranno utilizzati i seguenti elementi:

--trigger-resource projects/_/instances/DATABASE_INSTANCE/refs/PATH

Struttura dell'evento

Quando gestisci un evento di Realtime Database, l'oggetto data contiene due proprietà fornite in formato oggetto JSON:

  • data: uno snapshot dei dati acquisiti prima dell'evento che ha attivato la funzione.

  • delta: uno snapshot dei dati acquisiti dopo l'evento che ha attivato la funzione.

Esempio di codice

Node.js

/**
 * Background Function triggered by a change to a Firebase RTDB reference.
 *
 * @param {!Object} event The Cloud Functions event.
 * @param {!Object} context The Cloud Functions event context.
 */
exports.helloRTDB = (event, context) => {
  const triggerResource = context.resource;

  console.log(`Function triggered by change to: ${triggerResource}`);
  console.log(`Admin?: ${!!context.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

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

Vai


// 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: %w", 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;
    }
}

Ruby

require "functions_framework"

# Triggered by a change to a Firebase RTDB document.
FunctionsFramework.cloud_event "hello_rtdb" do |event|
  # Event-triggered Ruby functions receive a CloudEvents::Event::V1 object.
  # See https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event/V1.html
  # The Firebase event payload can be obtained from the `data` field.
  payload = event.data

  logger.info "Function triggered by change to: #{event.source}"
  logger.info "Admin?: #{payload.fetch 'admin', false}"
  logger.info "Delta: #{payload['delta']}"
end

PHP


use Google\CloudFunctions\CloudEvent;

function firebaseRTDB(CloudEvent $cloudevent)
{
    $log = fopen(getenv('LOGGER_OUTPUT') ?: 'php://stderr', 'wb');

    fwrite($log, 'Event: ' . $cloudevent->getId() . PHP_EOL);

    $data = $cloudevent->getData();
    $resource = $data['resource'] ?? '<null>';

    fwrite($log, 'Function triggered by change to: ' . $resource . PHP_EOL);

    $isAdmin = isset($data['auth']['admin']) && $data['auth']['admin'] == true;

    fwrite($log, 'Admin?: ' . var_export($isAdmin, true) . PHP_EOL);
    fwrite($log, 'Delta: ' . json_encode($data['delta'] ?? '') . PHP_EOL);
}

Eseguire il deployment della funzione

Il seguente comando gcloud esegue il deployment di una funzione che verrà attivata dagli eventi create nel percorso /messages/{pushId}/original:

gcloud functions deploy FUNCTION_NAME \
  --no-gen2 \
  --entry-point ENTRY_POINT \
  --trigger-event providers/google.firebase.database/eventTypes/ref.create \
  --trigger-resource projects/_/instances/DATABASE_INSTANCE/refs/messages/{pushId}/original \
  --runtime RUNTIME
Argomento Descrizione
FUNCTION_NAME Il nome registrato della funzione Cloud Run di cui stai eseguendo il deployment. Può essere il nome di una funzione nel codice sorgente o una stringa arbitraria. Se FUNCTION_NAME è una stringa arbitraria, devi includere il flag --entry-point.
--entry-point ENTRY_POINT Il nome di una funzione o di una classe nel codice sorgente. Facoltativo, a meno che non abbia utilizzato FUNCTION_NAME per specificare la funzione nel codice sorgente da eseguire durante il deployment. In questo caso, devi utilizzare --entry-point per fornire il nome della funzione eseguibile.
--trigger-event NAME Il nome del tipo di evento che la funzione vuole ricevere. In questo caso, sarà una delle seguenti: write, create, update o delete.
--trigger-resource NAME Il percorso completo del database a cui la funzione sarà in ascolto. Deve essere conforme al seguente formato: projects/_/instances/DATABASE_INSTANCE/refs/PATH.
--runtime RUNTIME Il nome del runtime in uso. Per un elenco completo, consulta il riferimento gcloud.