Mit Cloud Functions können Sie Ereignisse in der Firebase-Echtzeitdatenbank verarbeiten, ohne den Clientcode aktualisieren zu müssen. Mit Cloud Functions können Sie Realtime Database-Operationen mit vollen Administratorrechten ausführen und sicherstellen, dass jede Änderung an Realtime Database einzeln verarbeitet wird. Sie können Änderungen an der Firebase Realtime Database über DataSnapshot
oder über das Admin SDK vornehmen.
In einem typischen Lebenszyklus führt eine Firebase Realtime Database-Funktion Folgendes aus:
- Wartet auf Änderungen an einem bestimmten Speicherort der Echtzeitdatenbank.
- Löst aus, wenn ein Ereignis eintritt, und führt seine Aufgaben aus (Beispiele für Anwendungsfälle finden Sie unter Was kann ich mit Cloud Functions tun? ).
- Empfängt ein Datenobjekt, das eine Momentaufnahme der im angegebenen Dokument gespeicherten Daten enthält.
Auslösen einer Echtzeit-Datenbankfunktion
Erstellen Sie mit functions.database
neue Funktionen für Echtzeitdatenbankereignisse. Um zu steuern, wann die Funktion ausgelöst wird, geben Sie einen der Ereignishandler und den Pfad der Echtzeitdatenbank an, in dem sie auf Ereignisse lauschen soll.
Legen Sie den Ereignishandler fest
Mit Funktionen können Sie Realtime Database-Ereignisse auf zwei Spezifitätsebenen verarbeiten; Sie können speziell nur auf Erstellungs-, Aktualisierungs- oder Löschereignisse lauschen, oder Sie können auf jede Art von Änderung an einem Pfad horchen. Cloud Functions unterstützt diese Event-Handler für Realtime Database:
-
onWrite()
, das ausgelöst wird, wenn Daten in der Echtzeitdatenbank erstellt, aktualisiert oder gelöscht werden. -
onCreate()
, das ausgelöst wird, wenn neue Daten in der Echtzeitdatenbank erstellt werden. -
onUpdate()
, das ausgelöst wird, wenn Daten in der Echtzeitdatenbank aktualisiert werden. -
onDelete()
, das ausgelöst wird, wenn Daten aus der Realtime Database gelöscht werden.
Geben Sie die Instanz und den Pfad an
Um zu steuern, wann und wo Ihre Funktion ausgelöst werden soll, rufen Sie ref(path)
auf, um einen Pfad anzugeben, und geben Sie optional eine Realtime Database-Instanz mit instance('INSTANCE_NAME')
an. Wenn Sie keine Instanz angeben, wird die Funktion in der Standardinstanz der Echtzeitdatenbank für das Firebase-Projekt bereitgestellt. Beispiel:
- Standardinstanz der Echtzeitdatenbank:
functions.database.ref('/foo/bar')
- Instanz namens „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 Realtime Database-Instanz zu verarbeiten. Pfadspezifikationen stimmen mit allen Schreibvorgängen überein, die einen Pfad berühren, einschließlich Schreibvorgängen, die irgendwo darunter stattfinden. Wenn Sie den Pfad für Ihre Funktion als /foo/bar
festlegen, stimmt er mit Ereignissen an diesen beiden Orten überein:
/foo/bar
/foo/bar/baz/really/deep/path
In beiden Fällen interpretiert Firebase, dass das Ereignis unter /foo/bar
auftritt und die Ereignisdaten die alten und neuen Daten unter /foo/bar
enthalten. Wenn die Ereignisdaten möglicherweise umfangreich sind, sollten Sie erwägen, mehrere Funktionen in tieferen Pfaden anstelle einer einzelnen Funktion in der Nähe des Stammverzeichnisses Ihrer Datenbank zu verwenden. Fordern Sie für die beste Leistung 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}')
stimmt mit jedem untergeordneten Element von /foo
überein. Die Werte dieser Wildcard-Pfadkomponenten sind im EventContext.params
Objekt 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. Eine Einlage von
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
stimmt zweimal mit dem Pfad "/foo/{bar}"
überein: einmal mit "hello": "world"
und erneut mit "firebase": "functions"
.
Ereignisdaten verarbeiten
Bei der Behandlung eines Realtime Database-Ereignisses ist das zurückgegebene Datenobjekt ein DataSnapshot
. Bei onWrite
oder onUpdate
Ereignissen ist der erste Parameter ein Change
Objekt, das zwei Snapshots enthält, die den Datenstatus vor und nach dem auslösenden Ereignis darstellen. Bei onCreate
und onDelete
Ereignissen ist das zurückgegebene Datenobjekt eine Momentaufnahme der erstellten oder gelöschten Daten.
In diesem Beispiel ruft die Funktion den Snapshot für den angegebenen Pfad ab, konvertiert die Zeichenfolge an dieser Stelle in Großbuchstaben und schreibt diese geänderte Zeichenfolge 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); });
Zugriff auf Benutzerauthentifizierungsinformationen
Über EventContext.auth
und EventContext.authType
können Sie auf die Benutzerinformationen, einschließlich Berechtigungen, für den Benutzer zugreifen, der eine Funktion ausgelöst hat. 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 sich als Benutzer auszugeben 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 Werts
Das Change
Objekt hat eine before
Eigenschaft, mit der Sie überprüfen können, was vor dem Ereignis in der Realtime Database gespeichert wurde. Die before
Eigenschaft gibt einen DataSnapshot
zurück, in dem alle Methoden (z. B. val()
und exists()
) auf den vorherigen Wert verweisen. Sie können den neuen Wert erneut lesen, indem Sie entweder den ursprünglichen DataSnapshot
verwenden oder die after
Eigenschaft lesen. Diese Eigenschaft bei jeder Change
ist ein weiterer DataSnapshot
der den Status der Daten nach dem Eintreten des Ereignisses darstellt.
Beispielsweise kann die Eigenschaft before
verwendet werden, um sicherzustellen, dass die Funktion Text nur in Großbuchstaben schreibt, wenn sie 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);
});