راه‌اندازی پایگاه داده بیدرنگ


با Cloud Functions ، می‌توانید رویدادها را در Firebase Realtime Database بدون نیاز به به‌روزرسانی کد مشتری مدیریت کنید. Cloud Functions به شما امکان می دهد عملیات Realtime Database با امتیازات مدیریتی کامل اجرا کنید و تضمین می کند که هر تغییر در Realtime Database به صورت جداگانه پردازش می شود. می توانید از طریق DataSnapshot یا از طریق Admin SDK تغییراتی Firebase Realtime Database ایجاد کنید.

در یک چرخه عمر معمولی، یک تابع Firebase Realtime Database کارهای زیر را انجام می دهد:

  1. منتظر تغییرات در یک مکان خاص Realtime Database .
  2. هنگامی که یک رویداد رخ می دهد و وظایف خود را انجام می دهد، راه اندازی می شود (برای نمونه هایی از موارد استفاده، به «چه کاری می توانم با Cloud Functions انجام دهم؟ » مراجعه کنید.
  3. یک شی داده را دریافت می کند که حاوی یک عکس فوری از داده های ذخیره شده در سند مشخص شده است.

یک تابع Realtime Database فعال کنید

توابع جدید برای رویدادهای Realtime Database با functions.database ایجاد کنید. برای کنترل زمان راه‌اندازی تابع، یکی از کنترل‌کننده‌های رویداد را مشخص کنید و مسیر Realtime Database را که در آن به رویدادها گوش می‌دهد، مشخص کنید.

کنترل کننده رویداد را تنظیم کنید

توابع به شما امکان می دهند رویدادهای Realtime Database در دو سطح از ویژگی مدیریت کنید. شما می توانید به طور خاص فقط برای رویدادهای ایجاد، به روز رسانی یا حذف گوش دهید، یا می توانید برای هر نوع تغییر در یک مسیر گوش دهید. Cloud Functions از این دسته رویدادها برای Realtime Database پشتیبانی می کند:

  • onWrite() که هنگام ایجاد، به‌روزرسانی یا حذف داده‌ها در Realtime Database فعال می‌شود.
  • onCreate() که با ایجاد داده های جدید در Realtime Database فعال می شود.
  • onUpdate() که با به روز رسانی داده ها در Realtime Database فعال می شود.
  • onDelete() که با حذف داده ها از Realtime Database فعال می شود.

نمونه و مسیر را مشخص کنید

برای کنترل زمان و مکانی که تابع شما باید فعال شود، ref(path) را برای تعیین یک مسیر فراخوانی کنید و به صورت اختیاری یک نمونه Realtime Database با instance('INSTANCE_NAME') مشخص کنید. اگر نمونه ای را مشخص نکنید، تابع به نمونه پیش فرض Realtime Database برای پروژه Firebase مستقر می شود، به عنوان مثال:

  • نمونه پیش‌فرض Realtime Database : functions.database.ref('/foo/bar')
  • نمونه با نام "my-app-db-2": functions.database.instance('my-app-db-2').ref('/foo/bar')

این روش‌ها تابع شما را هدایت می‌کنند تا نوشته‌ها را در یک مسیر مشخص در نمونه Realtime Database مدیریت کند. مشخصات مسیر با تمام نوشته هایی که یک مسیر را لمس می کنند، از جمله نوشته هایی که در هر نقطه زیر آن اتفاق می افتد، مطابقت دارد. اگر مسیر تابع خود را به عنوان /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" .

مدیریت داده های رویداد

هنگام مدیریت یک رویداد Realtime Database ، شی داده ای که برگردانده می شود یک 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/v1');
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 است که به شما امکان می دهد آنچه را که قبل از رویداد در Realtime Database ذخیره شده است بررسی کنید. ویژگی 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);
    });