Catch up on everthing we announced at this year's Firebase Summit. Learn more

Datenbank-Trigger

Mit Cloud Functions können Sie Ereignisse in der Firebase Realtime Database verarbeiten, ohne den Clientcode aktualisieren zu müssen. Mit Cloud Functions können Sie Echtzeitdatenbankvorgänge mit vollen Administratorrechten ausführen und stellen sicher, dass jede Änderung an der Echtzeitdatenbank einzeln verarbeitet wird. Sie können über die Datenbank Firebase Realtime Änderungen vornehmen DataSnapshot oder über das Admin SDK .

In einem typischen Lebenszyklus führt eine Firebase Realtime Database-Funktion Folgendes aus:

  1. Wartet auf Änderungen an einem bestimmten Ort der Echtzeitdatenbank.
  2. Trigger , wenn ein Ereignis auftritt , und führt seine Aufgaben (siehe Was kann ich mit Cloud - Funktionen tun? Beispiele für Anwendungsfälle).
  3. Empfängt ein Datenobjekt, das eine Momentaufnahme der im angegebenen Dokument gespeicherten Daten enthält.

Auslösen einer Echtzeit-Datenbankfunktion

Erstellen Sie neue Funktionen für die Echtzeit - Datenbank - Ereignisse mit functions.database . Um zu steuern, wann die Funktion ausgelöst wird, geben Sie einen der Ereignishandler an und geben Sie den Echtzeitdatenbankpfad an, in dem sie auf Ereignisse lauscht.

Legen Sie den Ereignishandler fest

Mit Funktionen können Sie Echtzeit-Datenbankereignisse auf zwei Spezifitätsebenen verarbeiten; Sie können gezielt nur auf Erstellungs-, Aktualisierungs- oder Löschereignisse oder auf jede beliebige Änderung eines Pfads lauschen. Cloud Functions unterstützt diese Ereignishandler für Realtime Database:

  • onWrite() , die ausgelöst wird, wenn Daten erstellt wird, aktualisiert oder in Realtime - Datenbank gelöscht.
  • onCreate() , der Auslöser , wenn neue Daten in Echtzeit - Datenbank erstellt wird.
  • onUpdate() , die ausgelöst wird, wenn Daten in Echtzeit - Datenbank aktualisiert wird.
  • onDelete() , die ausgelöst wird, wenn Daten von Realtime - Datenbank gelöscht wird.

Instanz und Pfad angeben

Um die Kontrolle , wann und wo Ihre Funktion sollte auslösen, ruft ref(path) einen Pfad angeben, und optional eine Echtzeit - Datenbankinstanz mit angeben instance('INSTANCE_NAME') . Wenn Sie keine Instanz angeben, wird die Funktion in der standardmäßigen Echtzeitdatenbankinstanz für das Firebase-Projekt bereitgestellt. Beispiel:

  • Standard Echtzeit - Datenbankinstanz: 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 innerhalb der Echtzeitdatenbankinstanz zu verarbeiten. Pfadangaben entsprechen alle Schreibvorgänge , die einen Pfad, einschließlich schreibt berühren , die überall darunter passieren. Wenn Sie den Pfad für Ihre Funktion als Set /foo/bar , passt es Ereignisse an diesen beiden Standorten:

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

In jedem Fall Firebase interpretiert , dass das Ereignis tritt bei /foo/bar , und die Ereignisdaten enthalten die alten und neue Daten auf /foo/bar . Wenn die Ereignisdaten groß sein könnten, sollten Sie in Erwägung ziehen, mehrere Funktionen in tieferen Pfaden anstelle einer einzelnen Funktion in der Nähe des Stamms Ihrer Datenbank zu verwenden. Um die beste Leistung zu erzielen, fordern Sie nur Daten auf der tiefstmöglichen Ebene an.

Sie können eine Pfadkomponente als Platzhalter angeben, indem Sie sie mit geschweiften Klammern umgeben; ref('foo/{bar}') passt auf jedes Kind /foo . Die Werte dieser Platzhalter Pfadkomponenten sind im Rahmen der verfügbaren EventContext.params Objekt Ihrer Funktion. In diesem Beispiel ist der Wert als verfügbar context.params.bar .

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

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

entspricht den Pfad "/foo/{bar}" zweimal: einmal mit "hello": "world" und wieder mit "firebase": "functions" .

Ereignisdaten verarbeiten

Wenn eine Realtime - Datenbank Ereignisverarbeitung zurückgegeben das Datenobjekt ist ein DataSnapshot . Für onWrite oder onUpdate Ereignisse, ist der erste Parameter ein Change , das zwei Speicher enthält, der den Datenzustand vor und nach dem auslösenden Ereignis darstellen. Für onCreate und onDelete Ereignisse, kehrte das Datenobjekt ist eine Momentaufnahme der Daten erstellt oder gelöscht.

In diesem Beispiel ruft die Funktion die Momentaufnahme für den angegebenen Pfad als snap wandelt die Zeichenfolge an dieser Stelle in Großbuchstaben, und schreibt diese Zeichenfolge in die Datenbank geändert:

// 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);
    });

Zugriff auf Benutzerauthentifizierungsinformationen

Von EventContext.auth und EventContext.authType , können Sie die Benutzerinformationen, einschließlich der Berechtigungen zugreifen, für den Benutzer, der eine Funktion ausgelöst. Dies kann nützlich sein, um Sicherheitsregeln durchzusetzen, sodass Ihre Funktion je nach Berechtigungsstufe des Benutzers verschiedene Vorgänge ausführen kann:

const functions = require('firebase-functions');
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 Benutzerauthentifizierungsinformationen nutzen, um die Identität eines Benutzers anzunehmen und Schreibvorgänge im Namen des Benutzers auszuführen. Stellen Sie sicher, dass Sie die App-Instanz wie unten gezeigt löschen, um Parallelitätsprobleme 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));
      });
    });

Lesen des vorherigen Wertes

Das Change Objekt verfügt über eine before Eigenschaft, mit dem Sie überprüfen , was zu Realtime - Datenbank vor dem Ereignis gespeichert wurde. Die before Eigenschaft gibt eine DataSnapshot wo alle Methoden (zB val() und exists() ) auf den vorherigen Wert beziehen. Sie können wieder den neuen Wert lesen , indem entweder das Original mit DataSnapshot oder das Lesen after Eigentum. Diese Eigenschaft auf jedem Change ist ein weiterer DataSnapshot den Zustand der Daten , welche nach dem Ereignis passiert ist .

Zum Beispiel ist die before kann Eigenschaft verwendet werden , um sicherzustellen , dass nur die Funktion uppercases Text , wenn es 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);
    });