Với Cloud Functions, bạn có thể triển khai mã Node.js để xử lý các sự kiện được kích hoạt do những thay đổi trong cơ sở dữ liệu Cloud Firestore. Điều này cho phép bạn dễ dàng thêm chức năng phía máy chủ vào ứng dụng mà không cần chạy máy chủ của riêng mình.
Để xem ví dụ về các trường hợp sử dụng, hãy xem bài viết Tôi có thể làm gì với Cloud Functions? hoặc kho lưu trữ Mẫu hàm trên GitHub.
Cloud Firestore trình kích hoạt hàm
SDK Cloud Functions for Firebase xuất một đối tượng functions.firestore
cho phép bạn tạo trình xử lý được liên kết với các sự kiện Cloud Firestore cụ thể.
| Loại sự kiện | Điều kiện kích hoạt |
|---|---|
onCreate |
Được kích hoạt khi một tài liệu được ghi lần đầu tiên. |
onUpdate |
Được kích hoạt khi một tài liệu đã tồn tại và có bất kỳ giá trị nào bị thay đổi. |
onDelete |
Được kích hoạt khi một tài liệu có dữ liệu bị xoá. |
onWrite |
Được kích hoạt khi onCreate, onUpdate hoặc onDelete được kích hoạt. |
Nếu bạn chưa bật một dự án cho Cloud Functions for Firebase, hãy đọc Bắt đầu: Viết và triển khai hàm đầu tiên để định cấu hình và thiết lập dự án Cloud Functions for Firebase.
Viết các hàm được kích hoạt bằng Cloud Firestore
Xác định trình kích hoạt hàm
Để xác định trình kích hoạt Cloud Firestore, hãy chỉ định đường dẫn tài liệu và loại sự kiện:
Node.js
const functions = require('firebase-functions');
exports.myFunction = functions.firestore
.document('my-collection/{docId}')
.onWrite((change, context) => { /* ... */ });
Đường dẫn tài liệu có thể tham chiếu đến một tài liệu cụ thể hoặc một mẫu ký tự đại diện.
Chỉ định một tài liệu
Nếu muốn kích hoạt một sự kiện cho bất kỳ thay đổi nào đối với một tài liệu cụ thể, bạn có thể sử dụng hàm sau.
Node.js
// Listen for any change on document `marie` in collection `users` exports.myFunctionName = functions.firestore .document('users/marie').onWrite((change, context) => { // ... Your code here });
Chỉ định một nhóm tài liệu bằng ký tự đại diện
Nếu muốn đính kèm một trình kích hoạt vào một nhóm tài liệu, chẳng hạn như bất kỳ tài liệu nào trong một bộ sưu tập nhất định, hãy sử dụng {wildcard} thay cho mã tài liệu:
Node.js
// Listen for changes in all documents in the 'users' collection exports.useWildcard = functions.firestore .document('users/{userId}') .onWrite((change, context) => { // If we set `/users/marie` to {name: "Marie"} then // context.params.userId == "marie" // ... and ... // change.after.data() == {name: "Marie"} });
Trong ví dụ này, khi bất kỳ trường nào trên bất kỳ tài liệu nào trong users bị thay đổi, trường đó sẽ khớp với một ký tự đại diện có tên là userId.
Nếu một tài liệu trong users có các bộ sưu tập con và một trường trong một trong các tài liệu của bộ sưu tập con đó bị thay đổi, thì ký tự đại diện userId sẽ không được kích hoạt.
Các kết quả khớp ký tự đại diện được trích xuất từ đường dẫn tài liệu và được lưu trữ trong context.params.
Bạn có thể xác định bao nhiêu ký tự đại diện tuỳ thích để thay thế mã bộ sưu tập hoặc mã tài liệu rõ ràng, ví dụ:
Node.js
// Listen for changes in all documents in the 'users' collection and all subcollections exports.useMultipleWildcards = functions.firestore .document('users/{userId}/{messageCollectionId}/{messageId}') .onWrite((change, context) => { // If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then // context.params.userId == "marie"; // context.params.messageCollectionId == "incoming_messages"; // context.params.messageId == "134"; // ... and ... // change.after.data() == {body: "Hello"} });
Trình kích hoạt sự kiện
Kích hoạt một hàm khi một tài liệu mới được tạo
Bạn có thể kích hoạt một hàm để kích hoạt bất cứ khi nào một tài liệu mới được tạo trong một bộ sưu tập
bằng cách sử dụng trình xử lý onCreate() với ký tự đại diện.
Hàm ví dụ này gọi createUser mỗi khi một hồ sơ người dùng mới được thêm:
Node.js
exports.createUser = functions.firestore .document('users/{userId}') .onCreate((snap, context) => { // Get an object representing the document // e.g. {'name': 'Marie', 'age': 66} const newValue = snap.data(); // access a particular field as you would any JS property const name = newValue.name; // perform desired operations ... });
Kích hoạt một hàm khi một tài liệu được cập nhật
Bạn cũng có thể kích hoạt một hàm để kích hoạt khi một tài liệu được cập nhật bằng hàm
onUpdate() với một ký tự đại diện. Hàm ví dụ này gọi updateUser nếu người dùng thay đổi hồ sơ của họ:
Node.js
exports.updateUser = functions.firestore .document('users/{userId}') .onUpdate((change, context) => { // Get an object representing the document // e.g. {'name': 'Marie', 'age': 66} const newValue = change.after.data(); // ...or the previous value before this update const previousValue = change.before.data(); // access a particular field as you would any JS property const name = newValue.name; // perform desired operations ... });
Kích hoạt một hàm khi một tài liệu bị xoá
Bạn cũng có thể kích hoạt một hàm khi một tài liệu bị xoá bằng hàm
onDelete() với ký tự đại diện. Hàm ví dụ này gọi deleteUser khi người dùng xoá hồ sơ người dùng của họ:
Node.js
exports.deleteUser = functions.firestore .document('users/{userID}') .onDelete((snap, context) => { // Get an object representing the document prior to deletion // e.g. {'name': 'Marie', 'age': 66} const deletedValue = snap.data(); // perform desired operations ... });
Kích hoạt một hàm cho tất cả các thay đổi đối với một tài liệu
Nếu không quan tâm đến loại sự kiện đang được kích hoạt, bạn có thể theo dõi tất cả
các thay đổi trong một Cloud Firestore tài liệu bằng hàm onWrite()
với ký tự đại diện. Hàm ví dụ này gọi modifyUser nếu người dùng được tạo, cập nhật hoặc xoá:
Node.js
exports.modifyUser = functions.firestore .document('users/{userID}') .onWrite((change, context) => { // Get an object with the current document value. // If the document does not exist, it has been deleted. const document = change.after.exists ? change.after.data() : null; // Get an object with the previous document value (for update or delete) const oldDocument = change.before.data(); // perform desired operations ... });
Đọc và ghi dữ liệu
Khi một hàm được kích hoạt, hàm đó sẽ cung cấp ảnh chụp nhanh dữ liệu liên quan đến sự kiện. Bạn có thể sử dụng ảnh chụp nhanh này để đọc hoặc ghi vào tài liệu đã kích hoạt sự kiện, hoặc sử dụng SDK của Firebase dành cho quản trị viên để truy cập vào các phần khác của cơ sở dữ liệu.
Dữ liệu sự kiện
Đọc dữ liệu
Khi một hàm được kích hoạt, bạn có thể muốn lấy dữ liệu từ một tài liệu đã được cập nhật hoặc lấy dữ liệu trước khi cập nhật. Bạn có thể lấy dữ liệu trước đó bằng cách sử dụng change.before.data(), chứa ảnh chụp nhanh tài liệu trước khi cập nhật.
Tương tự, change.after.data() chứa trạng thái ảnh chụp nhanh tài liệu sau khi cập nhật.
Node.js
exports.updateUser2 = functions.firestore .document('users/{userId}') .onUpdate((change, context) => { // Get an object representing the current document const newValue = change.after.data(); // ...or the previous value before this update const previousValue = change.before.data(); });
Bạn có thể truy cập vào các thuộc tính như trong bất kỳ đối tượng nào khác. Ngoài ra, bạn có thể sử dụng hàm get để truy cập vào các trường cụ thể:
Node.js
// Fetch data using standard accessors const age = snap.data().age; const name = snap.data()['name']; // Fetch data using built in accessor const experience = snap.get('experience');
Ghi dữ liệu
Mỗi lệnh gọi hàm được liên kết với một tài liệu cụ thể trong cơ sở dữ liệu của bạn
Cloud Firestore. Bạn có thể truy cập vào tài liệu đó dưới dạng DocumentReference trong thuộc tính ref của ảnh chụp nhanh được trả về cho hàm của bạn.
DocumentReference này đến từ
Cloud Firestore Node.js SDK
và bao gồm các phương thức như update(), set() và remove() để bạn có thể dễ dàng
sửa đổi tài liệu đã kích hoạt hàm.
Node.js
// Listen for updates to any `user` document. exports.countNameChanges = functions.firestore .document('users/{userId}') .onUpdate((change, context) => { // Retrieve the current and previous value const data = change.after.data(); const previousData = change.before.data(); // We'll only update if the name has changed. // This is crucial to prevent infinite loops. if (data.name == previousData.name) { return null; } // Retrieve the current count of name changes let count = data.name_change_count; if (!count) { count = 0; } // Then return a promise of a set operation to update the count return change.after.ref.set({ name_change_count: count + 1 }, {merge: true}); });
Dữ liệu bên ngoài sự kiện kích hoạt
Cloud Functions thực thi trong một môi trường đáng tin cậy, nghĩa là các hàm này được uỷ quyền dưới dạng tài khoản dịch vụ trên dự án của bạn. Bạn có thể thực hiện các thao tác đọc và ghi bằng SDK của Firebase dành cho quản trị viên:
Node.js
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.writeToFirestore = functions.firestore
.document('some/doc')
.onWrite((change, context) => {
db.doc('some/otherdoc').set({ ... });
});
Hạn chế
Hãy lưu ý các hạn chế sau đối với trình kích hoạt Cloud Firestore cho Cloud Functions:
- Cloud Functions (thế hệ thứ 1) có điều kiện tiên quyết là một cơ sở dữ liệu "(default)" hiện có ở chế độ gốc của Firestore. Hàm này không hỗ trợ Cloud Firestore cơ sở dữ liệu có tên hoặc chế độ Datastore. Vui lòng sử dụng Cloud Functions (thế hệ thứ 2) để định cấu hình các sự kiện trong những trường hợp như vậy.
- Việc thiết lập dự án chéo với Cloud Functions và trình kích hoạt Cloud Firestore là một hạn chế. Để thiết lập trình kích hoạt Cloud Firestore, Cloud Functions phải nằm trong cùng một dự án.
- Không đảm bảo thứ tự. Những thay đổi nhanh chóng có thể kích hoạt lệnh gọi hàm theo thứ tự không mong muốn.
- Các sự kiện được gửi ít nhất một lần, nhưng một sự kiện có thể dẫn đến nhiều lệnh gọi hàm. Tránh phụ thuộc vào cơ chế chính xác một lần và viết các hàm bất biến.
- Cloud Firestore ở chế độ Datastore yêu cầu Cloud Functions (thế hệ thứ 2). Cloud Functions (thế hệ thứ 1) không hỗ trợ chế độ Datastore.
- Một trình kích hoạt được liên kết với một cơ sở dữ liệu. Bạn không thể tạo một trình kích hoạt khớp với nhiều cơ sở dữ liệu.
- Việc xoá một cơ sở dữ liệu không tự động xoá bất kỳ trình kích hoạt nào cho cơ sở dữ liệu đó. Trình kích hoạt ngừng gửi sự kiện nhưng vẫn tồn tại cho đến khi bạn xoá trình kích hoạt.
- Nếu một sự kiện được so khớp vượt quá kích thước yêu cầu tối đa, thì sự kiện đó có thể không được gửi đến Cloud Functions (thế hệ thứ 1).
- Các sự kiện không được gửi do kích thước yêu cầu được ghi lại trong nhật ký nền tảng và được tính vào mức sử dụng nhật ký cho dự án.
- Bạn có thể tìm thấy các nhật ký này trong Trình khám phá nhật ký với thông báo "Event cannot deliver to
Cloud function due to size exceeding the limit for thế hệ thứ 1..." ở mức độ nghiêm trọng
error. Bạn có thể tìm thấy tên hàm trong trườngfunctionName. Nếu trườngreceiveTimestampvẫn nằm trong vòng một giờ kể từ bây giờ, bạn có thể suy ra nội dung sự kiện thực tế bằng cách đọc tài liệu đang được đề cập bằng ảnh chụp nhanh trước và sau dấu thời gian. - Để tránh nhịp độ bước chân như vậy, bạn có thể:
- Di chuyển và nâng cấp lên Cloud Functions (thế hệ thứ 2)
- Giảm kích thước tài liệu
- Xoá Cloud Functions đang được đề cập
- Bạn có thể tắt tính năng ghi nhật ký bằng cách sử dụng loại trừ nhưng lưu ý rằng các sự kiện vi phạm vẫn sẽ không được gửi.