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 hoạt động Realtime Database bằng quyền quản trị toàn diện
đặc quyền và đảm bảo rằng mọi thay đổi đối với Realtime Database đều được xử lý
riêng lẻ. Bạn có thể thực hiện Firebase Realtime Database thay đổi thông qua
DataSnapshot
hoặc thông qua SDK dành cho quản trị viên.
Trong 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 vị trí Realtime Database cụ thể.
- Kích hoạt khi một sự kiện xảy ra và thực hiện các nhiệm vụ của sự kiện đó (xem phần Tôi có thể làm gì) với Cloud Functions? để có ví dụ về trường hợp sử dụng).
- Nhận một đối tượng dữ liệu chứa ảnh chụp nhanh về dữ liệu được lưu trữ trong tài liệu được chỉ định.
Kích hoạt hàm Realtime Database
Tạo hàm mới cho sự kiện Realtime Database
cùng với functions.database
. Người nhận
kiểm soát thời điểm chức năng này kích hoạt, chỉ định một trong các trình xử lý sự kiện và
chỉ định đường dẫn Realtime Database nơi ứng dụng sẽ theo dõi các sự kiện.
Thiết lập trình xử lý sự kiện
Các 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ể nghe riêng để tạo, cập nhật, hoặc xoá sự kiện hoặc bạn có thể theo dõi mọi thay đổi dưới bất kỳ hình thức nào đối với đường dẫn. Cloud Functions hỗ trợ các trình xử lý sự kiện sau cho Realtime Database:
onWrite()
, kích hoạt khi dữ liệu được tạo, cập nhật hoặc xoá trong Realtime Database.onCreate()
, kích hoạt khi dữ liệu mới được tạo trong Realtime Database.onUpdate()
, kích hoạt khi dữ liệu được cập nhật trong Realtime Database .onDelete()
sẽ kích hoạt khi dữ liệu bị xoá khỏi Realtime Database .
Chỉ định thực thể và đường dẫn
Để kiểm soát thời điểm và vị trí hàm của bạn sẽ kích hoạt, hãy gọi ref(path)
để chỉ định một đường dẫn và tuỳ ý chỉ định một thực thể Realtime Database
cùng với instance('INSTANCE_NAME')
. Nếu bạn không
chỉ định một thực thể, hàm này sẽ triển khai cho thực thể Realtime Database mặc định cho
dự án Firebase. Ví dụ:
- Phiên bản Realtime Database mặc định:
functions.database.ref('/foo/bar')
- Thực thể có tên là "my-app-db-2":
functions.database.instance('my-app-db-2').ref('/foo/bar')
Các phương thức này hướng dẫn hàm của bạn xử lý các lượt ghi tại 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ả các bản ghi chạm vào một đường dẫn,
bao gồm hoạt động ghi
xảy ra ở bất kỳ vị trí nào bên dưới nó. Nếu bạn thiết lập đường dẫn
cho hàm của bạn dưới dạng /foo/bar
, nó khớp với các sự kiện ở cả hai vị trí sau:
/foo/bar
/foo/bar/baz/really/deep/path
Trong cả hai trường hợp, Firebase 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 ở những đường dẫn sâu hơn thay vì một hàm
gần gốc của cơ sở dữ liệu. Để 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ể.
Bạn có thể chỉ định một thành phần đường dẫn làm ký tự đại diện bằng cách đặt thành phần đó bằng dấu ngoặc nhọn
dấu ngoặc; ref('foo/{bar}')
khớp với mọi phần tử con của /foo
. Giá trị của những thuộc tính này
có sẵn các thành phần đường dẫn ký tự đại diện trong
EventContext.params
đối tượng của hàm. Trong ví dụ này, giá trị được cung cấp là
context.params.bar
.
Đường dẫn chứa ký tự đại diện có thể khớp với nhiều sự kiện từ một lần ghi. Phụ trang của
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
khớp với đường dẫn "/foo/{bar}"
hai lần: một lần với "hello": "world"
và một lần nữa với "firebase": "functions"
.
Xử lý dữ liệu sự kiện
Khi xử lý sự kiện Realtime Database, đối tượng dữ liệu được trả về là một
DataSnapshot
.
Đối với các sự kiện onWrite
hoặc onUpdate
, phương thức
tham số đầu tiên là đối tượng Change
chứa hai ảnh chụp nhanh
biểu thị trạng thái dữ liệu trước khi
và sau sự kiện kích hoạt. Đối với các sự kiện onCreate
và onDelete
:
đối tượng dữ liệu được trả về là thông tin tổng quan nhanh về dữ liệu được tạo hoặc bị xoá.
Trong ví dụ này, hàm truy xuất ảnh chụp nhanh cho đường dẫn đã chỉ định, chuyển đổi chuỗi ở vị trí đó thành chữ viết 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 exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') .onCreate((snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); functions.logger.log('Uppercasing', context.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 snapshot.ref.parent.child('uppercase').set(uppercase); });
Truy cập thông tin xác thực người dùng
Từ EventContext.auth
và EventContext.authType
,
bạn có thể truy cập
thông tin người dùng, bao gồm cả các quyền, đối với người dùng đã kích hoạt
một hàm. Điều này có thể hữu ích cho việc thực thi các quy tắc bảo mật,
cho phép chức năng của bạn hoàn tất các hoạt động khác nhau dựa trên
cấp quyền:
const functions = require('firebase-functions/v1');
const admin = require('firebase-admin');
exports.simpleDbFunction = functions.database.ref('/path')
.onCreate((snap, context) => {
if (context.authType === 'ADMIN') {
// do something
} else if (context.authType === 'USER') {
console.log(snap.val(), 'written by', context.auth.uid);
}
});
Ngoài ra, bạn có thể tận dụng thông tin xác thực người dùng để "mạo danh" một người dùng và thực hiện các thao tác ghi thay mặt người dùng. Hãy nhớ xoá phiên bản ứng dụng như trình bày dưới đây nhằm ngăn chặn các vấn đề đồng thời:
exports.impersonateMakeUpperCase = functions.database.ref('/messages/{pushId}/original')
.onCreate((snap, context) => {
const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
appOptions.databaseAuthVariableOverride = context.auth;
const app = admin.initializeApp(appOptions, 'app');
const uppercase = snap.val().toUpperCase();
const ref = snap.ref.parent.child('uppercase');
const deleteApp = () => app.delete().catch(() => null);
return app.database().ref(ref).set(uppercase).then(res => {
// Deleting the app is necessary for preventing concurrency leaks
return deleteApp().then(() => res);
}).catch(err => {
return deleteApp().then(() => Promise.reject(err));
});
});
Đọc giá trị trước
Đối tượng Change
có
before
cho phép bạn kiểm tra nội dung đã lưu vào Realtime Database trước
sự kiện. Thuộc tính before
trả về DataSnapshot
trong đó tất cả
(ví dụ:
val()
và
exists()
)
tham chiếu đến giá trị trước đó. Bạn có thể đọc lại giá trị mới bằng cách sử dụng
DataSnapshot
gốc hoặc đọc
after
thuộc tính này. Thuộc tính này trên bất kỳ Change
nào cũng là một DataSnapshot
khác đại diện cho
trạng thái của dữ liệu sau khi sự kiện xảy ra.
Ví dụ: bạn có thể dùng thuộc tính before
để đảm bảo hàm này chỉ
viết hoa văn bản khi tạo lần đầu:
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onWrite((change, context) => {
// Only edit data when it is first created.
if (change.before.exists()) {
return null;
}
// Exit when the data is deleted.
if (!change.after.exists()) {
return null;
}
// Grab the current value of what was written to the Realtime Database.
const original = change.after.val();
console.log('Uppercasing', context.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 change.after.ref.parent.child('uppercase').set(uppercase);
});