ด้วย Cloud Functions คุณจะจัดการเหตุการณ์ใน Firebase Realtime Database ได้โดยไม่ต้องอัปเดตโค้ดฝั่งไคลเอ็นต์ Cloud Functions ช่วยให้คุณเรียกใช้การดำเนินการ Realtime Database โดยมีสิทธิ์ระดับผู้ดูแลระบบอย่างเต็มรูปแบบ และช่วยให้มั่นใจได้ว่าการเปลี่ยนแปลงแต่ละรายการใน Realtime Database จะได้รับการประมวลผลแยกกัน คุณสามารถทําFirebase Realtime Databaseการเปลี่ยนแปลงผ่านสแนปชอตข้อมูล หรือผ่าน Admin SDK
ในวงจรการใช้งานทั่วไป Firebase Realtime Database ฟังก์ชันจะทำสิ่งต่อไปนี้
- รอการเปลี่ยนแปลงในRealtime Databaseเส้นทางที่เฉพาะเจาะจง
- ทริกเกอร์เมื่อเกิดเหตุการณ์และดำเนินการตามที่กำหนด
- รับออบเจ็กต์ข้อมูลที่มีสแนปชอตของข้อมูลที่จัดเก็บ ในเส้นทางนั้น
คุณทริกเกอร์ฟังก์ชันเพื่อตอบสนองต่อการเขียน สร้าง อัปเดต หรือลบโหนดฐานข้อมูลใน Firebase Realtime Database ได้ หากต้องการ ควบคุมเวลาที่ฟังก์ชันทริกเกอร์ ให้ระบุตัวแฮนเดิลเหตุการณ์อย่างใดอย่างหนึ่ง และ ระบุเส้นทาง Realtime Database ที่จะใช้รับฟังเหตุการณ์
การตั้งค่าตำแหน่งฟังก์ชัน
ระยะห่างระหว่างตำแหน่งของอินสแตนซ์ Realtime Database กับตำแหน่งของฟังก์ชันอาจทำให้เกิดเวลาในการตอบสนองของเครือข่ายอย่างมาก นอกจากนี้ ภูมิภาคที่ไม่ตรงกันอาจทำให้การติดตั้งใช้งานล้มเหลว หากต้องการหลีกเลี่ยงสถานการณ์เหล่านี้ ให้ระบุตำแหน่งฟังก์ชันเพื่อให้ตรงกับตำแหน่งอินสแตนซ์ฐานข้อมูล
การจัดการเหตุการณ์ Realtime Database
ฟังก์ชันช่วยให้คุณจัดการRealtime Databaseเหตุการณ์ได้ 2 ระดับความเฉพาะเจาะจง คุณสามารถรอรับเฉพาะเหตุการณ์การเขียน การสร้าง การอัปเดต หรือการลบ หรือจะรอรับการเปลี่ยนแปลงใดๆ ในการอ้างอิงก็ได้
ตัวแฮนเดิลต่อไปนี้พร้อมใช้งานสำหรับการตอบสนองต่อเหตุการณ์ Realtime Database
onValueWritten()
ทริกเกอร์เมื่อมีการสร้าง อัปเดต หรือลบข้อมูลใน Realtime DatabaseonValueCreated()
จะทริกเกอร์เมื่อสร้างข้อมูลใน Realtime Database เท่านั้นonValueUpdated()
จะทริกเกอร์เมื่อมีการอัปเดตข้อมูลใน Realtime Database เท่านั้นonValueDeleted()
จะทริกเกอร์เมื่อมีการลบข้อมูลใน Realtime Database เท่านั้น
on_value_written()
ทริกเกอร์เมื่อมีการสร้าง อัปเดต หรือลบข้อมูลใน Realtime Databaseon_value_created()
จะทริกเกอร์เมื่อสร้างข้อมูลใน Realtime Database เท่านั้นon_value_updated()
จะทริกเกอร์เมื่อมีการอัปเดตข้อมูลใน Realtime Database เท่านั้นon_value_deleted()
จะทริกเกอร์เมื่อมีการลบข้อมูลใน Realtime Database เท่านั้น
นำเข้าโมดูลที่จำเป็น
ในแหล่งที่มาของฟังก์ชัน คุณต้องนําเข้าโมดูล SDK ที่ต้องการใช้ สำหรับ ตัวอย่างนี้ คุณต้องนำเข้าโมดูล HTTP และ Realtime Database พร้อมกับโมดูล Firebase Admin SDK เพื่อเขียนไปยัง 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()
ระบุอินสแตนซ์และเส้นทาง
หากต้องการควบคุมเวลาและตำแหน่งที่ควรเรียกใช้ฟังก์ชัน ให้กำหนดค่าฟังก์ชันด้วยเส้นทางและอินสแตนซ์ Realtime Database (ไม่บังคับ) หากคุณไม่ได้ ระบุอินสแตนซ์ ฟังก์ชันจะรับฟังRealtime Databaseอินสแตนซ์ทั้งหมด ในภูมิภาคของฟังก์ชัน นอกจากนี้ คุณยังระบุรูปแบบอินสแตนซ์ Realtime Database เพื่อทําการติดตั้งใช้งานกับชุดย่อยของอินสแตนซ์ที่เลือกในภูมิภาคเดียวกันได้ด้วย
เช่น
// 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
พารามิเตอร์เหล่านี้จะสั่งให้ฟังก์ชันจัดการการเขียนที่เส้นทางหนึ่งๆ ภายในอินสแตนซ์ Realtime Database
การระบุเส้นทางจะตรงกับการเขียนทั้งหมดที่แตะเส้นทาง รวมถึงการเขียนที่เกิดขึ้นที่ใดก็ตามด้านล่าง หากคุณตั้งค่าเส้นทาง
สำหรับฟังก์ชันเป็น /foo/bar
ระบบจะจับคู่เหตุการณ์ในทั้ง 2 ตำแหน่งต่อไปนี้
/foo/bar
/foo/bar/baz/really/deep/path
ไม่ว่าจะในกรณีใดก็ตาม Firebase จะตีความว่าเหตุการณ์เกิดขึ้นที่ /foo/bar
และข้อมูลเหตุการณ์จะมีข้อมูลเก่าและใหม่ที่ /foo/bar
หากข้อมูลเหตุการณ์
อาจมีขนาดใหญ่ ให้ลองใช้ฟังก์ชันหลายรายการในเส้นทางที่ลึกลงไปแทน
ฟังก์ชันเดียวที่อยู่ใกล้รูทของฐานข้อมูล ขอข้อมูลที่ระดับลึกที่สุดเท่าที่จะเป็นไปได้เท่านั้นเพื่อประสิทธิภาพที่ดีที่สุด
การใช้ไวลด์การ์ดและการจับภาพ
คุณใช้ {key}
, {key=*}
, {key=prefix*}
, {key=*suffix}
เพื่อจับภาพได้ *
, prefix*
, *suffix
สำหรับการใช้ไวลด์การ์ดแบบส่วนเดียว
หมายเหตุ: **
แสดงถึงการใช้ไวลด์การ์ดแบบหลายส่วน ซึ่ง Realtime Database ไม่รองรับ
ดูทำความเข้าใจรูปแบบเส้นทาง
การใช้ไวลด์การ์ดในเส้นทาง คุณระบุคอมโพเนนต์เส้นทางเป็นไวลด์การ์ดได้โดยทำดังนี้
- การใช้ดอกจัน
*
เช่นfoo/*
จะตรงกับลูกๆ ที่อยู่ต่ำกว่าfoo/
ในลำดับชั้นของโหนด 1 ระดับ - การใช้กลุ่มที่มีเครื่องหมายดอกจัน
*
เช่นfoo/app*-us
จะตรงกับกลุ่มย่อยใดก็ได้ด้านล่างfoo/
ที่มีคำนำหน้าapp
และคำต่อท้าย-us
เส้นทางที่มีไวลด์การ์ดจะจับคู่เหตุการณ์หลายรายการได้ เช่น จากการเขียนครั้งเดียว แทรก
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
จับคู่เส้นทาง "/foo/*"
2 ครั้ง โดยครั้งแรกใช้ "hello": "world"
และอีกครั้งใช้
"firebase": "functions"
การบันทึกเส้นทาง คุณสามารถบันทึกการจับคู่เส้นทางลงในตัวแปรที่มีชื่อเพื่อใช้
ในโค้ดฟังก์ชัน (เช่น /user/{uid}
, /user/{uid=*-us}
)
ค่าของตัวแปรการจับภาพจะอยู่ในออบเจ็กต์ database.DatabaseEvent.params ของฟังก์ชัน
การใช้สัญลักษณ์แทนของอินสแตนซ์ คุณยังระบุคอมโพเนนต์อินสแตนซ์
ได้โดยใช้ไวลด์การ์ด ไวลด์การ์ดอินสแตนซ์อาจมีคำนำหน้า คำต่อท้าย หรือทั้ง 2 อย่าง
(เช่น my-app-*-prod
)
การอ้างอิงไวลด์การ์ดและการจับภาพ
เมื่อใช้ Cloud Functions (รุ่นที่ 2) และ Realtime Database คุณจะใช้รูปแบบได้เมื่อระบุ 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*' ) |
ตัวแฮนเดิลขอบเขตไปยังอินสแตนซ์ทั้งหมดที่ตรงกับรูปแบบในภูมิภาคของฟังก์ชัน |
จัดการข้อมูลเหตุการณ์
เมื่อRealtime Databaseทริกเกอร์เหตุการณ์ ระบบจะส่งออบเจ็กต์ Event
ไปยังฟังก์ชันแฮนเดิล
ออบเจ็กต์นี้มีพร็อพเพอร์ตี้ data
ซึ่งสําหรับเหตุการณ์การสร้างและการลบ
จะมีสแนปชอตของข้อมูลที่สร้างหรือลบ
ในตัวอย่างนี้ ฟังก์ชันจะดึงข้อมูลสำหรับเส้นทางที่อ้างอิง แปลงสตริงในตำแหน่งนั้นเป็นตัวพิมพ์ใหญ่ และเขียนสตริงที่แก้ไขแล้วลงในฐานข้อมูล
// 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)
การอ่านค่าก่อนหน้า
สําหรับเหตุการณ์ write
หรือ update
พร็อพเพอร์ตี้ data
คือออบเจ็กต์ Change
ที่มีสแนปชอต 2 รายการ
ซึ่งแสดงสถานะข้อมูลก่อนและหลังเหตุการณ์ที่ทริกเกอร์
ออบเจ็กต์ Change
มีพร็อพเพอร์ตี้ before
ที่ช่วยให้คุณตรวจสอบสิ่งที่บันทึกไว้ใน Realtime Database ก่อนเกิดเหตุการณ์ และพร็อพเพอร์ตี้ after
ที่แสดงสถานะของข้อมูลหลังจากเกิดเหตุการณ์
เช่น คุณใช้พร็อพเพอร์ตี้ 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); });
@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)