با Cloud Functions ، میتوانید رویدادها را در Cloud Firestore بدون نیاز به بهروزرسانی کد مشتری مدیریت کنید. میتوانید تغییرات Cloud Firestore را از طریق رابط عکس فوری سند یا از طریق Admin SDK انجام دهید.
در یک چرخه عمر معمولی، یک تابع Cloud Firestore کارهای زیر را انجام می دهد:
- منتظر تغییرات در یک سند خاص است.
- هنگامی که یک رویداد رخ می دهد و وظایف خود را انجام می دهد، راه اندازی می شود.
- یک شی داده را دریافت می کند که حاوی یک عکس فوری از داده های ذخیره شده در سند مشخص شده است. برای رویدادهای نوشتن یا بهروزرسانی، شی داده حاوی دو عکس فوری است که وضعیت داده قبل و بعد از رویداد راهاندازی را نشان میدهد.
فاصله بین مکان نمونه Firestore و محل تابع می تواند تاخیر شبکه قابل توجهی ایجاد کند. برای بهینه سازی عملکرد، مکان عملکرد را در صورت امکان مشخص کنید.
عملکرد Cloud Firestore فعال می شود
Cloud Functions for Firebase SDK، محرکهای رویداد Cloud Firestore زیر را صادر میکند تا به شما امکان میدهد کنترلکنندههای مرتبط با رویدادهای Cloud Firestore خاص ایجاد کنید:
Node.js
نوع رویداد | ماشه |
---|---|
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 Functions for Firebase Get start with Cloud Functions for Firebase (نسل دوم) را بخوانید.
نوشتن توابع راه اندازی شده توسط Cloud Firestore
تریگر تابع را تعریف کنید
برای تعریف یک راهانداز Cloud Firestore، یک مسیر سند و یک نوع رویداد را مشخص کنید:
Node.js
import {
onDocumentWritten,
onDocumentCreated,
onDocumentUpdated,
onDocumentDeleted,
Change,
FirestoreEvent
} from "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:
مسیرهای سند می توانند به یک سند خاص یا یک الگوی عام ارجاع دهند.
یک سند واحد را مشخص کنید
اگر می خواهید یک رویداد را برای هر تغییری در یک سند خاص راه اندازی کنید، می توانید از تابع زیر استفاده کنید.
Node.js
import {
onDocumentWritten,
Change,
FirestoreEvent
} from "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:
گروهی از اسناد را با استفاده از حروف عام مشخص کنید
اگر میخواهید یک ماشه را به گروهی از اسناد وصل کنید، مانند هر سندی در یک مجموعه خاص، از یک {wildcard}
به جای شناسه سند استفاده کنید:
Node.js
import {
onDocumentWritten,
Change,
FirestoreEvent
} from "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
تغییر میکند، با علامتی به نام userId
مطابقت دارد.
اگر سندی در users
دارای مجموعههای فرعی باشد و فیلدی در اسناد یکی از آن مجموعههای فرعی تغییر کند، علامت userId
فعال نمیشود .
موارد منطبق با حروف عام از مسیر سند استخراج شده و در event.params
ذخیره می شوند. میتوانید به تعداد دلخواه ویلدکارت تعریف کنید تا شناسههای مجموعه یا سند صریح را جایگزین کنید، برای مثال:
Node.js
import {
onDocumentWritten,
Change,
FirestoreEvent
} from "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}
همیشه به یک سند اشاره میکند.
محرک های رویداد
هنگامی که یک سند جدید ایجاد می شود، یک تابع را فعال کنید
هر زمان که سند جدیدی در مجموعه ایجاد می شود، می توانید یک تابع را فعال کنید. این تابع مثال هر بار که یک نمایه کاربر جدید اضافه می شود فعال می شود:
Node.js
import {
onDocumentCreated,
Change,
FirestoreEvent
} from "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 ...
هنگامی که یک سند به روز می شود، یک تابع را فعال کنید
همچنین میتوانید هنگام بهروزرسانی یک سند، عملکردی را فعال کنید. اگر کاربر نمایه خود را تغییر دهد، این تابع مثال فعال می شود:
Node.js
import {
onDocumentUpdated,
Change,
FirestoreEvent
} from "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 ...
هنگام حذف یک سند، یک تابع را فعال کنید
همچنین می توانید یک تابع را هنگام حذف یک سند فعال کنید. این تابع مثال زمانی فعال می شود که کاربر نمایه کاربری خود را حذف کند:
Node.js
import {
onDocumentDeleted,
Change,
FirestoreEvent
} from "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 گوش دهید. اگر کاربر ایجاد، بهروزرسانی یا حذف شود، این تابع مثال فعال میشود:
Node.js
import {
onDocumentWritten,
Change,
FirestoreEvent
} from "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
شامل وضعیت عکس فوری سند پس از بهروزرسانی است.
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();
});
پایتون (پیش نمایش)
@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
برای دسترسی به فیلدهای خاص استفاده کنید:
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');
پایتون (پیش نمایش)
# 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 شما مرتبط است. شما می توانید در عکس فوری که به عملکرد خود بازگردانده شده است به آن سند دسترسی پیدا کنید.
مرجع سند شامل متدهایی مانند update()
، set()
و remove()
است تا بتوانید سندی را که تابع را راه اندازی کرده است تغییر دهید.
Node.js
import { onDocumentUpdated } from "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 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})
دسترسی به اطلاعات احراز هویت کاربر
اگر از یکی از انواع رویداد زیر استفاده میکنید، میتوانید به اطلاعات احراز هویت کاربر درباره اصلی که رویداد را راهاندازی کرده است، دسترسی داشته باشید. این اطلاعات علاوه بر اطلاعات بازگشتی در رویداد پایه است.
Node.js
-
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
برای اطلاعات در مورد داده های موجود در زمینه احراز هویت، به زمینه تأیید مراجعه کنید. مثال زیر نحوه بازیابی اطلاعات احراز هویت را نشان می دهد:
Node.js
import { onDocumentWrittenWithAuthContext } from "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 انجام دهید:
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
});
});
پایتون (پیش نمایش)
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 Functions توجه کنید:
- Cloud Functions (نسل اول) یک پایگاه داده موجود "(پیش فرض)" را در حالت بومی Firestore پیش نیاز دارد. این پایگاههای داده با نام Cloud Firestore یا حالت Datastore را پشتیبانی نمیکند. لطفاً از Cloud Functions (نسل دوم) برای پیکربندی رویدادها در چنین مواردی استفاده کنید.
- سفارش تضمین نمی شود. تغییرات سریع می تواند فراخوانی عملکرد را با ترتیب غیرمنتظره ای آغاز کند.
- رویدادها حداقل یک بار تحویل داده می شوند، اما یک رویداد ممکن است منجر به فراخوانی چند تابع شود. از وابستگی به مکانیک دقیقاً یکبار خودداری کنید و توابع بی توان را بنویسید.
- Cloud Firestore در حالت Datastore به Cloud Functions (نسل دوم) نیاز دارد. Cloud Functions (نسل اول) از حالت Datastore پشتیبانی نمی کند.
- یک ماشه با یک پایگاه داده واحد مرتبط است. شما نمی توانید تریگری ایجاد کنید که با چندین پایگاه داده مطابقت داشته باشد.
- حذف یک پایگاه داده به طور خودکار هیچ عاملی را برای آن پایگاه داده حذف نمی کند. ماشه تحویل رویدادها را متوقف می کند اما تا زمانی که ماشه را حذف نکنید به وجود خود ادامه می دهد.
- اگر یک رویداد منطبق از حداکثر اندازه درخواست بیشتر شود، ممکن است رویداد به Cloud Functions (نسل اول) تحویل داده نشود.
- رویدادهایی که به دلیل اندازه درخواست تحویل نمیشوند، در گزارشهای پلتفرم ثبت میشوند و بهحساب استفاده از گزارش برای پروژه حساب میشوند.
- میتوانید این گزارشها را در کاوشگر گزارشها با پیام شدت
error
پیدا کنید "رویداد نمیتواند به عملکرد Cloud تحویل داده شود به دلیل اندازه بیش از حد مجاز برای نسل اول...". می توانید نام تابع را در قسمتfunctionName
پیدا کنید. اگر قسمتreceiveTimestamp
هنوز تا یک ساعت دیگر باقی مانده است، می توانید با خواندن سند مورد نظر با یک عکس فوری قبل و بعد از مهر زمانی، محتوای واقعی رویداد را استنباط کنید. - برای جلوگیری از چنین آهنگی، می توانید:
- مهاجرت و ارتقاء به Cloud Functions (نسل دوم)
- سند را کوچک کنید
- Cloud Functions مورد نظر را حذف کنید
- شما می توانید خود گزارش را با استفاده از استثناها خاموش کنید، اما توجه داشته باشید که رویدادهای توهین آمیز هنوز تحویل داده نمی شوند.