با استفاده Cloud Functions ، میتوانید رویدادها را در Cloud Firestore بدون نیاز به بهروزرسانی کد کلاینت مدیریت کنید. میتوانید تغییرات Cloud Firestore را از طریق رابط عکس فوری سند یا از طریق Admin SDK انجام دهید.
در یک چرخه عمر معمولی، یک تابع Cloud Firestore موارد زیر را انجام میدهد:
- منتظر تغییرات در یک سند خاص است.
- هنگام وقوع یک رویداد فعال میشود و وظایف خود را انجام میدهد.
- یک شیء داده دریافت میکند که شامل یک تصویر لحظهای از دادههای ذخیره شده در سند مشخص شده است. برای رویدادهای نوشتن یا بهروزرسانی، شیء داده شامل دو تصویر لحظهای است که وضعیت داده را قبل و بعد از رویداد آغازین نشان میدهند.
فاصله بین محل قرارگیری نمونه Firestore و محل قرارگیری تابع میتواند تأخیر قابل توجهی در شبکه ایجاد کند. برای بهینهسازی عملکرد، در صورت لزوم، مشخص کردن محل تابع را در نظر بگیرید.
محرکهای تابع Cloud Firestore
Cloud Functions for Firebase SDK، محرکهای رویداد Cloud Firestore زیر را صادر میکنند تا به شما امکان دهند کنترلکنندههایی مرتبط با رویدادهای خاص Cloud Firestore ایجاد کنید:
نود جی اس
نوع رویداد | ماشه |
---|---|
onDocumentCreated | زمانی که برای اولین بار در یک سند نوشته میشود، فعال میشود. |
onDocumentUpdated | زمانی فعال میشود که یک سند از قبل وجود داشته باشد و مقداری از آن تغییر کرده باشد. |
onDocumentDeleted | زمانی که یک سند حذف میشود، فعال میشود. |
onDocumentWritten | زمانی فعال میشود که onDocumentCreated ، onDocumentUpdated یا onDocumentDeleted فعال شوند. |
onDocumentCreatedWithAuthContext | onDocumentCreated با اطلاعات احراز هویت اضافی |
onDocumentWrittenWithAuthContext | onDocumentWritten |
onDocumentDeletedWithAuthContext | onDocumentDeleted با اطلاعات احراز هویت اضافی |
onDocumentUpdatedWithAuthContext | onDocumentUpdated با اطلاعات احراز هویت اضافی |
پایتون
نوع رویداد | ماشه |
---|---|
on_document_created | زمانی که برای اولین بار در یک سند نوشته میشود، فعال میشود. |
on_document_updated | زمانی فعال میشود که یک سند از قبل وجود داشته باشد و مقداری از آن تغییر کرده باشد. |
on_document_deleted | زمانی که یک سند حذف میشود، فعال میشود. |
on_document_written | زمانی فعال میشود که on_document_created ، on_document_updated یا on_document_deleted فعال شوند. |
on_document_created_with_auth_context | on_document_created با اطلاعات احراز هویت اضافی |
on_document_updated_with_auth_context | on_document_updated با اطلاعات احراز هویت اضافی |
on_document_deleted_with_auth_context | on_document_deleted با اطلاعات احراز هویت اضافی |
on_document_written_with_auth_context | on_document_written با اطلاعات احراز هویت اضافی |
رویدادهای Cloud Firestore فقط در صورت تغییر سند فعال میشوند. بهروزرسانی یک سند Cloud Firestore که دادهها در آن بدون تغییر هستند (نوشتن بدون عملیات) رویداد بهروزرسانی یا نوشتن ایجاد نمیکند. افزودن رویدادها به فیلدهای خاص امکانپذیر نیست.
اگر هنوز پروژهای برای Cloud Functions for Firebase فعال نکردهاید، برای پیکربندی و راهاندازی پروژه Cloud Cloud Functions for Firebase Cloud Functions for Firebase (نسل دوم)» را مطالعه کنید.
نوشتن توابع فعال شده توسط Cloud Firestore
تعریف یک تریگر تابع
برای تعریف یک تریگر Cloud Firestore، یک مسیر سند و یک نوع رویداد را مشخص کنید:
نود جی اس
const {
onDocumentWritten,
onDocumentCreated,
onDocumentUpdated,
onDocumentDeleted,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.myfunction = onDocumentWritten("my-collection/{docId}", (event) => {
/* ... */
});
پایتون
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:
مسیرهای سند میتوانند به یک سند خاص یا یک الگوی wildcard اشاره کنند.
یک سند واحد را مشخص کنید
اگر میخواهید برای هرگونه تغییر در یک سند خاص، رویدادی را فعال کنید، میتوانید از تابع زیر استفاده کنید.
نود جی اس
const {
onDocumentWritten,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.myfunction = onDocumentWritten("users/marie", (event) => {
// Your code here
});
پایتون
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:
مشخص کردن گروهی از اسناد با استفاده از کاراکترهای عمومی (wildcards)
اگر میخواهید یک تریگر را به گروهی از اسناد، مانند هر سندی در یک مجموعه خاص، پیوست کنید، به جای شناسه سند از {wildcard}
استفاده کنید:
نود جی اس
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"}
});
پایتون
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
در این مثال، وقتی هر فیلدی در هر سندی در users
تغییر میکند، با یک wildcard به نام userId
مطابقت پیدا میکند.
اگر سندی در users
دارای زیرمجموعههایی باشد و فیلدی در یکی از اسناد آن زیرمجموعهها تغییر کند، کاراکتر wildcard userId
فعال نمیشود .
تطبیقهای Wildcard از مسیر سند استخراج شده و در event.params
ذخیره میشوند. میتوانید هر تعداد Wildcard که دوست دارید برای جایگزینی شناسههای صریح مجموعه یا سند تعریف کنید، برای مثال:
نود جی اس
const {
onDocumentWritten,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.myfunction = onDocumentWritten("users/{userId}/{messageCollectionId}/{messageId}", (event) => {
// If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
// event.params.userId == "marie";
// event.params.messageCollectionId == "incoming_messages";
// event.params.messageId == "134";
// ... and ...
// event.data.after.data() == {body: "Hello"}
});
پایتون
from firebase_functions.firestore_fn import (
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_written(document="users/{userId}/{messageCollectionId}/{messageId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
event.params["userId"] == "marie" # True
event.params["messageCollectionId"] == "incoming_messages" # True
event.params["messageId"] == "134" # True
# ... and ...
event.data.after.to_dict() == {"body": "Hello"}
تریگر شما باید همیشه به یک سند اشاره کند، حتی اگر از یک کاراکتر جایگزین استفاده میکنید. برای مثال، users/{userId}/{messageCollectionId}
معتبر نیست زیرا {messageCollectionId}
یک مجموعه است. با این حال، users/{userId}/{messageCollectionId}/{messageId}
معتبر است زیرا {messageId}
همیشه به یک سند اشاره میکند.
محرکهای رویداد
هنگام ایجاد یک سند جدید، یک تابع را فعال میکند
شما میتوانید هر زمان که یک سند جدید در یک مجموعه ایجاد میشود، یک تابع را فعال کنید. این تابع مثال هر بار که یک پروفایل کاربری جدید اضافه میشود، فعال میشود:
نود جی اس
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 ...
});
برای اطلاعات بیشتر در مورد احراز هویت، از onDocumentCreatedWithAuthContext
استفاده کنید.
پایتون
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 ...
هنگامی که یک سند بهروزرسانی میشود، یک تابع را فعال میکند
همچنین میتوانید هنگام بهروزرسانی یک سند، یک تابع را فعال کنید. این تابع مثال در صورتی که کاربر پروفایل خود را تغییر دهد، فعال میشود:
نود جی اس
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 ...
});
برای اطلاعات احراز هویت بیشتر، از onDocumentUpdatedWithAuthContext
استفاده کنید.
پایتون
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 ...
هنگام حذف یک سند، یک تابع را فعال میکند
همچنین میتوانید هنگام حذف یک سند، یک تابع را فعال کنید. این تابع نمونه هنگامی که کاربر نمایه کاربری خود را حذف میکند، فعال میشود:
نود جی اس
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 ...
});
برای اطلاعات بیشتر در مورد احراز هویت، از onDocumentDeletedWithAuthContext
استفاده کنید.
پایتون
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 ...
فعال کردن یک تابع برای همه تغییرات در یک سند
اگر نوع رویدادی که اجرا میشود برایتان مهم نیست، میتوانید با استفاده از تریگر رویداد «سند نوشته شده» به تمام تغییرات در یک سند Cloud Firestore گوش دهید. این تابع مثال در صورت ایجاد، بهروزرسانی یا حذف کاربر اجرا میشود:
نود جی اس
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 ...
});
برای اطلاعات بیشتر در مورد احراز هویت، از onDocumentWrittenWithAuthContext
استفاده کنید.
پایتون
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 ...
خواندن و نوشتن دادهها
وقتی یک تابع فعال میشود، یک تصویر لحظهای از دادههای مربوط به رویداد ارائه میدهد. میتوانید از این تصویر لحظهای برای خواندن یا نوشتن در سندی که رویداد را فعال کرده است استفاده کنید، یا از Firebase Admin SDK برای دسترسی به سایر بخشهای پایگاه داده خود استفاده کنید.
دادههای رویداد
خواندن دادهها
وقتی یک تابع فعال میشود، ممکن است بخواهید دادههایی را از سندی که بهروزرسانی شده است دریافت کنید، یا دادهها را قبل از بهروزرسانی دریافت کنید. میتوانید دادههای قبلی را با استفاده از event.data.before
دریافت کنید، که شامل عکس فوری سند قبل از بهروزرسانی است. به طور مشابه، event.data.after
شامل وضعیت عکس فوری سند پس از بهروزرسانی است.
نود جی اس
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();
});
پایتون
@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()
شما میتوانید مانند هر شیء دیگری به ویژگیها دسترسی داشته باشید. به عنوان یک جایگزین، میتوانید از تابع get
برای دسترسی به فیلدهای خاص استفاده کنید:
نود جی اس
// 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');
پایتون
# 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"]
نوشتن دادهها
هر فراخوانی تابع با یک سند خاص در پایگاه داده Cloud Firestore شما مرتبط است. میتوانید به آن سند در snapshot برگردانده شده به تابع خود دسترسی داشته باشید.
مرجع سند شامل متدهایی مانند update()
، set()
و remove()
است، بنابراین میتوانید سندی را که تابع را فعال کرده است، تغییر دهید.
نود جی اس
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});
});
پایتون
@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})
دسترسی به اطلاعات احراز هویت کاربر
اگر از یکی از انواع رویدادهای زیر استفاده کنید، میتوانید به اطلاعات احراز هویت کاربر در مورد اصلی که رویداد را آغاز کرده است، دسترسی پیدا کنید. این اطلاعات علاوه بر اطلاعات برگردانده شده در رویداد پایه است.
نود جی اس
-
onDocumentCreatedWithAuthContext
-
onDocumentWrittenWithAuthContext
-
onDocumentDeletedWithAuthContext
-
onDocumentUpdatedWithAuthContext
پایتون
-
on_document_created_with_auth_context
-
on_document_updated_with_auth_context
-
on_document_deleted_with_auth_context
-
on_document_written_with_auth_context
برای اطلاعات مربوط به دادههای موجود در زمینه احراز هویت، به Auth Context مراجعه کنید. مثال زیر نحوه بازیابی اطلاعات احراز هویت را نشان میدهد:
نود جی اس
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});
});
پایتون
@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
دادههای خارج از رویداد ماشه
Cloud Functions در یک محیط قابل اعتماد اجرا میشوند. آنها به عنوان یک حساب کاربری سرویس در پروژه شما مجاز هستند و میتوانید با استفاده از Firebase Admin SDK عملیات خواندن و نوشتن را انجام دهید:
نود جی اس
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
});
});
پایتون
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({
# ...
})
محدودیتها
به محدودیتهای زیر برای محرکهای Cloud Firestore برای توابع Cloud توجه کنید:
- Cloud Functions (نسل اول) در حالت بومی Firestore، یک پایگاه داده "(پیشفرض)" موجود را پیشنیاز دارد. این قابلیت از پایگاههای داده با نام Cloud Firestore یا حالت Datastore پشتیبانی نمیکند. لطفاً در چنین مواردی Cloud Functions (نسل دوم) برای پیکربندی رویدادها استفاده کنید.
- راهاندازی بین پروژهای با Cloud Functions و Cloud Firestore trigger یک محدودیت است. برای راهاندازی Cloud Firestore trigger، Cloud Functions باید در یک پروژه باشند.
- ترتیب اجرا تضمین شده نیست. تغییرات سریع میتوانند باعث فراخوانی توابع با ترتیب غیرمنتظره شوند.
- رویدادها حداقل یک بار اجرا میشوند، اما یک رویداد واحد ممکن است منجر به فراخوانی چندین تابع شود. از تکیه بر مکانیزمهای دقیقاً یکباره خودداری کنید و توابع خودتوان بنویسید.
- Cloud Firestore در حالت Datastore به Cloud Functions (نسل دوم) نیاز دارد. Cloud Functions (نسل اول) از حالت Datastore پشتیبانی نمیکند.
- یک تریگر (Trigger) به یک پایگاه داده واحد مرتبط است. شما نمیتوانید تریگری ایجاد کنید که با چندین پایگاه داده مطابقت داشته باشد.
- حذف یک پایگاه داده به طور خودکار هیچ تریگر (triggers) را برای آن پایگاه داده حذف نمیکند. تریگر ارائه رویدادها را متوقف میکند اما تا زمانی که تریگر را حذف نکنید، همچنان وجود خواهد داشت.
- اگر یک رویداد منطبق از حداکثر اندازه درخواست فراتر رود، ممکن است رویداد به Cloud Functions (نسل اول) تحویل داده نشود.
- رویدادهایی که به دلیل حجم درخواست تحویل داده نمیشوند، در لاگهای پلتفرم ثبت میشوند و در میزان استفاده از لاگ برای پروژه محاسبه میشوند.
- میتوانید این گزارشها را در Logs Explorer با پیام "Event cannot deliver to Cloud function due to size exceeding the limit for 1st gen..." از نظر شدت
error
پیدا کنید. میتوانید نام تابع را در فیلدfunctionName
پیدا کنید. اگر فیلدreceiveTimestamp
هنوز تا یک ساعت دیگر باقی مانده باشد، میتوانید با خواندن سند مورد نظر به همراه یک snapshot قبل و بعد از برچسب زمانی، محتوای واقعی رویداد را استنباط کنید. - برای جلوگیری از چنین ریتمی، میتوانید:
- مهاجرت و ارتقاء به Cloud Functions (نسل دوم)
- کوچک کردن حجم سند
- Cloud Functions مورد نظر را حذف کنید
- شما میتوانید با استفاده از استثنائات، خودِ ثبت وقایع را غیرفعال کنید، اما توجه داشته باشید که رویدادهای مشکلساز همچنان اجرا نخواهند شد.