在典型的生命週期中,Firebase 實時數據庫函數執行以下操作:
- 等待對特定實時數據庫路徑的更改。
- 當事件發生並執行其任務時觸發。
- 接收一個數據對象,該對象包含存儲在該路徑中的數據的快照。
您可以觸發一個函數來響應 Firebase 實時數據庫中數據庫節點的寫入、創建、更新或刪除。
在 Firebase 實時數據庫更改時觸發函數
使用firebase-functions/v2/database
子包創建處理 Firebase 實時數據庫事件的函數。要控制函數何時觸發,請指定事件處理程序之一,並指定它將偵聽事件的實時數據庫路徑。
設置函數位置
實時數據庫實例位置與函數位置之間的距離會造成顯著的網絡延遲。此外,區域之間的不匹配可能會導致部署失敗。為避免這些情況,請指定函數位置,使其與數據庫實例位置相匹配。
處理實時數據庫事件
函數讓您可以在兩個特定級別處理實時數據庫事件;您可以專門監聽寫入、創建、更新或刪除事件,或者您可以監聽對引用的任何類型的更改。
這些用於響應實時數據庫事件的處理程序可用:
-
onValueWritten()
僅在實時數據庫中寫入數據時觸發。 -
onValueCreated()
僅在實時數據庫中創建數據時觸發。 -
onValueUpdated()
僅在實時數據庫中更新數據時觸發。 -
onValueDeleted()
僅在實時數據庫中刪除數據時觸發。
指定實例和路徑
要控制您的函數應在何時何地觸發,請使用路徑和可選的實時數據庫實例配置您的函數。如果您不指定實例,該函數將部署到函數區域中的所有實時數據庫實例。您還可以指定實時數據庫實例模式以部署到同一區域中的選定實例子集。
例如,使用onValueWritten()
來說明:
# All Realtime Database instances in default function region us-central1 at path "/user/{uid}" # There must be at least one Realtime Database present in us-central1. const onwrittenfunctiondefault = onValueWritten("/user/{uid}", (event) => { // … }); # Instance named "my-app-db-2", at path "/user/{uid}". # The "my-app-db-2" instance must exist in this region. const onwrittenfunctioninstance = onValueWritten( { ref: "/user/{uid}", instance: "my-app-db-2" // This example assumes us-central1, but to set location: // region: "europe-west1" }, (event) => { // … } ); # Instance with "my-app-db-" prefix, at path "/user/{uid}", where uid ends with @gmail.com. # There must be at least one Realtime Database with "my-app-db-*" prefix in this region. const onwrittenfunctioninstance = onValueWritten( { ref: "/user/{uid=*@gmail.com}", instance: "my-app-db-*" // This example assumes us-central1, but to set location: // region: "europe-west1" }, (event) => { // … } );
這些參數指示您的函數處理實時數據庫實例中特定路徑的寫入。
路徑規範匹配接觸路徑的所有寫入,包括發生在其下方任何位置的寫入。如果將函數的路徑設置為/foo/bar
,它將匹配這兩個位置的事件:
/foo/bar
/foo/bar/baz/really/deep/path
在任何一種情況下,Firebase 都會將事件解釋為發生在/foo/bar
,並且事件數據包括/foo/bar
中的舊數據和新數據。如果事件數據可能很大,請考慮在更深的路徑中使用多個函數,而不是在數據庫根附近使用單個函數。為獲得最佳性能,請僅請求盡可能深層次的數據。
通配符和捕獲
您可以使用{key}
、 {key=*}
、 {key=prefix*}
、 {key=*suffix}
進行捕獲。 *
, prefix*
, *suffix
用於單段通配符。注: **
代表多段通配符,RTDB不支持。請參閱了解路徑模式。
路徑通配符。您可以將路徑組件指定為通配符:
- 使用星號
*
。例如,foo/*
匹配節點層次結構中低於foo/
一級的任何子級。 - 使用恰好包含星號
*
的段。例如,foo/app*-us
匹配foo/
下面帶有app
前綴和-us
後綴的任何子段。
帶有通配符的路徑可以匹配來自例如單個寫入的多個事件。插入的
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
匹配路徑"/foo/*"
兩次:一次與"hello": "world"
匹配,另一次與"firebase": "functions"
匹配。
路徑捕獲。您可以將路徑匹配捕獲到要在函數代碼中使用的命名變量中(例如/user/{uid}
、 /user/{uid=*-us}
)。
捕獲變量的值在函數的database.DatabaseEvent.params對像中可用。
實例通配符。您還可以使用通配符指定實例組件。實例通配符可以有前綴、後綴或兩者都有(例如my-app-*-prod
)。
通配符和捕獲參考
使用 Cloud Functions(第 2 代)和實時數據庫,可以在指定ref
和instance
時使用模式。每個觸發器接口都將具有以下用於確定功能範圍的選項:
指定ref | 指定instance | 行為 |
---|---|---|
單個 ( /foo/bar ) | 未指定 | 作用域處理程序到函數區域中的所有實例。 |
單個 ( /foo/bar ) | 單個( 'my-new-db' ) | 作用域處理程序到函數區域中的特定實例。 |
單個 ( /foo/bar ) | 模式( 'inst-prefix*' ) | 範圍處理程序到與函數區域中的模式匹配的所有實例。 |
模式 ( /foo/{bar} ) | 未指定 | 作用域處理程序到函數區域中的所有實例。 |
模式 ( /foo/{bar} ) | 單個( 'my-new-db' ) | 作用域處理程序到函數區域中的特定實例。 |
模式 ( /foo/{bar} ) | 模式( 'inst-prefix*' ) | 範圍處理程序到與函數區域中的模式匹配的所有實例。 |
處理事件數據
處理實時數據庫事件時,返回的數據對DataSnapshot
。
對於onValueWritten
或onValueUpdated
事件,第一個參數是一個Change
對象,它包含兩個快照,分別表示觸發事件前後的數據狀態。
對於onValueCreated
和onValueDeleted
事件,返回的數據對像是創建或刪除的數據的快照。
在此示例中,該函數將指定路徑foo/bar
的快照檢索為snap
,將該位置的字符串轉換為大寫,並將修改後的字符串寫入數據庫:
// Listens for new messages added to /messages/:pushId/original and creates an // uppercase version of the message to /messages/:pushId/uppercase export makeuppercase = onValueCreated("foo/bar", (event) => { // Grab the current value of what was written to the Realtime Database. const original = event.data.val(); functions.logger.log('Uppercasing', event.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 event.data.ref.parent.child('uppercase').set(uppercase); });
讀取前一個值
Change
對像有一個before
屬性,可讓您檢查在事件發生之前保存到實時數據庫的內容。 before
屬性返回一個DataSnapshot
,其中所有方法(例如, val()
和exists()
)都引用先前的值。您可以通過使用原始DataSnapshot
或讀取after
屬性再次讀取新值。任何Change
上的此屬性是另一個DataSnapshot
,表示事件發生後數據的狀態。
例如, before
屬性可用於確保函數在首次創建時僅使用大寫文本:
exports makeuppercase = onValueWritten("/messages/{pushId}/original", (event) => { // Only edit data when it is first created. if (event.data.before.exists()) { return null; } // Exit when the data is deleted. if (!event.data.after.exists()) { return null; } // Grab the current value of what was written to the Realtime Database. const original = event.data.after.val(); console.log('Uppercasing', event.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 event.data.after.ref.parent.child('uppercase').set(uppercase); });