Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

數據庫觸發器

借助 Cloud Functions,您無需更新客戶端代碼即可處理 Firebase 實時數據庫中的事件。 Cloud Functions 可讓您以完全管理權限運行實時數據庫操作,並確保對實時數據庫的每個更改都單獨處理。您可以通過實時火力地堡的數據庫更改DataSnapshot或通過管理SDK

在典型的生命週期中,Firebase 實時數據庫函數執行以下操作:

  1. 等待對特定實時數據庫位置的更改。
  2. 觸發事件發生時,並執行其任務(見我可以用雲功能做些什麼?有關使用案例的例子)。
  3. 接收一個數據對象,該對象包含存儲在指定文檔中的數據的快照。

觸發實時數據庫功能

創建用於實時的數據庫事件的新功能functions.database 。要控制函數何時觸發,請指定事件處理程序之一,並指定它將偵聽事件的實時數據庫路徑。

設置事件處理程序

函數讓您可以在兩個特定級別上處理實時數據庫事件;您可以只偵聽創建、更新或刪除事件,也可以偵聽任何類型的路徑更改。 Cloud Functions 支持實時數據庫的以下事件處理程序:

  • onWrite()其觸發器被創建數據時,更新或在實時數據庫中刪除。
  • onCreate()其觸發時在實時數據庫中創建新的數據。
  • onUpdate()該觸發器當數據以實時數據庫被更新。
  • onDelete()該觸發器當數據從實時數據庫中刪除。

指定實例和路徑

為了控制何時何地你的函數應該觸發,呼叫ref(path)指定的路徑,並任選指定實時數據庫實例instance('INSTANCE_NAME')如果您不指定實例,該函數將部署到 Firebase 項目的默認實時數據庫實例。例如:

  • 默認實時數據庫實例: functions.database.ref('/foo/bar')
  • 實例名為“我的-APP-DB-2”: functions.database.instance('my-app-db-2').ref('/foo/bar')

這些方法指示您的函數處理實時數據庫實例中特定路徑的寫入。路徑規格相匹配的觸摸路徑,包括發生在它下面的任何地方寫所有的寫操作。如果您為您的函數作為路徑/foo/bar ,它匹配在這兩個地點的事件:

 /foo/bar
 /foo/bar/baz/really/deep/path

在任一情況下,火力地堡解釋該事件發生在/foo/bar ,並且所述事件數據包括在舊的和新的數據/foo/bar 。如果事件數據可能很大,請考慮在更深的路徑中使用多個函數,而不是在數據庫根目錄附近使用單個函數。為獲得最佳性能,請僅請求最深層次的數據。

你可以用大括號將路徑組件指定為通配符; ref('foo/{bar}')相匹配的任何兒童/foo 。這些通配符路徑組件的值是內可用EventContext.params你的函數的對象。在這個例子中,該值可作為context.params.bar

帶有通配符的路徑可以匹配來自一次寫入的多個事件。一個插入

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

路徑匹配"/foo/{bar}"兩次:一次用"hello": "world" ,並再次與"firebase": "functions"

處理事件數據

當處理一個實時數據庫事件,返回的數據對象是DataSnapshot 。對於onWriteonUpdate事件,所述第一參數是Change對象,它包含兩個快照之前和在觸發事件之後代表數據狀態。為onCreateonDelete事件,返回的數據對象被創建或刪除的數據的快照。

在這個例子中,該函數檢索與指定的路徑快照snap ,該字符串在該位置轉換為大寫,和寫入該修改後的字符串到數據庫中:

// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
    .onCreate((snapshot, context) => {
      // Grab the current value of what was written to the Realtime Database.
      const original = snapshot.val();
      functions.logger.log('Uppercasing', context.params.pushId, original);
      const uppercase = original.toUpperCase();
      // You must return a Promise when performing asynchronous tasks inside a Functions such as
      // writing to the Firebase Realtime Database.
      // Setting an "uppercase" sibling in the Realtime Database returns a Promise.
      return snapshot.ref.parent.child('uppercase').set(uppercase);
    });

訪問用戶認證信息

EventContext.authEventContext.authType ,您可以訪問用戶的信息,包括權限,對於觸發功能的用戶。這對於強制執行安全規則非常有用,允許您的函數根據用戶的權限級別完成不同的操作:

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

exports.simpleDbFunction = functions.database.ref('/path')
    .onCreate((snap, context) => {
      if (context.authType === 'ADMIN') {
        // do something
      } else if (context.authType === 'USER') {
        console.log(snap.val(), 'written by', context.auth.uid);
      }
    });

此外,您可以利用用戶身份驗證信息來“模擬”用戶並代表用戶執行寫入操作。確保刪除應用程序實例,如下所示,以防止並發問題:

exports.impersonateMakeUpperCase = functions.database.ref('/messages/{pushId}/original')
    .onCreate((snap, context) => {
      const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
      appOptions.databaseAuthVariableOverride = context.auth;
      const app = admin.initializeApp(appOptions, 'app');
      const uppercase = snap.val().toUpperCase();
      const ref = snap.ref.parent.child('uppercase');

      const deleteApp = () => app.delete().catch(() => null);

      return app.database().ref(ref).set(uppercase).then(res => {
        // Deleting the app is necessary for preventing concurrency leaks
        return deleteApp().then(() => res);
      }).catch(err => {
        return deleteApp().then(() => Promise.reject(err));
      });
    });

讀取前一個值

Change對象有一個before屬性,可以讓你檢查什麼事件之前保存到數據庫實時。的before屬性返回一個DataSnapshot其中的所有方法(例如, val()exists()是指先前的值。您可以通過使用原始再次讀取新的值DataSnapshot或讀取after財產。任何這種性質Change是另一個DataSnapshot表示事件發生的數據的狀態。

例如, before財產可以用來確保在首次創建時它的功能只是文字轉換為大寫:

exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
    .onWrite((change, context) => {
      // Only edit data when it is first created.
      if (change.before.exists()) {
        return null;
      }
      // Exit when the data is deleted.
      if (!change.after.exists()) {
        return null;
      }
      // Grab the current value of what was written to the Realtime Database.
      const original = change.after.val();
      console.log('Uppercasing', context.params.pushId, original);
      const uppercase = original.toUpperCase();
      // You must return a Promise when performing asynchronous tasks inside a Functions such as
      // writing to the Firebase Realtime Database.
      // Setting an "uppercase" sibling in the Realtime Database returns a Promise.
      return change.after.ref.parent.child('uppercase').set(uppercase);
    });