Firebase Realtime Database-Trigger

Mit Cloud Run-Funktionen können Sie Ereignisse in der Firebase Realtime Database im selben Google Cloud-Projekt wie die Funktion verarbeiten. Cloud Run-Funktionen ermöglichen die Ausführung von Datenbankvorgängen mit vollen Administratorberechtigungen und stellen sicher, dass jede Änderung an der Datenbank einzeln verarbeitet wird. Sie können Änderungen an der Firebase Realtime Database über das Firebase Admin SDK vornehmen.

In einem typischen Lebenszyklus führt eine Firebase Realtime Database-Funktion folgende Vorgänge aus:

  1. Sie wartet auf Änderungen an einem bestimmten Datenbankspeicherort.

  2. Sie wird ausgelöst, wenn ein Ereignis eintritt, und führt dessen Aufgaben aus.

  3. Sie erhält ein Datenobjekt, das einen Snapshot der im angegebenen Dokument gespeicherten Daten enthält.

Ereignistypen

Mit Cloud Functions können Sie Datenbankereignisse mit zwei Spezifitätsgraden verarbeiten: Sie können gezielt nur nach Erstellungs-, Aktualisierungs- oder Löschereignissen oder nach beliebigen Änderungen jeglicher Art an einem Pfad Ausschau halten. Cloud Run-Funktionen unterstützen für die Realtime Database die folgenden Ereignistypen:

Ereignistyp Trigger
providers/google.firebase.database/eventTypes/ref.write Wird bei jedem Mutationsereignis ausgelöst: wenn Daten in der Echtzeitdatenbank erstellt, aktualisiert oder gelöscht werden
providers/google.firebase.database/eventTypes/ref.create (Standard) Wird ausgelöst, wenn neue Daten in der Echtzeitdatenbank erstellt werden
providers/google.firebase.database/eventTypes/ref.update Wird ausgelöst, wenn Daten in der Echtzeitdatenbank aktualisiert werden
providers/google.firebase.database/eventTypes/ref.delete Wird ausgelöst, wenn Daten aus der Echtzeitdatenbank gelöscht werden

Datenbankpfad und -instanz angeben

Wenn Sie festlegen möchten, wann und wo Ihre Funktion ausgelöst werden soll, müssen Sie einen Pfad – und optional eine Datenbankinstanz – angeben.

Pfad

Die Pfadspezifikationen gleichen alle Schreibvorgänge ab, die einen Pfad tangieren, einschließlich Schreibvorgängen, die an einem beliebigen untergeordneten Punkt auftreten. Wenn Sie als Pfad für Ihre Funktion /foo/bar festlegen, werden die Ereignisse an diesen beiden Speicherorten abgeglichen:

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

In beiden Fällen geht Firebase davon aus, dass das Ereignis unter /foo/barauftritt, und die Ereignisdaten umfassen sowohl die alten als auch die neuen Daten unter /foo/bar. Wenn die Ereignisdaten sehr umfangreich sein können, sollten Sie erwägen, mehrere Funktionen auf tieferen Pfadebenen anstatt lediglich einer Funktion im Bereich des Datenbankstamms zu verwenden. Für optimale Leistung sollten Sie Daten nur auf der untersten Ebene anfordern.

Sie können eine Pfadkomponente als Platzhalter angeben, indem Sie sie in geschweifte Klammern setzen. foo/{bar} entspricht allen untergeordneten Elementen von /foo. Die Werte dieser Platzhalterpfadkomponenten sind innerhalb des event.params-Objekts Ihrer Funktion verfügbar. In diesem Beispiel ist der Wert als event.params.bar verfügbar.

Pfade mit Platzhaltern können mit mehreren Ereignissen aus einem einzigen Schreibvorgang übereinstimmen. Die Verwendung von

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

ergibt zwei Übereinstimmungen mit dem Pfad /foo/{bar}: einmal "hello": "world" und einmal "firebase": "functions".

Instanz

Bei Verwendung der Google Cloud Console muss die Datenbankinstanz angegeben werden.

Bei Verwendung des Google Cloud CLI muss die Instanz als Teil des --trigger-resource-Strings angegeben werden.

In diesem Fall wird beispielsweise Folgendes in Ihrem String --trigger-resource verwendet:

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

Ereignisstruktur

Bei der Verarbeitung eines Realtime Database-Ereignisses enthält das Objekt data zwei Attribute, die im JSON-Objektformat bereitgestellt werden:

  • data: ein Snapshot der Daten vor dem Ereignis, das die Funktion ausgelöst hat.

  • delta: ein Snapshot der Daten nach dem Ereignis, das die Funktion ausgelöst hat.

Codebeispiel

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"]))

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

Funktion bereitstellen

Mit dem folgenden gcloud-Befehl wird eine Funktion bereitgestellt, die durch create-Ereignisse unter dem Pfad /messages/{pushId}/original ausgelöst wird:

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
Argument Beschreibung
FUNCTION_NAME Der registrierte Name der Cloud Run Functions, die Sie bereitstellen. Dies kann entweder der Name einer Funktion in Ihrem Quellcode oder ein beliebiger String sein. Wenn FUNCTION_NAME ein beliebiger String ist, müssen Sie das Flag --entry-point einfügen.
--entry-point ENTRY_POINT Der Name einer Funktion oder Klasse in Ihrem Quellcode. Optional, es sei denn, Sie haben FUNCTION_NAME nicht verwendet, um die Funktion in Ihrem Quellcode anzugeben, die während der Bereitstellung ausgeführt werden soll. In diesem Fall müssen Sie mit --entry-point den Namen der ausführbaren Funktion angeben.
--trigger-event NAME Der Name des Ereignistyps, den die Funktion erhalten möchte. In diesem Fall ist es einer der folgenden Typen: write, create, update oder delete.
--trigger-resource NAME Der voll qualifizierte Datenbankpfad, den die Funktion überwacht. Er sollte diesem Format entsprechen: projects/_/instances/DATABASE_INSTANCE/refs/PATH.
--runtime RUNTIME Der Name der Laufzeit, die Sie verwenden. Eine vollständige Liste finden Sie in der gcloud-Referenz.