转到控制台

Cloud Firestore 触发器

借助 Cloud Functions,您无需更新客户端代码即可处理 Cloud Firestore 中的事件。您可以通过 DocumentSnapshot 接口或 Admin SDK 进行 Cloud Firestore 更改。

在一个典型的生命周期中,Cloud Firestore 函数会执行以下操作:

  1. 等待特定文档发生更改。
  2. 在有事件发生时触发并执行相应的任务(请参阅 Cloud Functions 有哪些用途?,了解使用情形示例) 。
  3. 接收包含了存储在指定文档中的数据快照的数据对象。对于 onWriteonUpdate 事件,该数据对象包含两个快照,分别代表触发事件前后的数据状态。

Firestore 实例的位置与函数位置之间的距离可能会造成严重的网络延迟。为了优化性能,请考虑指定函数位置(如适用)。

Cloud Firestore 函数触发器

Cloud Functions for Firebase SDK 会导出一个 functions.firestore 对象,可用于创建与特定 Cloud Firestore 事件关联的处理程序。

事件类型 触发器
onCreate 首次写入某个文档时触发。
onUpdate 当某文档已存在且值发生了任何更改时触发。
onDelete 当文档的数据被删除时触发。
onWrite 当触发了 onCreateonUpdateonDelete 时触发。

如果您还没有启用了 Cloud Functions for Firebase 的项目,请参阅《使用入门:编写和部署您的第一批函数》,配置并设置 Cloud Functions for Firebase 项目。

编写 Cloud Firestore 触发的函数

定义函数触发器

要定义 Cloud Firestore 触发器,请指定文档路径和事件类型:

Node.js

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

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

文档路径可以引用特定文档通配符模式

指定单个文档

如果您希望针对特定文档的任何更改都触发一个事件,可以使用以下函数。

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

使用通配符指定一组文档

如果您要将触发器附加到一组文档(例如特定集合中的任何文档)中,请使用 {wildcard} 替代文档 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"}
    });

在此示例中,如果 users 中的任何文档的任何字段发生更改,都会与一个名为 userId 的通配符相匹配。

如果 users 中的某个文档有多个子集合,并且这些子集合中的一个文档内的某字段发生了更改,那么不会触发 userId 通配符。

通配符匹配项会从文档路径中提取出来并存储到 context.params 中。您可以定义任意多个通配符,以替代明确指定的集合或文档 ID,例如:

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

事件触发器

在创建新文档时触发函数

您可以使用带通配符onCreate() 处理程序,触发一个只要在集合中新建文档即会触发的函数。每次添加了新的用户个人资料时,此示例函数都会调用 createUser

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

当文档更新时触发函数

您还可以使用带通配符onUpdate() 函数,触发一个在文档更新时触发的函数。此示例函数会在用户更改其个人资料时调用 updateUser

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

当文档被删除时触发函数

您还可以使用带通配符onDelete() 函数在文档被删除时触发函数。当用户删除其用户个人资料时,此示例函数会调用 deleteUser

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

对文档进行任何更改时触发函数

如果您不在意所触发的事件类型,可以使用带通配符onWrite() 函数来侦听 Cloud Firestore 文档中的所有更改。如果创建、更新或删除用户,此示例函数将调用 modifyUser

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

读取和写入数据

函数被触发后,会提供与相应事件相关的数据的快照。您可以使用此快照对触发了该事件的文档执行读取或写入操作,也可以使用 Firebase Admin SDK 访问数据库的其他部分。

事件数据

读取数据

函数触发后,您可能希望获取更新后文档的数据,或者获取更新之前的数据。您可以通过使用 change.before.data() 来获取之前的数据,其中包含更新前的文档快照。同样,change.after.data() 包含更新后的文档快照状态。

Node.js

exports.updateUser = 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();
    });

您可以像在其他任何对象中一样访问属性。或者,您可以使用 get 函数访问特定字段:

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');

写入数据

每个函数调用都与 Cloud Firestore 数据库中的特定文档相关联。您可以在为函数返回的快照的 ref 属性中以 DocumentReference 的形式访问该文档。

DocumentReference 来自 Cloud Firestore Node.js SDK,并且包含 update()set()remove() 等方法,因此您可以轻松修改触发了相应函数的文档。

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

触发事件之外的数据

Cloud Functions 函数在受信任的环境中执行,这意味着这些函数被授权为项目的服务帐号。您可以使用 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({ ... });
  });

限制和保证

适用于 Cloud Functions 的 Cloud Firestore 触发器是一项测试版功能,具有一些已知限制:

  • 函数最长可能需要 10 秒钟才会响应 Cloud Firestore 中的更改。
  • 无法保证顺序。快速更改会以意想不到的顺序触发函数调用。
  • 事件至少会被传送一次,但单个事件可能会导致多次调用函数。避免依赖一次性机制,并编写幂等函数
  • 适用于 Cloud Functions 的 Cloud Firestore 触发器仅适用于原生模式下的 Cloud Firestore,不适用于 Datastore 模式下的 Cloud Firestore。