Google Cloud Firestore Triggers

Cloud Functions can handle events in Cloud Firestore with no need to update client code. You can read and/or update Cloud Firestore in response to these events using the Firestore APIs and client libraries.

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.

  3. Receives a data object with a snapshot of the affected document. For write or update events, the data object contains snapshots representing document state before and after the triggering event.

Event types

Cloud Firestore supports create, update, delete, and write events. The write event encompasses all modifications to a document.

Event type Trigger
providers/cloud.firestore/eventTypes/document.create Triggered when a document is written to for the first time.
providers/cloud.firestore/eventTypes/document.update Triggered when a document already exists and has any value changed.
providers/cloud.firestore/eventTypes/document.delete Triggered when a document with data is deleted.
providers/cloud.firestore/eventTypes/document.write Triggered when a document is created, updated or deleted.

Wildcards are written in triggers using curly braces, as follows: /projects/YOUR-PROJECT-ID/databases/(default)/documents/collection/{document_wildcard}

Specifying the document path

To trigger your function, specify a document path to listen to. Functions only respond to document changes, and cannot monitor specific fields or collections. Below are a few examples of valid document paths:

  • users/marie: valid trigger. Monitors a single document, /users/marie.

  • users/{username}: valid trigger. Monitors all user documents. Wildcards are used to monitor all documents in the collection.

  • users/{username}/addresses: invalid trigger. Refers to the subcollection addresses, not a document.

  • users/{username}/addresses/home: valid trigger. Monitors the home address document for all users.

  • users/{username}/addresses/{addressId}: valid trigger. Monitors all address documents.

Using wildcards and parameters

If you do not know the specific document you want to monitor, use a {wildcard} instead of the document ID:

  • users/{username} listens for changes to all user documents.

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

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

Wildcard matches are extracted from document paths and stored in event.params. You can define as many wildcards as you like to substitute explicit collection or document IDs.

Event structure

This trigger invokes your function with an event similar to the one shown below:

{
    "oldValue": { // Update and Delete operations only
        A Document object containing a pre-operation document snapshot
    },
    "updateMask": { // Update operations only
        A DocumentMask object that lists changed fields.
    },
    "value": {
        // A Document object containing a post-operation document snapshot
    }
}

Code sample

The sample Cloud Function below prints the fields of a triggering Cloud Firestore event:

Node.js 6

/**
 * Triggered by a change to a Firestore document.
 *
 * @param {!Object} event The Cloud Functions event.
 */
exports.helloFirestore = event => {
  const triggerResource = event.resource;

  console.log(`Function triggered by event on: ${triggerResource}`);
  console.log(`Event type: ${event.eventType}`);

  if (event.data.oldValue && Object.keys(event.data.oldValue).length) {
    console.log(`\nOld value:`);
    console.log(JSON.stringify(event.data.oldValue, null, 2));
  }

  if (event.data.value && Object.keys(event.data.value).length) {
    console.log(`\nNew value:`);
    console.log(JSON.stringify(event.data.value, null, 2));
  }
};

Node.js 8 (Beta)

/**
 * Triggered by a change to a Firestore document.
 *
 * @param {object} data The event payload.
 * @param {object} context The event metadata.
 */
exports.helloFirestore = (data, context) => {
  const triggerResource = context.resource;

  console.log(`Function triggered by change to: ${triggerResource}`);
  console.log(`Event type: ${context.eventType}`);

  if (data.oldValue && Object.keys(data.oldValue).length) {
    console.log(`\nOld value:`);
    console.log(JSON.stringify(data.oldValue, null, 2));
  }

  if (data.value && Object.keys(data.value).length) {
    console.log(`\nNew value:`);
    console.log(JSON.stringify(data.value, null, 2));
  }
};

Python (Beta)

import json
def hello_firestore(data, context):
    """ Triggered by a change to a Firestore document.
    Args:
        data (dict): The event payload.
        context (google.cloud.functions.Context): Metadata for the event.
    """
    trigger_resource = context.resource

    print('Function triggered by change to: %s' % trigger_resource)

    print('\nOld value:')
    print(json.dumps(data["oldValue"]))

    print('\nNew value:')
    print(json.dumps(data["value"]))

