مشغِّلات Cloud Firestore


باستخدام Cloud Functions، يمكنك معالجة الأحداث في Cloud Firestore بدون الحاجة إلى تعديل رمز العميل. يمكنك إجراء تغييرات في Cloud Firestore من خلال واجهة لقطة وثيقة أو عبر SDK للمشرف.

في دورة حياة نموذجية، تُجري دالة Cloud Firestore ما يلي:

  1. لانتظار التغييرات في مستند معيّن.
  2. يتم تشغيله عند حدوث حدث وتنفيذ مهامه.
  3. يتلقى كائن بيانات يحتوي على لقطة من البيانات المخزنة في المستند المحدد. بالنسبة إلى أحداث الكتابة أو التعديل، يحتوي كائن البيانات على لقتَين تمثّلان حالة البيانات قبل وبعد الحدث المشغِّل.

المسافة بين موقع مثيل Firestore والموقع إلى إنشاء زمن انتقال كبير في الشبكة. لتحسين الأداء، ننصحك بتحديد موقع الدالة حيث ينطبق ذلك.

عوامل تشغيل وظائف Cloud Firestore

تُصدِّر حزمة SDK الخاصة بمنصّة Cloud Functions for Firebase عنصر functions.firestore يتيح لك إنشاء عناصر معالجة مرتبطة بأحداث معيّنة في Cloud Firestore.

نوع الحدث عامل التفعيل
onCreate يتم تشغيله عند الكتابة في مستند لأول مرة.
onUpdate يتم تشغيله عندما يكون هناك مستند متوفّر وتغيّرت أي قيمة فيه.
onDelete يتم تشغيله عند حذف مستند يحتوي على بيانات.
onWrite يتم تشغيله عند بدء onCreate أو onUpdate أو onDelete.

إذا لم يسبق لك تفعيل مشروع في Cloud Functions for Firebase، عليك قراءة البدء: كتابة الدوال الأولى ونشرها لضبط مشروع Cloud Functions for Firebase وإعداده.

كتابة دوال يتم تشغيلها من خلال Cloud Firestore

تحديد مشغل الدالة

لتحديد عامل تشغيل في Cloud Firestore، حدِّد مسار مستند ونوع حدث:

Node.js

const functions = require('firebase-functions');

exports.myFunction = functions.firestore
  .document('my-collection/{docId}')
  .onWrite((change, context) => { /* ... */ });

يمكن أن تشير مسارات المستندات إلى مستند معيّن أو نمط عنصر نائب.

تحديد مستند واحد

إذا كنت تريد بدء حدث لأي تغيير في مستند معيّن، يمكنك استخدام الدالة التالية.

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
    });

تحديد مجموعة من المستندات باستخدام أحرف البدل

إذا أردت إرفاق عامل تشغيل بمجموعة من المستندات، مثل أي مستند في مجموعة معيّنة، ثم استخدام {wildcard} بدلاً من معرف المستند:

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"}
    });

في هذا المثال، عند تغيير أي حقل في أي مستند في users، يتطابق مع علامة متعلّقة تُسمى userId.

إذا كان مستند في users يحتوي على مجموعات فرعية، وحقل في إحدى هذه المجموعات الفرعية' المستندات، لا يتم تشغيل حرف البدل userId.

يتم استخراج تطابقات أحرف البدل من مسار المستند وتخزينها في context.params. يمكنك تحديد العدد الذي تريده من أحرف البدل لاستبدال المجموعة الفاضحة. أو معرِّفات المستندات، مثل:

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"}
    });

عوامل تشغيل الأحداث

تشغيل دالة عند إنشاء مستند جديد

يمكنك تنشيط دالة لإطلاقها في أي وقت يتم فيه إنشاء مستند جديد في مجموعة، وذلك باستخدام معالِج onCreate() مع حرف بدل. يستدعي مثال الدالة هذا createUser في كل مرة تتم فيها إضافة ملف شخصي جديد للمستخدم:

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 ...
    });

تنشيط دالة عند تعديل مستند

يمكنك أيضًا بدء دالة لإطلاقها عند تعديل مستند باستخدام الدالة onUpdate() مع علامة متعلّقة. تستدعي الدالة التالية المثال updateUser إذا كان أحد المستخدمين تغيير الملف الشخصي:

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 ...
    });

بدء دالة عند حذف مستند

يمكنك أيضًا تشغيل دالة عند حذف مستند باستخدام الدالة onDelete() باستخدام حرف بدل. هذا المثال تستدعي الدالة deleteUser عندما يحذف أحد المستخدمين الملف الشخصي للمستخدم:

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 ...
    });

تشغيل دالة لجميع التغييرات التي يتم إجراؤها على مستند

إذا لم تكن مهتمًا بنوع الحدث الذي يتم تشغيله، يمكنك الاستماع إلى جميع التغييرات في مستند Cloud Firestore باستخدام الدالة onWrite() مع حرف بدل. يستدعي هذا المثال الدالة modifyUser في حال إنشاء مستخدم أو تعديله أو حذفه:

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 ...
    });

