گسترش Cloud Firestore با سازگاری MongoDB با Cloud Functions (نسل دوم)

با استفاده از Cloud Functions ، می‌توانید کدی را برای مدیریت رویدادهای ناشی از تغییرات در Cloud Firestore خود با پایگاه داده سازگار با MongoDB مستقر کنید. این به شما امکان می‌دهد بدون اجرای سرورهای خود، قابلیت‌های سمت سرور را به برنامه خود اضافه کنید.

Cloud Functions (نسل دوم)

با پشتیبانی Cloud Run و Eventarc ، Cloud Functions for Firebase (نسل دوم) زیرساخت قدرتمندتر، کنترل پیشرفته بر عملکرد و مقیاس‌پذیری و کنترل بیشتر بر زمان اجرای توابع را در اختیار شما قرار می‌دهد. برای اطلاعات بیشتر در مورد نسل دوم، به توابع ابری برای Firebase (نسل دوم) مراجعه کنید.

Cloud Firestore با تریگرهای تابع سازگاری MongoDB

Cloud Functions for Firebase SDK، محرک‌های رویداد سازگاری با Cloud Firestore با MongoDB زیر را صادر می‌کنند تا به شما امکان دهند هندلرهایی مرتبط با رویدادهای خاص سازگاری با Cloud Firestore با MongoDB ایجاد کنید:

نود جی اس

نوع رویداد ماشه
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 با MongoDB فقط در صورت تغییر سند فعال می‌شوند. به‌روزرسانی یک سند سازگاری Cloud Firestore با MongoDB که داده‌ها در آن بدون تغییر هستند (نوشتن بدون عملیات) رویداد به‌روزرسانی یا نوشتن ایجاد نمی‌کند. افزودن رویدادها به فیلدهای خاص امکان‌پذیر نیست.

اگر هنوز پروژه‌ای برای Cloud Functions for Firebase فعال نکرده‌اید، برای پیکربندی و راه‌اندازی پروژه Cloud Functions for Firebase خود ، «شروع به کار با Cloud Functions for Firebase (نسل دوم)» را مطالعه کنید.

نوشتن Cloud Firestore با توابع فعال شده توسط سازگاری MongoDB

تعریف یک تریگر تابع

برای تعریف یک Cloud Firestore با تریگر سازگاری MongoDB، یک مسیر سند و یک نوع رویداد را مشخص کنید:

نود جی اس

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 مطابقت پیدا می‌کند.

تطبیق‌های Wildcard از مسیر سند استخراج شده و در event.params ذخیره می‌شوند. trigger شما باید همیشه به یک سند اشاره کند، حتی اگر از wildcard استفاده می‌کنید.

محرک‌های رویداد

هنگام ایجاد یک سند جدید، یک تابع را فعال می‌کند

شما می‌توانید هر زمان که یک سند جدید در یک مجموعه ایجاد می‌شود، یک تابع را فعال کنید. این تابع مثال هر بار که یک پروفایل کاربری جدید اضافه می‌شود، فعال می‌شود:

نود جی اس

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 ...

فعال کردن یک تابع برای همه تغییرات در یک سند

اگر نوع رویدادی که اجرا می‌شود برایتان مهم نیست، می‌توانید با استفاده از تریگر رویداد «document written» به تمام تغییرات در یک سند سازگاری Cloud Firestore با MongoDB گوش دهید. این تابع مثال در صورت ایجاد، به‌روزرسانی یا حذف کاربر اجرا می‌شود:

نود جی اس

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 با MongoDB شما مرتبط است. می‌توانید به آن سند در 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({
      # ...
  })

محدودیت‌ها

  • ترتیب اجرا تضمین شده نیست. تغییرات سریع می‌توانند باعث فراخوانی توابع با ترتیب غیرمنتظره شوند.
  • رویدادها حداقل یک بار اجرا می‌شوند، اما یک رویداد واحد ممکن است منجر به فراخوانی چندین تابع شود. از تکیه بر مکانیزم‌های دقیقاً یک‌باره خودداری کنید و توابع خودتوان بنویسید.
  • یک تریگر (Trigger) به یک پایگاه داده واحد مرتبط است. شما نمی‌توانید تریگری ایجاد کنید که با چندین پایگاه داده مطابقت داشته باشد.
  • حذف یک پایگاه داده به طور خودکار هیچ تریگر (triggers) را برای آن پایگاه داده حذف نمی‌کند. تریگر ارائه رویدادها را متوقف می‌کند اما تا زمانی که تریگر را حذف نکنید، همچنان وجود دارد.