مشغلات قاعدة البيانات في الوقت الفعلي


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

في دورة الحياة النموذجية، تنفّذ دالة قاعدة بيانات Firebase في الوقت الفعلي ما يلي:

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

تشغيل دالة "قاعدة البيانات في الوقت الفعلي"

إنشاء دوال جديدة لأحداث قاعدة البيانات في الوقت الفعلي مع functions.database. إلى التحكم في وقت تشغيل الدالة، وتحديد أحد معالِجات الأحداث، تحديد مسار قاعدة بيانات الوقت الفعلي حيث ستستمع إلى الأحداث.

ضبط معالِج الحدث

تتيح لك الدوال التعامل مع أحداث قاعدة البيانات في الوقت الفعلي على مستويَين من الخصوصية؛ التي يمكنك الاستماع إليها تحديدًا للإنشاء والتحديث أو حذف الأحداث، أو يمكنك الاستماع إلى أي تغيير من أي نوع في المسار. تدعم دوال السحابة معالِجات الأحداث التالية لقاعدة البيانات في الوقت الفعلي:

  • onWrite()، الذي يعمل عند إنشاء البيانات أو تحديثها أو حذفها في قاعدة بيانات الوقت الفعلي.
  • onCreate()، الذي يتم تشغيله عند إنشاء بيانات جديدة في قاعدة بيانات الوقت الفعلي.
  • onUpdate()، يعمل عند تعديل البيانات في قاعدة بيانات الوقت الفعلي .
  • onDelete()، الذي يعمل عند حذف البيانات من قاعدة بيانات الوقت الفعلي

تحديد المثيل والمسار

للتحكّم في وقت ومكان تشغيل الدالة، يمكنك طلب ref(path). لتحديد مسار، واختياريًا تحديد مثيل قاعدة بيانات الوقت الفعلي مع instance('INSTANCE_NAME'). إذا لم لتحديد مثيل، يتم نشر الدالة على مثيل قاعدة البيانات الافتراضية في الوقت الفعلي مشروع Firebase على سبيل المثال:

  • مثيل قاعدة البيانات التلقائية في الوقت الفعلي: functions.database.ref('/foo/bar')
  • مثيل باسم "my-app-db-2": functions.database.instance('my-app-db-2').ref('/foo/bar')

توجه هذه الطرق دالتك للتعامل مع عمليات الكتابة في مسار معين داخل مثيل قاعدة بيانات الوقت الفعلي. تتطابق مواصفات المسار مع جميع النصوص التي تلمس مسارًا، بما في ذلك الكتابة تحدث في أي مكان تحتها. في حال تحديد المسار لوظيفتك كـ /foo/bar، فإنها تتطابق مع الأحداث في كلا الموقعين التاليين:

 /foo/bar
 /foo/bar/baz/really/deep/path

في كلتا الحالتين، يفسّر Firebase أن الحدث وقع في /foo/bar، وتشمل بيانات الحدث البيانات القديمة والجديدة في /foo/bar. إذا كانت بيانات الحدث كبيرة، ننصحك باستخدام دوال متعددة في مسارات أكثر عمقًا بدلاً من دالة واحدة تعمل بالقرب من جذر قاعدة البيانات الخاصة بك. للحصول على أفضل أداء، اطلب فقط البيانات على أعمق مستوى ممكن.

يمكنك تحديد مكون مسار كحرف بدل من خلال إحاطته بحرف مجعد الأقواس يتطابق ref('foo/{bar}') مع أي عنصر ثانوي في /foo. ولا تعتبر قيم هذه تتوفر مكونات مسار حرف البدل ضمن EventContext.params كائن الدالة لديك. في هذا المثال، تتوفر القيمة على شكل context.params.bar

يمكن أن تتطابق المسارات التي تتضمن أحرف البدل مع أحداث متعددة من عملية كتابة واحدة. إدراج

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

تتطابق مع المسار "/foo/{bar}" مرتين: مرة مع "hello": "world" ومرة أخرى باستخدام "firebase": "functions".

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