The example below retrieves the value added by the user, converts the string at that location to uppercase, and replaces the value with the uppercase string:

Node.js 6

const Firestore = require('@google-cloud/firestore');

const firestore = new Firestore({
  projectId: process.env.GCP_PROJECT,
});

// Converts strings added to /messages/{pushId}/original to uppercase
exports.makeUpperCase = event => {
  const resource = event.resource;
  const affectedDoc = firestore.doc(resource.split('/documents/')[1]);

  const curValue = event.data.value.fields.original.stringValue;
  const newValue = curValue.toUpperCase();
  console.log(`Replacing value: ${curValue} --> ${newValue}`);

  return affectedDoc.set({
    original: newValue,
  });
};

Node.js 8 (Beta)

const Firestore = require('@google-cloud/firestore');

const firestore = new Firestore({
  projectId: process.env.GCP_PROJECT,
});

// Converts strings added to /messages/{pushId}/original to uppercase
exports.makeUpperCase = (data, context) => {
  const resource = context.resource;
  const affectedDoc = firestore.doc(resource.split('/documents/')[1]);

  const curValue = data.value.fields.original.stringValue;
  const newValue = curValue.toUpperCase();
  console.log(`Replacing value: ${curValue} --> ${newValue}`);

  return affectedDoc.set({
    original: newValue,
  });
};

Python (Beta)

from google.cloud import firestore
client = firestore.Client()


# Converts strings added to /messages/{pushId}/original to uppercase
def make_upper_case(data, context):
    path_parts = context.resource.split('/documents/')[1].split('/')
    collection_path = path_parts[0]
    document_path = '/'.join(path_parts[1:])

    affected_doc = client.collection(collection_path).document(document_path)

    cur_value = data["value"]["fields"]["original"]["stringValue"]
    new_value = cur_value.upper()
    print(f'Replacing value: {cur_value} --> {new_value}')

    affected_doc.set({
        u'original': new_value
    })

Deploying your function

The following gcloud command deploys a function that is triggered by write events on the document /messages/{pushId}:

Node.js 6

gcloud functions deploy FUNCTION_NAME --runtime nodejs6 \ 
  --trigger-event providers/cloud.firestore/eventTypes/document.write \ 
  --trigger-resource projects/YOUR-PROJECT-ID/databases/(default)/documents/messages/{pushId}

Node.js 8 (Beta)

gcloud functions deploy FUNCTION_NAME --runtime nodejs8 \ 
  --trigger-event providers/cloud.firestore/eventTypes/document.write \ 
  --trigger-resource projects/YOUR-PROJECT-ID/databases/(default)/documents/messages/{pushId}

Python (Beta)

gcloud functions deploy FUNCTION_NAME --runtime python37 \ 
  --trigger-event providers/cloud.firestore/eventTypes/document.write \ 
  --trigger-resource projects/YOUR-PROJECT-ID/databases/(default)/documents/messages/{pushId}
Argument Description
--runtime RUNTIME The name of the runtime you are using, such as nodejs6, nodejs8, or python37.
--trigger-event NAME The event type that the function will monitor for (one of write, create, update or delete).
--trigger-resource NAME The fully qualified database path to which the function will listen. This should conform to the following format: projects/YOUR-PROJECT-ID/databases/(default)/documents/PATH

Limitations and guarantees

Both Cloud Firestore and Cloud Functions for Firebase are Beta products, and have some known limitations:

  • It can take more than 5 seconds for a functions to respond to Cloud Firestore changes.

  • Proper function invocation is not yet currently guaranteed. Currently, events might not be delivered at all or delivered more than once. Eventually, we plan to guarantee "at least once" delivery. To avoid depending on "exactly-once" mechanics, write your functions to be idempotent.

  • Ordering is not guaranteed. Rapid changes can trigger function invocations in an unexpected order.

Was this page helpful? Let us know how we did:

Send feedback about...

Cloud Functions Documentation