Cloud Firestore-Trigger


Mit Cloud Functions können Sie Ereignisse in Cloud Firestore verarbeiten, ohne den Clientcode aktualisieren zu müssen. Sie können Cloud Firestore-Änderungen über die Dokument-Snapshot-Schnittstelle oder über das Admin SDK vornehmen.

In einem typischen Lebenszyklus führt eine Cloud Firestore-Funktion Folgendes aus:

  1. Wartet auf Änderungen an einem bestimmten Dokument.
  2. Wird ausgelöst, wenn ein Ereignis eintritt, und führt seine Aufgaben aus.
  3. Empfängt ein Datenobjekt, das eine Momentaufnahme der im angegebenen Dokument gespeicherten Daten enthält. Bei Schreib- oder Aktualisierungsereignissen enthält das Datenobjekt zwei Snapshots, die den Datenzustand vor und nach dem auslösenden Ereignis darstellen.

Die Entfernung zwischen dem Standort der Firestore-Instanz und dem Standort der Funktion kann zu erheblicher Netzwerklatenz führen. Um die Leistung zu optimieren, sollten Sie ggf. den Speicherort der Funktion angeben.

Auslöser der Cloud Firestore-Funktion

Das Cloud Functions for Firebase SDK exportiert ein functions.firestore -Objekt, mit dem Sie Handler erstellen können, die an bestimmte Cloud Firestore-Ereignisse gebunden sind.

Ereignistyp Auslösen
onCreate Wird ausgelöst, wenn ein Dokument zum ersten Mal beschrieben wird.
onUpdate Wird ausgelöst, wenn ein Dokument bereits vorhanden ist und ein Wert geändert wurde.
onDelete Wird ausgelöst, wenn ein Dokument mit Daten gelöscht wird.
onWrite Wird ausgelöst, wenn onCreate , onUpdate oder onDelete ausgelöst wird.

Wenn Sie noch kein Projekt für Cloud Functions for Firebase aktiviert haben, lesen Sie „Erste Schritte: Schreiben und Bereitstellen Ihrer ersten Funktionen“, um Ihr Cloud Functions for Firebase-Projekt zu konfigurieren und einzurichten.

Schreiben von durch Cloud Firestore ausgelösten Funktionen

Definieren Sie einen Funktionsauslöser

Um einen Cloud Firestore-Trigger zu definieren, geben Sie einen Dokumentpfad und einen Ereignistyp an:

Node.js

const functions = require('firebase-functions');

exports.myFunction = functions.firestore
  .document('my-collection/{docId}')
  .onWrite((change, context) => { /* ... */ });

Dokumentpfade können entweder auf ein bestimmtes Dokument oder auf ein Platzhaltermuster verweisen.

Geben Sie ein einzelnes Dokument an

Wenn Sie bei einer Änderung an einem bestimmten Dokument ein Ereignis auslösen möchten, können Sie die folgende Funktion verwenden.

Node.js

// Listen for any change on document `marie` in collection `users`
exports.myFunctionName = functions.firestore
    .document('users/marie').onWrite((change, context) => {
      // ... Your code here
    });

Geben Sie eine Gruppe von Dokumenten mit Platzhaltern an

Wenn Sie einen Auslöser an eine Gruppe von Dokumenten anhängen möchten, beispielsweise an ein beliebiges Dokument in einer bestimmten Sammlung, verwenden Sie anstelle der Dokument-ID einen {wildcard} :

Node.js

// Listen for changes in all documents in the 'users' collection
exports.useWildcard = functions.firestore
    .document('users/{userId}')
    .onWrite((change, context) => {
      // If we set `/users/marie` to {name: "Marie"} then
      // context.params.userId == "marie"
      // ... and ...
      // change.after.data() == {name: "Marie"}
    });

Wenn in diesem Beispiel ein Feld in einem beliebigen Dokument in „ users geändert wird, entspricht es einem Platzhalter namens userId .

Wenn ein Dokument in users über Untersammlungen verfügt und ein Feld in einem dieser Untersammlungsdokumente geändert wird, wird der Platzhalter userId nicht ausgelöst.

Platzhalterübereinstimmungen werden aus dem Dokumentpfad extrahiert und in context.params gespeichert. Sie können beliebig viele Platzhalter definieren, um explizite Sammlungs- oder Dokument-IDs zu ersetzen, zum Beispiel:

Node.js

