Với Cloud Functions, bạn có thể xử lý các sự kiện trong Firebase Realtime Database mà không cần cập nhật mã ứng dụng. Cloud Functions cho phép bạn chạy các thao tác Realtime Database với đầy đủ các đặc quyền quản trị và đảm bảo rằng từng thay đổi đối với Realtime Database được xử lý riêng lẻ. Bạn có thể thực hiện các thay đổi đối với Firebase Realtime Database thông qua ảnh chụp nhanh dữ liệu hoặc thông qua SDK dành cho quản trị viên.
Trong một vòng đời thông thường, hàm Firebase Realtime Database thực hiện những việc sau:
- Chờ các thay đổi đối với một đường dẫn Realtime Database cụ thể.
- Kích hoạt khi một sự kiện xảy ra và thực hiện các tác vụ của sự kiện đó.
- Nhận một đối tượng dữ liệu chứa ảnh chụp nhanh của dữ liệu được lưu trữ tại đường dẫn đó.
Bạn có thể kích hoạt một hàm để phản hồi việc ghi, tạo, cập nhật hoặc xoá các nút cơ sở dữ liệu trong Firebase Realtime Database. Để kiểm soát thời điểm hàm kích hoạt, hãy chỉ định một trong các trình xử lý sự kiện và chỉ định đường dẫn Realtime Database nơi hàm sẽ nghe các sự kiện.
Đặt vị trí hàm
Khoảng cách giữa vị trí của một thực thể Realtime Database và vị trí của hàm có thể tạo ra độ trễ mạng đáng kể. Ngoài ra, việc không khớp giữa các khu vực có thể dẫn đến việc triển khai không thành công. Để tránh những trường hợp này, hãy chỉ định vị trí hàm sao cho khớp với vị trí thực thể cơ sở dữ liệu.
Xử lý sự kiện Realtime Database
Hàm cho phép bạn xử lý các sự kiện Realtime Database ở hai cấp độ cụ thể; bạn có thể chỉ theo dõi các sự kiện ghi, tạo, cập nhật hoặc xoá, hoặc bạn có thể theo dõi mọi thay đổi thuộc bất kỳ loại nào đối với một tệp tham chiếu.
Các trình xử lý sau đây để phản hồi sự kiện Realtime Database:
onValueWritten()
Được kích hoạt khi dữ liệu được tạo, cập nhật hoặc xoá trong Realtime Database.onValueCreated()
Chỉ được kích hoạt khi dữ liệu được tạo trong Realtime Database.onValueUpdated()
Chỉ được kích hoạt khi dữ liệu được cập nhật trong Realtime Database.onValueDeleted()
Chỉ được kích hoạt khi dữ liệu bị xoá trong Realtime Database.
on_value_written()
Được kích hoạt khi dữ liệu được tạo, cập nhật hoặc xoá trong Realtime Database.on_value_created()
Chỉ được kích hoạt khi dữ liệu được tạo trong Realtime Database.on_value_updated()
Chỉ được kích hoạt khi dữ liệu được cập nhật trong Realtime Database.on_value_deleted()
Chỉ được kích hoạt khi dữ liệu bị xoá trong Realtime Database.
Nhập các mô-đun bắt buộc
Trong nguồn hàm, bạn phải nhập các mô-đun SDK mà bạn muốn sử dụng. Đối với mẫu này, bạn cần nhập các mô-đun HTTP và Realtime Database cùng với mô-đun Firebase Admin SDK để ghi vào 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()
Chỉ định thực thể và đường dẫn
Để kiểm soát thời điểm và vị trí kích hoạt hàm, hãy định cấu hình hàm bằng một đường dẫn và tuỳ chọn là một thực thể Realtime Database. Nếu bạn không chỉ định một thực thể, hàm sẽ nghe tất cả các thực thể Realtime Database trong vùng hàm. Bạn cũng có thể chỉ định mẫu thực thể Realtime Database để triển khai cho một nhóm nhỏ các thực thể được chọn trong cùng một khu vực.
Ví dụ:
// 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
Các tham số này hướng dẫn hàm của bạn xử lý các hoạt động ghi ở một đường dẫn nhất định trong thực thể Realtime Database.
Thông số kỹ thuật của đường dẫn khớp với tất cả hoạt động ghi chạm vào một đường dẫn, bao gồm cả hoạt động ghi xảy ra ở bất kỳ vị trí nào bên dưới đường dẫn đó. Nếu bạn đặt đường dẫn cho hàm là /foo/bar
, thì hàm này sẽ so khớp các sự kiện ở cả hai vị trí này:
/foo/bar
/foo/bar/baz/really/deep/path
Trong cả hai trường hợp, Firebase sẽ diễn giải rằng sự kiện xảy ra tại /foo/bar
và dữ liệu sự kiện bao gồm dữ liệu cũ và mới tại /foo/bar
. Nếu dữ liệu sự kiện có thể lớn, hãy cân nhắc sử dụng nhiều hàm ở các đường dẫn sâu hơn thay vì một hàm duy nhất gần gốc cơ sở dữ liệu. Để đạt được hiệu suất tốt nhất, chỉ yêu cầu dữ liệu ở cấp độ sâu nhất có thể.
Ký tự đại diện và thu thập
Bạn có thể sử dụng {key}
, {key=*}
, {key=prefix*}
, {key=*suffix}
để chụp. *
, prefix*
, *suffix
cho ký tự đại diện một đoạn.
Lưu ý: **
đại diện cho ký tự đại diện nhiều phân đoạn mà Realtime Database không hỗ trợ.
Xem phần Tìm hiểu về mẫu đường dẫn.
Thay thế ký tự đại diện cho đường dẫn. Bạn có thể chỉ định một thành phần đường dẫn làm ký tự đại diện:
- Sử dụng dấu hoa thị,
*
. Ví dụ:foo/*
khớp với mọi thành phần con ở một cấp của hệ phân cấp nút bên dướifoo/
. - Sử dụng một phân đoạn chứa đúng dấu hoa thị,
*
. Ví dụ:foo/app*-us
khớp với mọi phân đoạn con bên dướifoo/
có tiền tốapp
và hậu tố-us
.
Các đường dẫn có ký tự đại diện có thể khớp với nhiều sự kiện, chẳng hạn như một lần ghi. Phần chèn
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
khớp với đường dẫn "/foo/*"
hai lần: một lần với "hello": "world"
và một lần nữa với "firebase": "functions"
.
Ghi lại đường dẫn. Bạn có thể ghi lại các kết quả khớp đường dẫn vào các biến có tên để sử dụng trong mã hàm (ví dụ: /user/{uid}
, /user/{uid=*-us}
).
Giá trị của các biến thu thập được có trong đối tượng database.DatabaseEvent.params của hàm.
Tính năng ký tự đại diện cho thực thể. Bạn cũng có thể chỉ định một thành phần thực thể bằng cách sử dụng ký tự đại diện. Ký tự đại diện của thực thể có thể có tiền tố, hậu tố hoặc cả hai (ví dụ: my-app-*-prod
).
Tham chiếu ký tự đại diện và tham chiếu thu thập
Với Cloud Functions (thế hệ 2) và Realtime Database, bạn có thể sử dụng mẫu khi chỉ định ref
và instance
. Mỗi giao diện điều kiện kích hoạt sẽ có các tuỳ chọn sau đây để xác định phạm vi của một hàm:
Chỉ định ref |
Chỉ định instance |
Hành vi |
---|---|---|
Đơn (/foo/bar ) |
Không chỉ định | Phạm vi trình xử lý cho tất cả các thực thể trong vùng hàm. |
Đơn (/foo/bar ) |
Đơn (‘my-new-db' ) |
Giới hạn trình xử lý đến thực thể cụ thể trong vùng chức năng. |
Đơn (/foo/bar ) |
Mẫu (‘inst-prefix*' ) |
Phạm vi trình xử lý cho tất cả các thực thể khớp với mẫu trong vùng hàm. |
Mẫu (/foo/{bar} ) |
Không chỉ định | Phạm vi trình xử lý cho tất cả các thực thể trong vùng hàm. |
Mẫu (/foo/{bar} ) |
Đơn (‘my-new-db' ) |
Giới hạn trình xử lý đến thực thể cụ thể trong vùng chức năng. |
Mẫu (/foo/{bar} ) |
Mẫu (‘inst-prefix*' ) |
Phạm vi trình xử lý cho tất cả các thực thể khớp với mẫu trong vùng hàm. |
Xử lý dữ liệu sự kiện
Khi một sự kiện Realtime Database kích hoạt, sự kiện đó sẽ truyền một đối tượng Event
đến hàm xử lý của bạn.
Đối tượng này có một thuộc tính data
. Đối với các sự kiện tạo và xoá, thuộc tính này chứa ảnh chụp nhanh của dữ liệu đã tạo hoặc đã xoá.
Trong ví dụ này, hàm truy xuất dữ liệu cho đường dẫn được tham chiếu, chuyển đổi chuỗi tại vị trí đó thành chữ hoa và ghi chuỗi đã sửa đổi đó vào cơ sở dữ liệu:
// 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)
Đọc giá trị trước đó
Đối với sự kiện write
hoặc update
, thuộc tính data
là một đối tượng Change
chứa hai ảnh chụp nhanh đại diện cho trạng thái dữ liệu trước và sau khi kích hoạt sự kiện.
Đối tượng Change
có thuộc tính before
cho phép bạn kiểm tra nội dung đã được lưu vào Realtime Database trước sự kiện và thuộc tính after
thể hiện trạng thái của dữ liệu sau khi sự kiện xảy ra.
Ví dụ: bạn có thể sử dụng thuộc tính before
để đảm bảo hàm chỉ viết hoa văn bản khi được tạo lần đầu:
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)