Realtime Database-Trigger (1. Generation)

Mit Cloud Functions können Sie Ereignisse in der Firebase Realtime Database verarbeiten, ohne Clientcode aktualisieren zu müssen. Cloud Functions ermöglicht die Ausführung von Realtime Database-Vorgängen mit vollen Administrator berechtigungen und stellt sicher, dass jede Änderung an Realtime Database einzeln verarbeitet wird. Sie können Firebase Realtime Database Änderungen über die DataSnapshot oder über das Admin SDK vornehmen.

Der typische Lebenszyklus einer Firebase Realtime Database Funktion sieht so aus:

  1. Sie wartet auf Änderungen an einem bestimmten Realtime Database Speicherort.
  2. Sie wird ausgelöst, wenn ein Ereignis eintritt, und führt dessen Aufgaben aus. Beispiele für Anwendungsfälle finden Sie unter Was kann ich mit Cloud Functions?
  3. Sie erhält ein Datenobjekt, das einen Snapshot der im angegebenen Dokument gespeicherten Daten enthält.

Eine Realtime Database Funktion auslösen

Erstellen Sie neue Funktionen für Realtime Database Ereignisse mit functions.database. Wenn Sie festlegen möchten, wann die Funktion ausgelöst wird, geben Sie einen der Ereignishandler und geben Sie den Realtime Database Pfad an, an dem nach Ereignissen gesucht werden soll.

Ereignishandler festlegen

Mit Cloud Functions können Sie Realtime Database Ereignisse 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 Functions unterstützt die folgenden Ereignishandler für Realtime Database:

  • onWrite(), das ausgelöst wird, wenn Daten in Realtime Database erstellt, aktualisiert oder gelöscht werden.
  • onCreate(), das ausgelöst wird, wenn neue Daten in Realtime Database erstellt werden.
  • onUpdate(), das ausgelöst wird, wenn Daten in Realtime Database aktualisiert werden .
  • onDelete(), das ausgelöst wird, wenn Daten aus Realtime Database gelöscht werden .

Instanz und Pfad angeben

Wenn Sie festlegen möchten, wann und wo Ihre Funktion ausgelöst werden soll, rufen Sie ref(path) auf, um einen Pfad anzugeben, und geben Sie optional mit instance('INSTANCE_NAME') eine Realtime Database Instanz an. Wenn Sie keine Instanz angeben, wird die Funktion für die Standard-Realtime Database Instanz für das Firebase-Projekt bereitgestellt. Beispiel:

  • Standard-Realtime Database Instanz: functions.database.ref('/foo/bar')
  • Instanz mit dem Namen „my-app-db-2“: functions.database.instance('my-app-db-2').ref('/foo/bar')

Diese Methoden weisen Ihre Funktion an, Schreibvorgänge an einem bestimmten Pfad in der Realtime Database Instanz zu verarbeiten. 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/bar auftritt, 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. ref('foo/{bar}') entspricht allen untergeordneten Elementen von /foo. Die Werte dieser Platzhalterpfadkomponenten sind innerhalb des EventContext.params Objekts Ihrer Funktion verfügbar. In diesem Beispiel ist der Wert als context.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 mit "hello": "world" und einmal mit "firebase": "functions".

Ereignisdaten verarbeiten

Beim Verarbeiten eines -Ereignisses ist das zurückgegebene Datenobjekt ein DataSnapshot.Realtime Database Für onWrite- oder onUpdate-Ereignisse ist der erste Parameter ein Change-Objekt, das zwei Snapshots enthält, die den Datenstatus vor und nach dem auslösenden Ereignis darstellen. Für onCreate- und onDelete-Ereignisse ist das zurückgegebene Datenobjekt ein Snapshot der erstellten oder gelöschten Daten.

In diesem Beispiel ruft die Funktion den Snapshot für den angegebenen Pfad ab, wandelt den String an dieser Stelle in Großbuchstaben um und schreibt diesen geänderten String in die Datenbank:

// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
    .onCreate((snapshot, context) => {
      // Grab the current value of what was written to the Realtime Database.
      const original = snapshot.val();
      functions.logger.log('Uppercasing', context.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 snapshot.ref.parent.child('uppercase').set(uppercase);
    });

Auf Informationen zur Nutzerauthentifizierung zugreifen

Über EventContext.auth und EventContext.authType, können Sie auf die Nutzerinformationen, einschließlich Berechtigungen, für den Nutzer zugreifen, der eine Funktion ausgelöst hat. Dies kann nützlich sein, um Sicherheitsregeln zu erzwingen und Ihrer Funktion zu ermöglichen, je nach Berechtigungsstufe des Nutzers unterschiedliche Vorgänge auszuführen:

const functions = require('firebase-functions/v1');
const admin = require('firebase-admin');

exports.simpleDbFunction = functions.database.ref('/path')
    .onCreate((snap, context) => {
      if (context.authType === 'ADMIN') {
        // do something
      } else if (context.authType === 'USER') {
        console.log(snap.val(), 'written by', context.auth.uid);
      }
    });

Außerdem können Sie Informationen zur Nutzerauthentifizierung verwenden, um einen Nutzer zu imitieren und Schreibvorgänge in seinem Namen auszuführen. Löschen Sie die App-Instanz wie unten gezeigt, um Probleme mit der Parallelität zu vermeiden:

exports.impersonateMakeUpperCase = functions.database.ref('/messages/{pushId}/original')
    .onCreate((snap, context) => {
      const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
      appOptions.databaseAuthVariableOverride = context.auth;
      const app = admin.initializeApp(appOptions, 'app');
      const uppercase = snap.val().toUpperCase();
      const ref = snap.ref.parent.child('uppercase');

      const deleteApp = () => app.delete().catch(() => null);

      return app.database().ref(ref).set(uppercase).then(res => {
        // Deleting the app is necessary for preventing concurrency leaks
        return deleteApp().then(() => res);
      }).catch(err => {
        return deleteApp().then(() => Promise.reject(err));
      });
    });

Vorherigen Wert lesen

Das Change Objekt hat eine before Eigenschaft, mit der Sie prüfen können, was Realtime Database vor dem Ereignis gespeichert wurde. Die before Eigenschaft gibt einen DataSnapshot zurück, bei dem sich alle Methoden (z. B. val() und exists()) auf den vorherigen Wert beziehen. Sie können den neuen Wert entweder mit dem ursprünglichen DataSnapshot oder mit der after Eigenschaft noch einmal lesen. Diese Eigenschaft für jede Change ist ein weiterer DataSnapshot, der den Status der Daten nach dem Ereignis darstellt.

Die before-Eigenschaft kann beispielsweise verwendet werden, um sicherzustellen, dass die Funktion Text nur dann in Großbuchstaben umwandelt, wenn er zum ersten Mal erstellt wird:

exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
    .onWrite((change, context) => {
      // Only edit data when it is first created.
      if (change.before.exists()) {
        return null;
      }
      // Exit when the data is deleted.
      if (!change.after.exists()) {
        return null;
      }
      // Grab the current value of what was written to the Realtime Database.
      const original = change.after.val();
      console.log('Uppercasing', context.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 change.after.ref.parent.child('uppercase').set(uppercase);
    });