রিয়েলটাইম ডেটাবেস ট্রিগার (1ম প্রজন্ম)

Cloud Functions সাহায্যে, আপনি ক্লায়েন্ট কোড আপডেট করার প্রয়োজন ছাড়াই Firebase Realtime Database ইভেন্টগুলি পরিচালনা করতে পারবেন। Cloud Functions আপনাকে সম্পূর্ণ প্রশাসনিক সুবিধা সহ Realtime Database অপারেশন চালাতে দেয় এবং নিশ্চিত করে যে Realtime Database প্রতিটি পরিবর্তন পৃথকভাবে প্রক্রিয়া করা হয়। আপনি DataSnapshot বা অ্যাডমিন SDK এর মাধ্যমে Firebase Realtime Database পরিবর্তন করতে পারেন।

একটি সাধারণ জীবনচক্রের মধ্যে, একটি Firebase Realtime Database ফাংশন নিম্নলিখিত কাজগুলি করে:

  1. একটি নির্দিষ্ট Realtime Database অবস্থানের পরিবর্তনের জন্য অপেক্ষা করে।
  2. যখন কোনও ঘটনা ঘটে এবং তার কাজ সম্পাদন করে তখন ট্রিগার করে (ব্যবহারের উদাহরণের জন্য Cloud Functions দিয়ে আমি কী করতে পারি? দেখুন)।
  3. নির্দিষ্ট ডকুমেন্টে সংরক্ষিত ডেটার একটি স্ন্যাপশট ধারণকারী একটি ডেটা অবজেক্ট গ্রহণ করে।

একটি Realtime Database ফাংশন ট্রিগার করুন

functions.database ব্যবহার করে Realtime Database ইভেন্টের জন্য নতুন ফাংশন তৈরি করুন। ফাংশনটি কখন ট্রিগার হবে তা নিয়ন্ত্রণ করতে, ইভেন্ট হ্যান্ডলারগুলির একটি নির্দিষ্ট করুন এবং Realtime Database পাথটি নির্দিষ্ট করুন যেখানে এটি ইভেন্টগুলি শুনবে।

ইভেন্ট হ্যান্ডলার সেট করুন

ফাংশনগুলি আপনাকে দুটি নির্দিষ্ট স্তরে Realtime Database ইভেন্ট পরিচালনা করতে দেয়; আপনি কেবল তৈরি, আপডেট বা মুছে ফেলার ইভেন্টগুলির জন্য বিশেষভাবে শুনতে পারেন, অথবা আপনি কোনও পথে যেকোনো ধরণের পরিবর্তন শুনতে পারেন। Cloud Functions Realtime Database জন্য এই ইভেন্ট হ্যান্ডলারগুলিকে সমর্থন করে:

  • onWrite() , যা Realtime Database ডেটা তৈরি, আপডেট বা মুছে ফেলার সময় ট্রিগার করে।
  • onCreate() , যা Realtime Database নতুন ডেটা তৈরি হলে ট্রিগার করে।
  • onUpdate() , যা Realtime Database ডেটা আপডেট করার সময় ট্রিগার করে।
  • onDelete() , যা Realtime Database থেকে ডেটা মুছে ফেলা হলে ট্রিগার করে।

উদাহরণ এবং পথ নির্দিষ্ট করুন

আপনার ফাংশনটি কখন এবং কোথায় ট্রিগার হবে তা নিয়ন্ত্রণ করতে, একটি পাথ নির্দিষ্ট করতে ref(path) কল করুন এবং ঐচ্ছিকভাবে instance('INSTANCE_NAME') সহ একটি Realtime Database ইনস্ট্যান্স নির্দিষ্ট করুন। যদি আপনি একটি ইনস্ট্যান্স নির্দিষ্ট না করেন, তাহলে ফাংশনটি Firebase প্রকল্পের জন্য ডিফল্ট Realtime Database ইনস্ট্যান্সে স্থাপন করা হবে। উদাহরণস্বরূপ:

  • ডিফল্ট 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 ইভেন্ট পরিচালনা করার সময়, ফেরত পাঠানো ডেটা অবজেক্টটি একটি DataSnapshotonWrite বা 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);
    });