// Listen for changes in all documents in the 'users' collection and all subcollections
exports.useMultipleWildcards = functions.firestore
    .document('users/{userId}/{messageCollectionId}/{messageId}')
    .onWrite((change, context) => {
      // If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
      // context.params.userId == "marie";
      // context.params.messageCollectionId == "incoming_messages";
      // context.params.messageId == "134";
      // ... and ...
      // change.after.data() == {body: "Hello"}
    });

Ereignisauslöser

Lösen Sie eine Funktion aus, wenn ein neues Dokument erstellt wird

Sie können eine Funktion jedes Mal auslösen, wenn ein neues Dokument in einer Sammlung erstellt wird, indem Sie einen onCreate() Handler mit einem Platzhalter verwenden. Diese Beispielfunktion ruft createUser jedes Mal auf, wenn ein neues Benutzerprofil hinzugefügt wird:

Node.js

exports.createUser = functions.firestore
    .document('users/{userId}')
    .onCreate((snap, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = snap.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

Lösen Sie eine Funktion aus, wenn ein Dokument aktualisiert wird

Sie können auch eine Funktion zum Auslösen auslösen, wenn ein Dokument aktualisiert wird, indem Sie die Funktion onUpdate() mit einem Platzhalter verwenden. Diese Beispielfunktion ruft updateUser auf, wenn ein Benutzer sein Profil ändert:

Node.js

exports.updateUser = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

Lösen Sie eine Funktion aus, wenn ein Dokument gelöscht wird

Sie können eine Funktion auch auslösen, wenn ein Dokument gelöscht wird, indem Sie die Funktion onDelete() mit einem Platzhalter verwenden. Diese Beispielfunktion ruft deleteUser auf, wenn ein Benutzer sein Benutzerprofil löscht:

Node.js

exports.deleteUser = functions.firestore
    .document('users/{userID}')
    .onDelete((snap, context) => {
      // Get an object representing the document prior to deletion
      // e.g. {'name': 'Marie', 'age': 66}
      const deletedValue = snap.data();

      // perform desired operations ...
    });

Lösen Sie eine Funktion für alle Änderungen an einem Dokument aus

Wenn Ihnen die Art des ausgelösten Ereignisses egal ist, können Sie mithilfe der Funktion onWrite() mit einem Platzhalter auf alle Änderungen in einem Cloud Firestore-Dokument warten. Diese Beispielfunktion ruft modifyUser auf, wenn ein Benutzer erstellt, aktualisiert oder gelöscht wird:

Node.js

exports.modifyUser = functions.firestore
    .document('users/{userID}')
    .onWrite((change, context) => {
      // Get an object with the current document value.
      // If the document does not exist, it has been deleted.
      const document = change.after.exists ? change.after.data() : null;

      // Get an object with the previous document value (for update or delete)
      const oldDocument = change.before.data();

      // perform desired operations ...
    });

Daten lesen und schreiben

Wenn eine Funktion ausgelöst wird, stellt sie eine Momentaufnahme der mit dem Ereignis verbundenen Daten bereit. Sie können diesen Snapshot verwenden, um aus dem Dokument zu lesen oder in dieses zu schreiben, das das Ereignis ausgelöst hat, oder das Firebase Admin SDK verwenden, um auf andere Teile Ihrer Datenbank zuzugreifen.

Ereignisdaten

Daten lesen

Wenn eine Funktion ausgelöst wird, möchten Sie möglicherweise Daten aus einem aktualisierten Dokument abrufen oder die Daten vor der Aktualisierung abrufen. Sie können die vorherigen Daten abrufen, indem Sie change.before.data() verwenden, das den Dokument-Snapshot vor der Aktualisierung enthält. In ähnlicher Weise enthält change.after.data() den Dokument-Snapshot-Status nach der Aktualisierung.

Node.js

exports.updateUser2 = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the current document
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();
    });

Sie können wie bei jedem anderen Objekt auf Eigenschaften zugreifen. Alternativ können Sie die get Funktion verwenden, um auf bestimmte Felder zuzugreifen:

Node.js

// Fetch data using standard accessors
const age = snap.data().age;
const name = snap.data()['name'];

// Fetch data using built in accessor
const experience = snap.get('experience');

Daten schreiben

Jeder Funktionsaufruf ist einem bestimmten Dokument in Ihrer Cloud Firestore-Datenbank zugeordnet. Sie können auf dieses Dokument als DocumentReference in der ref Eigenschaft des an Ihre Funktion zurückgegebenen Snapshots zugreifen.

