Cloud Firestore mit Cloud Functions erweitern

Mit Cloud Functions können Sie Node.js-Code bereitstellen, um Ereignisse zu verarbeiten, die durch Änderungen in Ihrer Cloud Firestore-Datenbank ausgelöst werden. Auf diese Weise können Sie problemlos serverseitige Funktionen zu Ihrer App hinzufügen, ohne Ihre eigenen Server zu betreiben.

Beispiele für Anwendungsfälle finden Sie unter Was kann ich tun mit Cloud Functions? oder Functions Samples im GitHub-Repository.

Cloud Firestore Funktionstrigger

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 Trigger
onCreate Wird ausgelöst, wenn ein Dokument zum ersten Mal beschrieben wird.
onUpdate Wird ausgelöst, wenn ein Dokument bereits existiert und sich ein Wert geändert hat.
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: Erste Funktionen schreiben und bereitstellen um Ihr Cloud Functions for Firebase-Projekt zu konfigurieren und einzurichten.

Cloud Firestore-ausgelöste Funktionen schreiben

Funktions-Trigger definieren

Geben Sie zum Definieren eines Cloud Firestore-Triggers 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 ein Platzhaltermuster verweisen.

Einzelnes Dokument angeben

Wenn Sie ein Ereignis für beliebige Änderungen an einem bestimmten Dokument 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
    });

Mithilfe von Platzhaltern eine Gruppe von Dokumenten angeben

Wenn Sie einen Trigger an eine Gruppe von Dokumenten anhängen möchten, z. B. an ein Dokument in einer bestimmten Sammlung, verwenden Sie {wildcard} anstelle der Dokument-ID:

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 Dokument im Verzeichnis users geändert wird, entspricht es einem Platzhalter namens userId.

Wenn ein Dokument in users untergeordnete Sammlungen enthält und ein Feld in einem Dokument dieser Sammlungen 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 festlegen, um explizite Sammlungs- oder Dokument-IDs zu ersetzen. 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"}
    });

Ereignis-Trigger

Beim Erstellen eines neuen Dokuments eine Funktion auslösen

Sie können auch festlegen, dass eine Funktion ausgelöst wird, wenn ein neues Dokument in einer Sammlung erstellt wird, indem Sie einen onCreate()-Handler mit einem Platzhalter verwenden. Diese Beispielfunktion ruft bei jedem Hinzufügen eines neuen Nutzerprofils createUser auf:

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

Funktion auslösen, wenn ein Dokument aktualisiert wird

Sie können auch festlegen, dass eine Funktion ausgelöst wird, wenn ein Dokument mithilfe der onUpdate()-Funktion mit einem Platzhalter aktualisiert wird. Diese Beispielfunktion ruft updateUser auf, wenn ein Nutzer 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 ...
    });

Funktion auslösen, wenn ein Dokument gelöscht wird

Sie können eine Funktion auch auslösen, wenn ein Dokument mit der onDelete()-Funktion mit einem Platzhalter gelöscht wird. Diese Beispielfunktion ruft deleteUser auf, wenn ein Nutzer sein Nutzerprofil 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 ...
    });

Funktion für alle Änderungen an einem Dokument auslösen

Wenn Ihnen die Art des ausgelösten Ereignisses nicht wichtig ist, können Sie auf alle Ereignisse warten, Änderungen in einem Cloud Firestore-Dokument mithilfe der Funktion onWrite() durch einen Platzhalter. Diese Beispielfunktion ruft modifyUser auf. Ein Nutzer wird erstellt, aktualisiert oder gelöscht:

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 einen Snapshot der Daten bereit, die sich auf das Ereignis beziehen. Sie können diesen Snapshot verwenden, um das Dokument zu lesen oder 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 Dokument abrufen, das aktualisiert wurde, oder die Daten vor der Aktualisierung abrufen. Sie können die vorherigen Daten mithilfe von change.before.data() abrufen, das den Dokument-Snapshot vor der Aktualisierung enthält. Entsprechend enthält change.after.data() den Status des Dokument-Snapshots 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 auf Attribute wie in jedem anderen Objekt zugreifen. Alternativ können Sie die Funktion get für den Zugriff auf bestimmte Felder verwenden:

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 mit einem bestimmten Dokument in Ihrem Cloud Firestore-Datenbank. Sie können auf dieses Dokument zugreifen als DocumentReference im Attribut ref des an Ihre Funktion zurückgegebenen Snapshots.

Dieses DocumentReference stammt aus der Cloud Firestore Node.js SDK und umfasst Methoden wie update(), set() und remove(), Ändern des Dokuments, das die Funktion ausgelöst hat.

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, als Dienstkonto für Ihr Projekt autorisiert ist. Sie können Lese- und Schreibvorgänge ausführen mit dem Firebase Admin SDK:

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({ ... });
  });

Beschränkungen

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

  • Für Cloud Functions (1. Generation) muss ein vorhandener „(Standard)“ vorhanden sein im nativen Modus von Firestore verwenden. Nicht unterstützen Cloud Firestore-benannte Datenbanken oder den Datastore-Modus. Bitte Cloud Functions verwenden (2. Generation), um in solchen Fällen Ereignisse zu konfigurieren.
  • Die Reihenfolge ist nicht garantiert. Schnelle Änderungen können Funktionsaufrufe in einer unvorhergesehenen Reihenfolge auslösen.
  • Ereignisse werden mindestens einmal übergeben. Ein einzelnes Ereignis kann aber zu mehreren Funktionsaufrufen führen. Vermeiden Sie die Abhängigkeit von genau einmal vorkommenden Verfahren und schreiben Sie idempotente Funktionen.
  • Cloud Firestore im Datastore-Modus erfordert Cloud Functions (2. Generation). Cloud Functions (1. Generation) nicht unterstützen den Datastore-Modus.
  • 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 die Trigger für diese Datenbank gelöscht. Die Der Trigger liefert keine Ereignisse mehr. Er bleibt jedoch bestehen, bis Sie den Trigger löschen.
  • Überschreitet ein übereinstimmendes Ereignis die maximale Anfragegröße, wird das Ereignis wird möglicherweise nicht an Cloud Functions (1. Generation) gesendet.
    • Ereignisse, die aufgrund der Größe der Anfrage nicht zugestellt wurden, werden in Plattformlogs protokolliert und auf die Lognutzung für das Projekt angerechnet.
    • Sie finden diese Logs im Log-Explorer mit der Meldung "Ereignis kann nicht an die Cloud Functions-Funktion gesendet werden, da die Größe das Limit für die 1. Generation überschreitet..." mit dem Schweregrad error. Sie finden den Funktionsnamen unter dem Feld functionName. Wenn das Feld receiveTimestamp noch bis zu einer Stunde in der Zukunft liegt, können Sie den tatsächlichen Ereignisinhalt ableiten, indem Sie das betreffende Dokument mit einem Snapshot vor und nach dem Zeitstempel lesen.
    • So kannst du einen solchen Ablauf vermeiden:
      • Migrieren und zu Cloud Functions (2. Generation) migrieren
      • Dokument verkleinern
      • Betreffende Cloud Functions löschen
    • Sie können das Logging selbst mithilfe von Ausschlüssen deaktivieren. Beachten Sie jedoch, dass die betreffenden Ereignisse dennoch nicht übermittelt werden.