Với Cloud Functions, bạn có thể triển khai mã để xử lý các sự kiện do các thay đổi trong Cloud Firestore kích hoạt bằng cơ sở dữ liệu tương thích với MongoDB. Điều này cho phép bạn 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.
Cloud Functions (thế hệ thứ 2)
Được hỗ trợ bởi Cloud Run và Eventarc, Cloud Functions for Firebase (thế hệ thứ 2) mang đến cho bạn cơ sở hạ tầng mạnh mẽ hơn, khả năng kiểm soát nâng cao đối với hiệu suất và khả năng mở rộng, cũng như khả năng kiểm soát nhiều hơn đối với thời gian chạy của các hàm. Để biết thêm thông tin về thế hệ thứ 2, hãy xem bài viết Cloud Functions cho Firebase (thế hệ thứ 2).
Cloud Firestore có các trình kích hoạt hàm tương thích với MongoDB
SDK Cloud Functions for Firebase xuất các trình kích hoạt sự kiện Cloud Firestore sau đây có khả năng tương thích với MongoDB để cho phép bạn tạo các trình xử lý được liên kết với các sự kiện Cloud Firestore cụ thể có khả năng tương thích với MongoDB:
Node.js
| Loại sự kiện | Điều kiện kích hoạt |
|---|---|
onDocumentCreated |
Được kích hoạt khi một tài liệu được ghi lần đầu tiên. |
onDocumentUpdated |
Đượ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 thay đổi. |
onDocumentDeleted |
Được kích hoạt khi một tài liệu bị xoá. |
onDocumentWritten |
Được kích hoạt khi onDocumentCreated, onDocumentUpdated hoặc onDocumentDeleted được kích hoạt. |
onDocumentCreatedWithAuthContext |
onDocumentCreated cùng thông tin xác thực bổ sung |
onDocumentWrittenWithAuthContext |
onDocumentWritten cùng thông tin xác thực bổ sung |
onDocumentDeletedWithAuthContext |
onDocumentDeleted cùng thông tin xác thực bổ sung |
onDocumentUpdatedWithAuthContext |
onDocumentUpdated cùng thông tin xác thực bổ sung |
Python
| Loại sự kiện | Điều kiện kích hoạt |
|---|---|
on_document_created |
Được kích hoạt khi một tài liệu được ghi lần đầu tiên. |
on_document_updated |
Đượ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 thay đổi. |
on_document_deleted |
Được kích hoạt khi một tài liệu bị xoá. |
on_document_written |
Được kích hoạt khi on_document_created, on_document_updated hoặc on_document_deleted được kích hoạt. |
on_document_created_with_auth_context |
on_document_created cùng thông tin xác thực bổ sung |
on_document_updated_with_auth_context |
on_document_updated cùng thông tin xác thực bổ sung |
on_document_deleted_with_auth_context |
on_document_deleted cùng thông tin xác thực bổ sung |
on_document_written_with_auth_context |
on_document_written cùng thông tin xác thực bổ sung |
Các sự kiện Cloud Firestore có khả năng tương thích với MongoDB chỉ kích hoạt khi có thay đổi về tài liệu. Bản cập nhật cho tài liệu Cloud Firestore có khả năng tương thích với MongoDB mà dữ liệu không thay đổi (thao tác ghi không có hiệu lực) sẽ không tạo ra sự kiện cập nhật hoặc ghi. Bạn không thể thêm sự kiện vào các trường cụ thể.
Nếu bạn chưa bật dự án cho Cloud Functions for Firebase, hãy đọc bài viết Bắt đầu sử dụng Cloud Functions for Firebase (thế hệ thứ 2) để định cấu hình và thiết lập dự án Cloud Functions for Firebase.
Viết Cloud Firestore bằng các hàm tương thích với MongoDB
Xác định một trình kích hoạt hàm
Để xác định một điều kiện kích hoạt Cloud Firestore có khả năng tương thích với MongoDB, hãy chỉ định một đường dẫn tài liệu và một loại sự kiện:
Node.js
const {
onDocumentWritten,
onDocumentCreated,
onDocumentUpdated,
onDocumentDeleted,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.myfunction = onDocumentWritten("my-collection/{docId}", (event) => {
/* ... */
});
Python
from firebase_functions.firestore_fn import (
on_document_created,
on_document_deleted,
on_document_updated,
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_created(document="users/{userId}")
def myfunction(event: Event[DocumentSnapshot]) -> None:
Đường dẫn tài liệu có thể tham chiếu đến một tài liệu cụ thể hoặc 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ể dùng hàm sau.
Node.js
const {
onDocumentWritten,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.myfunction = onDocumentWritten("users/marie", (event) => {
// Your code here
});
Python
from firebase_functions.firestore_fn import (
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_written(document="users/marie")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
Chỉ định một nhóm tài liệu bằng ký tự đại diện
Nếu bạn muốn đính kèm một điều kiện 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ã nhận dạng tài liệu:
Node.js
const {
onDocumentWritten,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.myfunction = onDocumentWritten("users/{userId}", (event) => {
// If we set `/users/marie` to {name: "Marie"} then
// event.params.userId == "marie"
// ... and ...
// event.data.after.data() == {name: "Marie"}
});
Python
from firebase_functions.firestore_fn import (
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_written(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# If we set `/users/marie` to {name: "Marie"} then
event.params["userId"] == "marie" # True
# ... and ...
event.data.after.to_dict() == {"name": "Marie"} # True
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 thay đổi, trường đó sẽ khớp với một ký tự đại diện có tên là userId.
Các mẫu khớp ký tự đại diện được trích xuất từ đường dẫn tài liệu và lưu trữ vào event.params.
Điều kiện kích hoạt của bạn luôn phải trỏ đến một tài liệu, ngay cả khi bạn đang sử dụng ký tự đại diện.
Trình kích hoạt sự kiện
Kích hoạt một hàm khi có tài liệu mới được tạo
Bạn có thể kích hoạt một hàm để thực thi 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. Hàm ví dụ này kích hoạt mỗi khi một hồ sơ người dùng mới được thêm:
Node.js
const {
onDocumentCreated,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.createuser = onDocumentCreated("users/{userId}", (event) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const snapshot = event.data;
if (!snapshot) {
console.log("No data associated with the event");
return;
}
const data = snapshot.data();
// access a particular field as you would any JS property
const name = data.name;
// perform more operations ...
});
Để biết thêm thông tin xác thực, hãy sử dụng onDocumentCreatedWithAuthContext.
Python
from firebase_functions.firestore_fn import (
on_document_created,
Event,
DocumentSnapshot,
)
@on_document_created(document="users/{userId}")
def myfunction(event: Event[DocumentSnapshot]) -> None:
# Get a dictionary representing the document
# e.g. {'name': 'Marie', 'age': 66}
new_value = event.data.to_dict()
# Access a particular field as you would any dictionary
name = new_value["name"]
# Perform more operations ...
Kích hoạt một hàm khi 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. Hàm ví dụ này sẽ kích hoạt nếu người dùng thay đổi hồ sơ của họ:
Node.js
const {
onDocumentUpdated,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.updateuser = onDocumentUpdated("users/{userId}", (event) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const newValue = event.data.after.data();
// access a particular field as you would any JS property
const name = newValue.name;
// perform more operations ...
});
Để biết thêm thông tin xác thực, hãy sử dụng onDocumentUpdatedWithAuthContext.
Python
from firebase_functions.firestore_fn import (
on_document_updated,
Event,
Change,
DocumentSnapshot,
)
@on_document_updated(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# Get a dictionary representing the document
# e.g. {'name': 'Marie', 'age': 66}
new_value = event.data.after.to_dict()
# Access a particular field as you would any dictionary
name = new_value["name"]
# Perform more 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á. Hàm ví dụ này sẽ kích hoạt khi người dùng xoá hồ sơ người dùng của họ:
Node.js
const {
onDocumentDeleted,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.deleteuser = onDocumentDeleted("users/{userId}", (event) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const snap = event.data;
const data = snap.data();
// perform more operations ...
});
Để biết thêm thông tin xác thực, hãy sử dụng onDocumentDeletedWithAuthContext.
Python
from firebase_functions.firestore_fn import (
on_document_deleted,
Event,
DocumentSnapshot,
)
@on_document_deleted(document="users/{userId}")
def myfunction(event: Event[DocumentSnapshot|None]) -> None:
# Perform more 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 được kích hoạt, bạn có thể theo dõi mọi thay đổi trong một tài liệu Cloud Firestore có khả năng tương thích với MongoDB bằng trình kích hoạt sự kiện "document written" (tài liệu đã ghi). Hàm ví dụ này sẽ kích hoạt nếu người dùng được tạo, cập nhật hoặc xoá:
Node.js
const {
onDocumentWritten,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.modifyuser = onDocumentWritten("users/{userId}", (event) => {
// Get an object with the current document values.
// If the document does not exist, it was deleted
const document = event.data.after.data();
// Get an object with the previous document values
const previousValues = event.data.before.data();
// perform more operations ...
});
Để biết thêm thông tin xác thực, hãy sử dụng onDocumentWrittenWithAuthContext.
Python
from firebase_functions.firestore_fn import (
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_written(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot | None]]) -> None:
# Get an object with the current document values.
# If the document does not exist, it was deleted.
document = (event.data.after.to_dict()
if event.data.after is not None else None)
# Get an object with the previous document values.
# If the document does not exist, it was newly created.
previous_values = (event.data.before.to_dict()
if event.data.before is not None else None)
# Perform more 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 Firebase Admin SDK để 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 event.data.before. event.data.before chứa ảnh chụp nhanh tài liệu trước khi cập nhật.
Tương tự, event.data.after chứa trạng thái ảnh chụp nhanh của tài liệu sau khi cập nhật.
Node.js
exports.updateuser2 = onDocumentUpdated("users/{userId}", (event) => {
// Get an object with the current document values.
// If the document does not exist, it was deleted
const newValues = event.data.after.data();
// Get an object with the previous document values
const previousValues = event.data.before.data();
});
Python
@on_document_updated(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# Get an object with the current document values.
new_value = event.data.after.to_dict()
# Get an object with the previous document values.
prev_value = event.data.before.to_dict()
Bạn có thể truy cập vào các thuộc tính như trong mọi đối tượng khác. Ngoài ra, bạn có thể 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 = event.data.after.data().age;
const name = event.data.after.data()['name'];
// Fetch data using built in accessor
const experience = event.data.after.data.get('experience');
Python
# Get the value of a single document field.
age = event.data.after.get("age")
# Convert the document to a dictionary.
age = event.data.after.to_dict()["age"]
Ghi dữ liệu
Mỗi lần gọi hàm đều được liên kết với một tài liệu cụ thể trong Cloud Firestore có cơ sở dữ liệu tương thích với MongoDB. Bạn có thể truy cập vào tài liệu đó trong ảnh chụp nhanh được trả về cho hàm của bạn.
Tài liệu tham khảo bao gồm các phương thức như update(), set() và remove() để bạn có thể sửa đổi tài liệu đã kích hoạt hàm.
Node.js
const {onDocumentUpdated} = require('firebase-functions/v2/firestore');
exports.countnamechanges = onDocumentUpdated('users/{userId}', (event) => {
// Retrieve the current and previous value
const data = event.data.after.data();
const previousData = event.data.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 event.data.after.ref.set({
name_change_count: count + 1
}, {merge: true});
});
Python
@on_document_updated(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# Get the current and previous document values.
new_value = event.data.after
prev_value = event.data.before
# We'll only update if the name has changed.
# This is crucial to prevent infinite loops.
if new_value.get("name") == prev_value.get("name"):
return
# Retrieve the current count of name changes
count = new_value.to_dict().get("name_change_count", 0)
# Update the count
new_value.reference.update({"name_change_count": count + 1})
Truy cập vào thông tin xác thực người dùng
Nếu sử dụng một trong các loại sự kiện sau, bạn có thể truy cập vào thông tin xác thực người dùng về chủ thể đã kích hoạt sự kiện. Thông tin này bổ sung cho thông tin được trả về trong sự kiện cơ sở.
Node.js
onDocumentCreatedWithAuthContextonDocumentWrittenWithAuthContextonDocumentDeletedWithAuthContextonDocumentUpdatedWithAuthContext
Python
on_document_created_with_auth_contexton_document_updated_with_auth_contexton_document_deleted_with_auth_contexton_document_written_with_auth_context
Để biết thông tin về dữ liệu có trong bối cảnh xác thực, hãy xem phần Bối cảnh xác thực. Ví dụ sau đây minh hoạ cách truy xuất thông tin xác thực:
Node.js
const {onDocumentWrittenWithAuthContext} = require('firebase-functions/v2/firestore');
exports.syncUser = onDocumentWrittenWithAuthContext("users/{userId}", (event) => {
const snapshot = event.data.after;
if (!snapshot) {
console.log("No data associated with the event");
return;
}
const data = snapshot.data();
// retrieve auth context from event
const { authType, authId } = event;
let verified = false;
if (authType === "system") {
// system-generated users are automatically verified
verified = true;
} else if (authType === "unknown" || authType === "unauthenticated") {
// admin users from a specific domain are verified
if (authId.endsWith("@example.com")) {
verified = true;
}
}
return data.after.ref.set({
created_by: authId,
verified,
}, {merge: true});
});
Python
@on_document_updated_with_auth_context(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# Get the current and previous document values.
new_value = event.data.after
prev_value = event.data.before
# Get the auth context from the event
user_auth_type = event.auth_type
user_auth_id = event.auth_id
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. Chúng được uỷ quyền dưới dạng tài khoản dịch vụ trên dự án của bạn và bạn có thể thực hiện các thao tác đọc và ghi bằng Firebase Admin SDK:
Node.js
const { initializeApp } = require('firebase-admin/app');
const { getFirestore, Timestamp, FieldValue } = require('firebase-admin/firestore');
initializeApp();
const db = getFirestore();
exports.writetofirestore = onDocumentWritten("some/doc", (event) => {
db.doc('some/otherdoc').set({ ... });
});
exports.writetofirestore = onDocumentWritten('users/{userId}', (event) => {
db.doc('some/otherdoc').set({
// Update otherdoc
});
});
Python
from firebase_admin import firestore, initialize_app
import google.cloud.firestore
initialize_app()
@on_document_written(document="some/doc")
def myfunction(event: Event[Change[DocumentSnapshot | None]]) -> None:
firestore_client: google.cloud.firestore.Client = firestore.client()
firestore_client.document("another/doc").set({
# ...
})
Hạn chế
- 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 một thứ tự không mong muốn.
- Sự kiện được phân phối ít nhất một lần, nhưng một sự kiện duy nhất có thể dẫn đến nhiều lệnh gọi hàm. Tránh phụ thuộc vào cơ chế chỉ một lần và viết các hàm đẳng nhất.
- Một điều kiện kích hoạt được liên kết với một cơ sở dữ liệu duy nhất. Bạn không thể tạo một điều kiện 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á mọi điều kiện kích hoạt cho cơ sở dữ liệu đó. Điều kiện kích hoạt sẽ ngừng gửi sự kiện nhưng vẫn tồn tại cho đến khi bạn xoá điều kiện kích hoạt.