Diese DocumentReference stammt aus dem Cloud Firestore Node.js SDK und enthält Methoden wie update() , set() und remove() , sodass Sie das Dokument, das die Funktion ausgelöst hat, problemlos ändern können.

Node.js

// Listen for updates to any `user` document.
exports.countNameChanges = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Retrieve the current and previous value
      const data = change.after.data();
      const previousData = change.before.data();

      // We'll only update if the name has changed.
      // This is crucial to prevent infinite loops.
      if (data.name == previousData.name) {
        return null;
      }

      // Retrieve the current count of name changes
      let count = data.name_change_count;
      if (!count) {
        count = 0;
      }

      // Then return a promise of a set operation to update the count
      return change.after.ref.set({
        name_change_count: count + 1
      }, {merge: true});
    });

Daten außerhalb des Triggerereignisses

Cloud Functions werden in einer vertrauenswürdigen Umgebung ausgeführt, was bedeutet, dass sie als Dienstkonto für Ihr Projekt autorisiert sind. Sie können Lese- und Schreibvorgänge mit dem Firebase Admin SDK durchführen:

Node.js

const admin = require('firebase-admin');
admin.initializeApp();

const db = admin.firestore();

exports.writeToFirestore = functions.firestore
  .document('some/doc')
  .onWrite((change, context) => {
    db.doc('some/otherdoc').set({ ... });
  });

Einschränkungen

Beachten Sie die folgenden Einschränkungen für Cloud Firestore-Trigger für Cloud Functions:

  • Die Bestellung ist nicht garantiert. Schnelle Änderungen können Funktionsaufrufe in einer unerwarteten Reihenfolge auslösen.
  • Ereignisse werden mindestens einmal übermittelt, ein einzelnes Ereignis kann jedoch zu mehreren Funktionsaufrufen führen. Vermeiden Sie die Abhängigkeit von der genau-einmaligen Mechanik und schreiben Sie idempotente Funktionen .
  • Cloud Firestore im Datastore-Modus erfordert Cloud Functions (2. Generation). Cloud Functions (1. Generation) unterstützt den Datastore-Modus nicht.
  • Cloud Functions (1. Generation) funktioniert nur mit der Datenbank „(Standard)“ und unterstützt keine benannten Cloud Firestore-Datenbanken. Bitte verwenden Sie Cloud Functions (2. Generation), um Ereignisse für benannte Datenbanken zu konfigurieren.
  • Ein Trigger ist einer einzelnen Datenbank zugeordnet. Sie können keinen Trigger erstellen, der mit mehreren Datenbanken übereinstimmt.
  • Durch das Löschen einer Datenbank werden nicht automatisch alle Trigger für diese Datenbank gelöscht. Der Auslöser liefert keine Ereignisse mehr, bleibt jedoch bestehen, bis Sie den Auslöser löschen .
  • Wenn ein übereinstimmendes Ereignis die maximale Anforderungsgröße überschreitet, wird das Ereignis möglicherweise nicht an Cloud Functions (1. Generation) übermittelt.
    • Ereignisse, die aufgrund der Anfragegröße nicht zugestellt werden, werden in Plattformprotokollen protokolliert und auf die Protokollnutzung für das Projekt angerechnet.
    • Sie finden diese Protokolle im Protokoll-Explorer mit der Meldung „Ereignis kann nicht an die Cloud-Funktion übermittelt werden, da die Größe den Grenzwert für die 1. Generation überschreitet …“ mit error . Den Funktionsnamen finden Sie im Feld functionName . Wenn sich das Feld receiveTimestamp noch innerhalb einer Stunde befindet, können Sie auf den tatsächlichen Ereignisinhalt schließen, indem Sie das betreffende Dokument mit einem Schnappschuss vor und nach dem Zeitstempel lesen.
    • Um eine solche Trittfrequenz zu vermeiden, können Sie:
      • Migration und Upgrade auf Cloud Functions (2. Generation)
      • Verkleinern Sie das Dokument
      • Löschen Sie die betreffenden Cloud-Funktionen
    • Sie können die Protokollierung selbst mithilfe von Ausschlüssen deaktivieren. Beachten Sie jedoch, dass die betreffenden Ereignisse weiterhin nicht übermittelt werden.