Dengan Cloud Functions, Anda dapat menangani peristiwa di Firebase Realtime Database tanpa harus memperbarui kode klien. Cloud Functions dapat Anda gunakan untuk menjalankan operasi Realtime Database dengan hak istimewa administratif penuh, dan memastikan setiap perubahan pada Realtime Database diproses secara terpisah. Anda dapat membuat perubahan pada Firebase Realtime Database melalui snapshot data atau melalui Admin SDK.
Dalam siklus proses umum, fungsi Firebase Realtime Database melakukan hal-hal berikut:
- Menunggu perubahan pada jalur Realtime Database tertentu.
- Terpicu ketika suatu peristiwa terjadi dan menjalankan tugasnya.
- Menerima objek data yang berisi snapshot data yang disimpan di jalur tersebut.
Anda dapat memicu fungsi sebagai respons terhadap penulisan, pembuatan, pembaruan, atau penghapusan node database di Firebase Realtime Database. Untuk mengontrol kapan fungsi terpicu, tentukan salah satu pengendali peristiwa dan tentukan jalur Realtime Database tempat peristiwa akan diproses.
Menetapkan lokasi fungsi
Jarak antara lokasi instance Realtime Database dan lokasi fungsi dapat menyebabkan latensi jaringan yang signifikan. Selain itu, ketidakcocokan antara region dapat mengakibatkan kegagalan deployment. Untuk menghindari situasi tersebut, tentukan lokasi fungsi sehingga cocok dengan lokasi instance database.
Menangani peristiwa Realtime Database
Dengan Functions, Anda dapat menangani peristiwa Realtime Database di dua tingkat kekhususan; Anda dapat hanya memproses peristiwa penulisan, pembuatan, pembaruan, atau penghapusan secara khusus, atau Anda dapat memproses jenis perubahan apa pun pada referensi.
Pengendali berikut tersedia untuk merespons peristiwa Realtime Database:
onValueWritten()
Dipicu saat data dibuat, diperbarui, atau dihapus di Realtime Database.onValueCreated()
Hanya dipicu saat data dibuat di Realtime Database.onValueUpdated()
Hanya dipicu saat data diperbarui di Realtime Database.onValueDeleted()
Hanya dipicu saat data dihapus di Realtime Database.
on_value_written()
Dipicu saat data dibuat, diperbarui, atau dihapus di Realtime Database.on_value_created()
Hanya dipicu saat data dibuat di Realtime Database.on_value_updated()
Hanya dipicu saat data diperbarui di Realtime Database.on_value_deleted()
Hanya dipicu saat data dihapus di Realtime Database.
Mengimpor modul yang diperlukan
Di sumber fungsi, Anda harus mengimpor modul SDK yang ingin digunakan. Untuk contoh ini, Anda perlu mengimpor modul HTTP dan Realtime Database bersama dengan modul Firebase Admin SDK untuk menulis ke Realtime Database.
// The Cloud Functions for Firebase SDK to setup triggers and logging.
const {onRequest} = require("firebase-functions/v2/https");
const {onValueCreated} = require("firebase-functions/v2/database");
const {logger} = require("firebase-functions");
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require("firebase-admin");
admin.initializeApp();
# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import db_fn, https_fn
# The Firebase Admin SDK to access the Firebase Realtime Database.
from firebase_admin import initialize_app, db
app = initialize_app()
Menentukan instance dan jalur
Untuk mengontrol kapan dan di mana fungsi Anda harus terpicu, konfigurasikan fungsi dengan jalur dan, secara opsional, instance Realtime Database. Jika Anda tidak menentukan instance, fungsi tersebut akan memproses semua instance Realtime Database di region fungsi. Anda juga dapat menentukan pola instance Realtime Database yang akan di-deploy ke subset instance tertentu di region yang sama.
Contoh:
// 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) => { // … } );
# 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.
@db_fn.on_value_written(r"/user/{uid}")
def onwrittenfunctiondefault(event: db_fn.Event[db_fn.Change]):
# ...
pass
# Instance named "my-app-db-2", at path "/user/{uid}".
# The "my-app-db-2" instance must exist in this region.
@db_fn.on_value_written(
reference=r"/user/{uid}",
instance="my-app-db-2",
# This example assumes us-central1, but to set location:
# region="europe-west1",
)
def on_written_function_instance(event: db_fn.Event[db_fn.Change]):
# ...
pass
# 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.
@db_fn.on_value_written(
reference=r"/user/{uid=*@gmail.com}",
instance="my-app-db-*",
# This example assumes us-central1, but to set location:
# region="europe-west1",
)
def on_written_function_instance(event: db_fn.Event[db_fn.Change]):
# ...
pass
Parameter ini akan mengarahkan fungsi Anda untuk menangani penulisan di jalur tertentu dalam instance Realtime Database.
Spesifikasi jalur cocok dengan semua penulisan yang menyentuh suatu jalur, termasuk penulisan yang terjadi di bawahnya. Jika Anda menetapkan /foo/bar
sebagai jalur fungsi, jalur tersebut akan cocok dengan peristiwa di kedua lokasi ini:
/foo/bar
/foo/bar/baz/really/deep/path
Bagaimanapun juga, Firebase akan menafsirkan bahwa peristiwa terjadi di /foo/bar
, dan data peristiwa menyertakan data lama dan baru di /foo/bar
. Jika data peristiwa kemungkinan berukuran besar, sebaiknya gunakan beberapa fungsi di jalur yang lebih dalam, bukan fungsi tunggal di dekat root database Anda. Untuk mendapatkan performa terbaik, hanya minta data di level sedalam mungkin.
Karakter pengganti dan pengambilan
Anda dapat menggunakan {key}
, {key=*}
, {key=prefix*}
, {key=*suffix}
untuk pengambilan. *
, prefix*
, *suffix
untuk karakter pengganti segmen tunggal.
Catatan: **
merepresentasikan karakter pengganti multi-segmen, yang tidak didukung oleh Realtime Database.
Lihat bagian Memahami pola jalur.
Karakter pengganti jalur. Anda dapat menentukan komponen jalur sebagai karakter pengganti:
- Menggunakan tanda bintang,
*
. Misalnya,foo/*
cocok dengan turunan mana pun dari satu level hierarki node di bawahfoo/
. - Menggunakan segmen yang berisi tanda bintang
*
. Misalnya,foo/app*-us
cocok dengan segmen turunan di bawahfoo/
dengan awalanapp
dan akhiran-us
.
Jalur dengan karakter pengganti dapat cocok dengan beberapa peristiwa dari, misalnya, satu penulisan. Sisipan
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
cocok dengan jalur "/foo/*"
dua kali: sekali dengan "hello": "world"
dan sekali lagi dengan "firebase": "functions"
.
Pengambilan jalur. Anda dapat mengambil jalur yang cocok dan menjadikannya variabel bernama untuk digunakan dalam kode fungsi Anda (misalnya /user/{uid}
, /user/{uid=*-us}
).
Nilai variabel pengambilan ini tersedia dalam objek database.DatabaseEvent.params dari fungsi Anda.
Karakter pengganti instance. Anda juga dapat menentukan komponen
instance menggunakan karakter pengganti. Karakter pengganti instance dapat memiliki awalan, akhiran, atau keduanya (misalnya, my-app-*-prod
).
Referensi karakter pengganti dan pengambilan
Dengan Cloud Functions (generasi ke-2) dan Realtime Database, suatu pola dapat digunakan saat menentukan ref
dan instance
. Setiap antarmuka pemicu akan memiliki opsi berikut untuk mencakup fungsi:
Menentukan ref |
Menentukan instance |
Perilaku |
---|---|---|
Tunggal (/foo/bar ) |
Tidak menentukan | Mencakup pengendali ke semua instance di region fungsi. |
Tunggal (/foo/bar ) |
Tunggal (‘my-new-db' ) |
Mencakup pengendali ke instance tertentu di region fungsi. |
Tunggal (/foo/bar ) |
Pola (‘inst-prefix*' ) |
Mencakup pengendali ke semua instance yang cocok dengan pola di region fungsi. |
Pola (/foo/{bar} ) |
Tidak menentukan | Mencakup pengendali ke semua instance di region fungsi. |
Pola (/foo/{bar} ) |
Tunggal (‘my-new-db' ) |
Mencakup pengendali ke instance tertentu di region fungsi. |
Pola (/foo/{bar} ) |
Pola (‘inst-prefix*' ) |
Mencakup pengendali ke semua instance yang cocok dengan pola di region fungsi. |
Menangani data peristiwa
Saat terpicu, peristiwa Realtime Database akan meneruskan objek Event
ke fungsi pengendali Anda.
Objek ini memiliki properti data
, yang berisi snapshot data yang dibuat atau dihapus untuk peristiwa pembuatan dan penghapusan.
Dalam contoh ini, fungsi mengambil data untuk jalur yang direferensikan, mengubah string di lokasi tersebut menjadi huruf kapital, dan menulis string yang telah diubah tersebut ke database:
// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
// for all databases in 'us-central1'
exports.makeuppercase = onValueCreated(
"/messages/{pushId}/original",
(event) => {
// Grab the current value of what was written to the Realtime Database.
const original = event.data.val();
logger.log("Uppercasing", event.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing
// asynchronous tasks inside a function, 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);
},
);
@db_fn.on_value_created(reference="/messages/{pushId}/original")
def makeuppercase(event: db_fn.Event[Any]) -> None:
"""Listens for new messages added to /messages/{pushId}/original and
creates an uppercase version of the message to /messages/{pushId}/uppercase
"""
# Grab the value that was written to the Realtime Database.
original = event.data
if not isinstance(original, str):
print(f"Not a string: {event.reference}")
return
# Use the Admin SDK to set an "uppercase" sibling.
print(f"Uppercasing {event.params['pushId']}: {original}")
upper = original.upper()
parent = db.reference(event.reference).parent
if parent is None:
print("Message can't be root node.")
return
parent.child("uppercase").set(upper)
Membaca nilai sebelumnya
Untuk peristiwa write
atau update
, properti data
adalah objek Change
yang berisi dua snapshot
yang mewakili status data sebelum dan setelah peristiwa pemicu.
Objek Change
memiliki properti before
yang dapat digunakan untuk memeriksa
apa saja yang telah disimpan ke Realtime Database sebelum peristiwa ini dan properti after
yang mewakili status data setelah peristiwa tersebut terjadi.
Misalnya, properti before
dapat digunakan untuk memastikan bahwa fungsi hanya mengubah teks menjadi huruf kapital ketika pertama kali dibuat:
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); });
@db_fn.on_value_written(reference="/messages/{pushId}/original")
def makeuppercase2(event: db_fn.Event[db_fn.Change]) -> None:
"""Listens for new messages added to /messages/{pushId}/original and
creates an uppercase version of the message to /messages/{pushId}/uppercase
"""
# Only edit data when it is first created.
if event.data.before is not None:
return
# Exit when the data is deleted.
if event.data.after is None:
return
# Grab the value that was written to the Realtime Database.
original = event.data.after
if not hasattr(original, "upper"):
print(f"Not a string: {event.reference}")
return
# Use the Admin SDK to set an "uppercase" sibling.
print(f"Uppercasing {event.params['pushId']}: {original}")
upper = original.upper()
parent = db.reference(event.reference).parent
if parent is None:
print("Message can't be root node.")
return
parent.child("uppercase").set(upper)