قراءة البيانات وكتابتها

عند تشغيل دالة، فإنها توفر لقطة من البيانات المتعلقة فعالية. يمكنك استخدام هذه اللقطة للقراءة من المستند الذي أدّى إلى بدء الحدث، أو استخدام حزمة تطوير البرامج (SDK) لمشرف Firebase للوصول إلى أجزاء أخرى من قاعدة البيانات لديك.

بيانات الأحداث

قراءة البيانات

عند تشغيل دالة، قد ترغب في الحصول على بيانات من مستند البيانات، أو الحصول على البيانات قبل التحديث. يمكنك الحصول على البيانات السابقة باستخدام change.before.data()، الذي يحتوي على نبذة عن المستند قبل التحديث. وبالمثل، يحتوي change.after.data() على حالة لقطة المستند بعد التحديث.

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();
    });

يمكنك الوصول إلى السمات كما تفعل في أيّ عنصر آخر. بدلاً من ذلك، يمكنك استخدام الدالة get للوصول إلى حقول محددة:

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');

كتابة البيانات

يرتبط كل استدعاء للدالة بمستند معين في قاعدة بيانات Cloud Firestore. يمكنك الوصول إلى هذا المستند يتم عرض DocumentReference في السمة ref الخاصة باللقطة إلى الدالة.

تأتي DocumentReference هذه من حزمة تطوير برامج Node.js في Cloud Firestore وتتضمّن طرقًا مثل update() وset() وremove() لتتمكّن من تعديل المستند الذي أدّى إلى تشغيل الدالة.

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});
    });

البيانات خارج عامل التفعيل

Cloud Functions يتم تنفيذها في بيئة موثوق بها، ما يعني أنّه تم تفويضها كحساب خدمة في مشروعك. يمكنك إجراء عمليات القراءة والكتابة باستخدام مدير حزمة تطوير البرامج (SDK) في Firebase:

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({ ... });
  });

القيود

لاحظ القيود التالية لعوامل تشغيل Cloud Firestore للحساب Cloud Functions:

  • يستلزم Cloud Functions (الجيل الأول) وجود "(تلقائي)" حالي قاعدة البيانات في وضع Firestore الأصلي. لا إتاحة قواعد البيانات المُسمّاة Cloud Firestore أو وضع تخزين البيانات. يُرجى استخدام Cloud Functions. (الجيل الثاني) لضبط الأحداث في مثل هذه الحالات
  • الطلب غير مضمون. يمكن أن تؤدي التغييرات السريعة إلى استدعاء الدوال في طلب غير متوقع.
  • يتم تسليم الأحداث مرة واحدة على الأقل، ولكن قد يؤدي حدث واحد إلى استدعاءات الدوال المتعددة. تجنَّب الاعتماد على آليات التنفيذ مرّة واحدة فقط، واكتب دوالًّا متماثلة.
  • "Cloud Firestore" في وضع "تخزين البيانات" تتطلّب الميزة Cloud Functions (الجيل الثاني). يُرجى العِلم بأنّ "Cloud Functions" (الجيل الأول) لا ينطبق تدعم وضع تخزين البيانات.
  • يرتبط المشغل بقاعدة بيانات واحدة. لا يمكنك إنشاء عامل تشغيل يتطابق مع قواعد بيانات متعددة.
  • لا يؤدي حذف قاعدة بيانات إلى حذف أي مشغلات لقاعدة البيانات هذه تلقائيًا. يتوقف ال disparador عن إرسال الأحداث، ولكنه يبقى متوفّرًا إلى أن تحذفه.
  • إذا تجاوز حدث مطابق الحد الأقصى لحجم الطلب، سيتم قد لا يتم تسليم الحدث إلى Cloud Functions (الجيل الأول).
    • يتم تسجيل الدخول إلى سجلّات النظام الأساسي للأحداث التي لم يتم تسليمها بسبب حجم الطلب. وحسابها ضمن استخدام السجل للمشروع.
    • يمكنك العثور على هذه السجلّات في "مستكشف السجلات" مع الرسالة "تعذّر تسليم الحدث إلى دالة السحابة الإلكترونية لأنّ حجمها يتجاوز الحد الأقصى المسموح به للجيل الأول..." من error وشدة الخطأ. يمكنك العثور على اسم الدالة ضمن الحقل functionName. في حال حذف لا يزال الحقل receiveTimestamp خلال ساعة من الآن، يمكنك استنتاج محتوى الحدث الفعلي من خلال قراءة المستند المعني لقطة قبل وبعد الطابع الزمني.
    • لتجنُّب هذا الأسلوب، يمكنك اتّباع الخطوات التالية:
      • نقل البيانات والترقية إلى Cloud Functions (الجيل الثاني)
      • تصغير حجم المستند
      • حذف Cloud Functions المعنيّ
    • يمكنك إيقاف التسجيل نفسه باستخدام الاستبعادات ولكن يُرجى العلم أنّه لن يتم تسليم الأحداث المخالفة.