Cloud Firestore Triggers

With Cloud Functions, you can handle events in Cloud Firestore with no need to update client code. You can make Cloud Firestore changes via the DeltaDocumentSnapshot interface or via the Admin SDK.

In a typical lifecycle, a Cloud Firestore function does the following:

  1. Waits for changes to a particular document.
  2. Triggers when an event occurs and performs its tasks (see What can I do with Cloud Functions? for examples of use cases).
  3. Receives an event data object that contains two snapshots of the data stored in the specified document: one with the original data prior to the change, and one with the new data.

Trigger a Cloud Firestore function

The Cloud Functions for Firebase SDK exports a functions.firestore object that allows you to create handlers tied to specific events.

Cloud Firestore supports create, update, delete, and write events:

Event Type Trigger
onCreate Triggered when a document is written to for the first time.
onUpdate Triggered when a document already exists and has any value changed.
onDelete Triggered when a document with data is deleted.
onWrite Triggered when onCreate, onUpdate or onDelete is triggered.

If you don't have a project enabled for Cloud Functions for Firebase yet, then read Get Started: Write and Deploy Your First Functions to configure and set up your Cloud Functions for Firebase project.

Trigger a function when a specific document changes

If you want to trigger an event for any change to a specific document then you can use the following function.

Node.js

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

Trigger a function when a new document is created

You can trigger a function to fire any time a new document is created in a collection by using an onCreate() handler with a wildcard. This example function calls createUser every time a new user profile is added:

Node.js

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

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

    // perform desired operations ...
});

Trigger a function when a document is updated

You can also trigger a function to fire when a document is updated using the onUpdate() function with a wildcard. This example function calls updateUser if a user changes their profile:

Node.js

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

    // ...or the previous value before this update
    var previousValue = event.data.previous.data();

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

    // perform desired operations ...
});

Trigger a function when a document is deleted

You can also trigger a function when a document is deleted using the onDelete() function with a wildcard. This example function calls deleteUser when a user deletes their user profile:

Node.js

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

    // perform desired operations ...
});

Trigger a function for any change to a document

If you don't care about the type of event being fired, you can listen for all changes in a Cloud Firestore document using the onWrite() function with a wildcard This example function calls modifyUser if a user is created, updated, or deleted:

Node.js

exports.modifyUser = functions.firestore
  .document('users/{userID}')
  .onWrite(event => {
    // Get an object with the current document value
    var document = event.data.data();

    // Get an object with the previous document value (for update or delete)
    // Note that previous will be null if no old value exists.
    if (event.data.previous) {
      var oldDocument = event.data.previous.data();
    }

    // perform desired operations ...
});

Handle Event Data

Reading Data

When a function is triggered, you might want to get data from a document that was updated, or get the data prior to update. You can get this data by using event.data, which contains the current document (event.data.data()) as well as the document prior to update (event.data.previous.data()).

Node.js

exports.updateUser = functions.firestore
  .document('users/{userId}')
  .onUpdate(event => {
    // Get an object representing the current document
    var newValue = event.data.data();

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

You can access properties as you would in any other object. Alternatively, you can use the get function to access specific fields:

Node.js

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

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

Writing Data

Each function invocation is associated with a specific document in your Cloud Firestore database. You can access that document as a DocumentReference at event.data.ref.

This DocumentReference comes from the Cloud Firestore Node.js SDK and includes methods like update(), set(), and remove() so you can easily modify the document that triggered the function.

Node.js

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

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

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

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

Using wildcards and parameters

If you do not know the specific document you want to attach an event trigger to, then you can use a {wildcard} in place of the document ID.

Node.js

// Listen for changes in all documents and all sub-collections
exports.useWildcard = functions.firestore
  .document('users/{userId}')
  .onWrite((event) => {
    // If we set `/users/marie` to {name: "marie"} then
    event.params.userId == "marie"
    // ... and ...
    event.data.data() == {name: "Marie"}
  });

In this example, when any field on any document in users is changed, it matches a wildcard called userId.

If a document in users has subcollections, and a field in one of those subcollections' documents is changed, the userId wildcard is not triggered.

Wildcard matches are extracted from the document path and stored into event.params. You may define as many wildcards as you like to substitute explicit collection or document IDs.

Node.js

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

Limitations and guarantees

While developing your applications, keep in mind that both Cloud Firestore and Cloud Functions for Firebase are currently in beta which may result in unexpected behavior.

A few known limitations include:

  • It may take more than 5 seconds for a function to be triggered after a change to Cloud Firestore data.
  • Delivery of function invocations is not currently guaranteed. As the Cloud Firestore and Cloud Functions integration improves, we plan to guarantee "at least once" delivery. However, this may not always be the case during beta. This may also result in multple invocations for a single event, so for the highest quality functions ensure that the functions are written to be idempotent.
  • Ordering is not guaranteed. It is possible that rapid changes could trigger function invocations in an unexpected order.

Send feedback about...

Need help? Visit our support page.