Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

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刪除包含數據的文檔時觸發。
onWriteonCreateonUpdateonDelete被觸發時觸發。

如果您尚未為 Cloud Functions for Firebase 啟用項目,請閱讀入門:編寫和部署您的第一個函數以配置和設置您的 Cloud Functions for Firebase 項目。

編寫 Cloud Firestore 觸發的函數

定義函數觸發器

要定義 Cloud Firestore 觸發器,請指定文檔路徑和事件類型:

節點.js

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

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

文檔路徑可以引用特定文檔通配符模式

指定單個文檔

如果要觸發對特定文檔的任何更改的事件,則可以使用以下函數。

節點.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:

節點.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,例如:

節點.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

節點.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

節點.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

節點.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

節點.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()包含更新後的文檔快照狀態。

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

您可以像訪問任何其他對像一樣訪問屬性。或者,您可以使用get函數訪問特定字段:

節點.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()等方法,因此您可以輕鬆修改觸發該函數的文檔。

節點.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執行讀取和寫入:

節點.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 觸發器的以下限制:

  • 不保證訂購。快速更改可能會以意外的順序觸發函數調用。
  • 事件至少傳遞一次,但單個事件可能會導致多個函數調用。避免依賴完全一次的機制,並編寫冪等函數
  • Cloud Functions 的 Cloud Firestore 觸發器僅適用於原生模式下的 Cloud Firestore。它不適用於 Datastore 模式下的 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刪除包含數據的文檔時觸發。
onWriteonCreateonUpdateonDelete被觸發時觸發。

如果您尚未為 Cloud Functions for Firebase 啟用項目,請閱讀入門:編寫和部署您的第一個函數以配置和設置您的 Cloud Functions for Firebase 項目。

編寫 Cloud Firestore 觸發的函數

定義函數觸發器

要定義 Cloud Firestore 觸發器,請指定文檔路徑和事件類型:

節點.js

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

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

文檔路徑可以引用特定文檔通配符模式

指定單個文檔

如果要觸發對特定文檔的任何更改的事件,則可以使用以下函數。

節點.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:

節點.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,例如:

節點.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

節點.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

節點.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

節點.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

節點.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()包含更新後的文檔快照狀態。

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

您可以像訪問任何其他對像一樣訪問屬性。或者,您可以使用get函數訪問特定字段:

節點.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()等方法,因此您可以輕鬆修改觸發該函數的文檔。

節點.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執行讀取和寫入:

節點.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 觸發器的以下限制:

  • 不保證訂購。快速更改可能會以意外的順序觸發函數調用。
  • 事件至少傳遞一次,但單個事件可能會導致多個函數調用。避免依賴完全一次的機制,並編寫冪等函數
  • Cloud Functions 的 Cloud Firestore 觸發器僅適用於原生模式下的 Cloud Firestore。它不適用於 Datastore 模式下的 Cloud Firestore。