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 DatabaseonValueDeleted()
จะทริกเกอร์เฉพาะเมื่อมีการขลบข้อมูลใน Realtime Database
on_value_written()
ทริกเกอร์เมื่อสร้าง อัปเดต หรือลบข้อมูลใน Realtime Databaseon_value_created()
จะทริกเกอร์เมื่อสร้างข้อมูลใน Realtime Database เท่านั้นon_value_updated()
จะทริกเกอร์เฉพาะเมื่อมีอัปเดตข้อมูลใน Realtime Databaseon_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/*
จะจับคู่กับโหนดย่อยระดับ 1 ของลําดับชั้นโหนดที่อยู่ด้านล่างfoo/
- การใช้กลุ่มที่มีเครื่องหมายดอกจัน
*
เท่านั้น เช่นfoo/app*-us
จะจับคู่กับกลุ่มย่อยที่อยู่ใต้foo/
ที่มีคำนำหน้าapp
และคำต่อท้าย-us
เส้นทางที่มีไวลด์การ์ดจะจับคู่กับเหตุการณ์หลายรายการได้ เช่น การเขียนครั้งเดียว แทรกของ
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
จับคู่เส้นทาง "/foo/*"
2 ครั้ง ได้แก่ 1 ครั้งกับ "hello": "world"
และอีก 1 ครั้งกับ "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)