عند التعامل مع حدث قاعدة بيانات الوقت الفعلي، يكون كائن البيانات الذي يتم عرضه DataSnapshot بالنسبة إلى onWrite أو onUpdate حدث، سيتم المعلمة الأولى هي كائن Change يحتوي على لقطتين التي تمثل حالة البيانات قبل وبعد الحدث التشغيلي. في onCreate وonDelete حدث كائن البيانات المعروض هو لقطة من البيانات التي تم إنشاؤها أو حذفها.

في هذا المثال، تسترد الدالة لقطة المسار المحدد، يحول السلسلة في هذا الموقع إلى أحرف كبيرة، وتكتب هذه السلسلة المعدّلة في قاعدة البيانات:

// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
    .onCreate((snapshot, context) => {
      // Grab the current value of what was written to the Realtime Database.
      const original = snapshot.val();
      functions.logger.log('Uppercasing', context.params.pushId, original);
      const uppercase = original.toUpperCase();
      // You must return a Promise when performing asynchronous tasks inside a Functions such as
      // writing to the Firebase Realtime Database.
      // Setting an "uppercase" sibling in the Realtime Database returns a Promise.
      return snapshot.ref.parent.child('uppercase').set(uppercase);
    });

الوصول إلى معلومات مصادقة المستخدم

من EventContext.auth وEventContext.authType، يمكنك الوصول إلى معلومات المستخدم، بما في ذلك الأذونات، للمستخدم الذي بدأ تشغيل إحدى الدوال. ويمكن أن يفيد ذلك في فرض قواعد الأمان، ما يسمح لوظيفتك بإكمال عمليات مختلفة بناءً على واجهة المستخدم مستوى الأذونات:

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

exports.simpleDbFunction = functions.database.ref('/path')
    .onCreate((snap, context) => {
      if (context.authType === 'ADMIN') {
        // do something
      } else if (context.authType === 'USER') {
        console.log(snap.val(), 'written by', context.auth.uid);
      }
    });

يمكنك أيضًا الاستفادة من معلومات مصادقة المستخدم من أجل "انتحال الهوية" مستخدِم وتنفيذ عمليات الكتابة نيابةً عن المستخدم تأكد من حذف مثيل التطبيق كما هو موضّح أدناه لتجنُّب حدوث مشاكل في المزامنة:

exports.impersonateMakeUpperCase = functions.database.ref('/messages/{pushId}/original')
    .onCreate((snap, context) => {
      const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
      appOptions.databaseAuthVariableOverride = context.auth;
      const app = admin.initializeApp(appOptions, 'app');
      const uppercase = snap.val().toUpperCase();
      const ref = snap.ref.parent.child('uppercase');

      const deleteApp = () => app.delete().catch(() => null);

      return app.database().ref(ref).set(uppercase).then(res => {
        // Deleting the app is necessary for preventing concurrency leaks
        return deleteApp().then(() => res);
      }).catch(err => {
        return deleteApp().then(() => Promise.reject(err));
      });
    });

قراءة القيمة السابقة

يحتوي الكائن Change على before تتيح لك فحص ما تم حفظه في قاعدة بيانات الوقت الفعلي قبل فعالية. تعرض السمة before علامة DataSnapshot حيث تكون جميع (على سبيل المثال، val() و exists()) يشير إلى القيمة السابقة. يمكنك قراءة القيمة الجديدة مرة أخرى باستخدام DataSnapshot الأصلية أو قراءة after الموقع. هذه السمة على أي Change هي سمة DataSnapshot أخرى تمثّل حالة البيانات بعد وقوع الحدث.

على سبيل المثال، يمكن استخدام السمة before للتأكّد من أنّ الدالة فقط كتابة النص بأحرف كبيرة عند إنشائه لأول مرة:

exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
    .onWrite((change, context) => {
      // Only edit data when it is first created.
      if (change.before.exists()) {
        return null;
      }
      // Exit when the data is deleted.
      if (!change.after.exists()) {
        return null;
      }
      // Grab the current value of what was written to the Realtime Database.
      const original = change.after.val();
      console.log('Uppercasing', context.params.pushId, original);
      const uppercase = original.toUpperCase();
      // You must return a Promise when performing asynchronous tasks inside a Functions such as
      // writing to the Firebase Realtime Database.
      // Setting an "uppercase" sibling in the Realtime Database returns a Promise.
      return change.after.ref.parent.child('uppercase').set(uppercase);
    });