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 Realtime Database-Vorgänge mit vollen Administratorberechtigungen ausführen und sicherstellen, dass jede Änderung an Realtime Database einzeln verarbeitet wird. Sie können Firebase Realtime Database-Änderungen über die DataSnapshot oder das Admin SDK vornehmen.
Der typische Lebenszyklus einer Firebase Realtime Database-Funktion sieht so aus:
- Sie wartet auf Änderungen an einem bestimmten Realtime Database-Speicherort.
- Wird ausgelöst, wenn ein Ereignis auftritt, und führt seine Aufgaben aus (siehe Was kann ich mit Cloud Functions tun?). Beispiele für Anwendungsfälle finden Sie unter
- Empfängt ein Datenobjekt, das einen Snapshot der im angegebenen Dokument gespeicherten Daten enthält.
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 Event-Handler und den Realtime Database-Pfad an, auf dem auf Ereignisse gewartet wird.
Ereignis-Handler festlegen
Mit Funktionen können Sie Realtime Database-Ereignisse auf zwei Ebenen verarbeiten. Sie können nur auf Erstellungs-, Aktualisierungs- oder Löschereignisse oder auf jede Art von Änderung an einem Pfad warten. Cloud Functions unterstützt diese Event-Handler für Realtime Database:
onWrite(), das ausgelöst wird, wenn Daten in Realtime Database erstellt, aktualisiert oder gelöscht werden.onCreate(), der ausgelöst wird, wenn neue Daten in Realtime Database erstellt werden.onUpdate(), das ausgelöst wird, wenn Daten in Realtime Database aktualisiert werden .onDelete(), der 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. Optional können Sie mit instance('INSTANCE_NAME') eine Realtime Database-Instanz angeben. Wenn Sie keine Instanz angeben, wird die Funktion in der Standardinstanz Realtime Database 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 in einem bestimmten Pfad innerhalb der Realtime Database-Instanz zu verarbeiten. Pfadspezifikationen stimmen mit allen Schreibvorgängen überein, die einen Pfad betreffen, einschließlich Schreibvorgängen, die an einer beliebigen Stelle darunter erfolgen. Wenn Sie den Pfad für Ihre Funktion auf /foo/bar festlegen, werden Ereignisse an beiden Standorten abgeglichen:
/foo/bar
/foo/bar/baz/really/deep/path
In beiden Fällen interpretiert Firebase, dass das Ereignis um /foo/bar auftritt, und die Ereignisdaten enthalten die alten und neuen Daten um /foo/bar. Wenn die Ereignisdaten groß sein könnten, sollten Sie mehrere Funktionen in tieferen Pfaden anstelle einer einzelnen Funktion in der Nähe des Stammverzeichnisses Ihrer Datenbank 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 einem beliebigen untergeordneten Element von /foo. Die Werte dieser Platzhalterpfadkomponenten sind im Objekt EventContext.params 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 Einfügung von
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
stimmt zweimal mit dem Pfad "/foo/{bar}" überein: einmal mit "hello": "world" und einmal mit "firebase": "functions".
Ereignisdaten verarbeiten
Bei der Verarbeitung 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 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 den 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 durchzusetzen, sodass Ihre Funktion je nach Berechtigungsstufe des Nutzers unterschiedliche Vorgänge ausführen kann:
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 Nutzerauthentifizierungsinformationen verwenden, um sich als Nutzer auszugeben und Schreibvorgänge im Namen des Nutzers auszuführen. Löschen Sie die App-Instanz wie unten gezeigt, um Nebenläufigkeitsprobleme 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 das Attribut before, mit dem Sie prüfen können, was vor dem Ereignis in Realtime Database gespeichert wurde. Das Attribut before 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 noch einmal lesen, indem Sie entweder den ursprünglichen DataSnapshot verwenden oder das Attribut after lesen. Dieses Attribut für ein beliebiges Change ist ein weiteres DataSnapshot, das den Status der Daten nach dem Ereignis darstellt.
Mit dem Attribut before können Sie beispielsweise dafür sorgen, 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);
});