ক্লাউড ফাংশন সহ রিয়েলটাইম ডাটাবেস প্রসারিত করুন

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

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

  1. একটি নির্দিষ্ট Realtime Database পাথে পরিবর্তনের জন্য অপেক্ষা করে।
  2. যখন কোনও ঘটনা ঘটে তখন ট্রিগার করে এবং তার কাজ সম্পাদন করে।
  3. একটি ডেটা অবজেক্ট গ্রহণ করে যাতে সেই পথে সংরক্ষিত ডেটার একটি স্ন্যাপশট থাকে।

Firebase Realtime Database ডাটাবেস নোড লেখা, তৈরি, আপডেট বা মুছে ফেলার প্রতিক্রিয়ায় আপনি একটি ফাংশন ট্রিগার করতে পারেন। ফাংশনটি কখন ট্রিগার হবে তা নিয়ন্ত্রণ করতে, ইভেন্ট হ্যান্ডলারগুলির মধ্যে একটি নির্দিষ্ট করুন এবং Realtime Database পাথটি নির্দিষ্ট করুন যেখানে এটি ইভেন্টগুলি শুনবে।

ফাংশনের অবস্থান নির্ধারণ করা হচ্ছে

Realtime Database ইনস্ট্যান্সের অবস্থান এবং ফাংশনের অবস্থানের মধ্যে দূরত্ব উল্লেখযোগ্য নেটওয়ার্ক ল্যাটেন্সি তৈরি করতে পারে। এছাড়াও, অঞ্চলগুলির মধ্যে অমিলের ফলে স্থাপনা ব্যর্থতা দেখা দিতে পারে। এই পরিস্থিতিগুলি এড়াতে, ফাংশনের অবস্থানটি নির্দিষ্ট করুন যাতে এটি ডাটাবেস ইনস্ট্যান্স অবস্থানের সাথে মেলে।

Realtime Database ইভেন্ট পরিচালনা করা

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

Realtime Database ইভেন্টগুলিতে সাড়া দেওয়ার জন্য এই হ্যান্ডলারগুলি উপলব্ধ:

নোড.জেএস

  • onValueWritten() Realtime Database ডেটা তৈরি, আপডেট বা মুছে ফেলা হলে ট্রিগার হয়।
  • onValueCreated() শুধুমাত্র তখনই ট্রিগার হয় যখন Realtime Database ডেটা তৈরি করা হয়।
  • onValueUpdated() শুধুমাত্র তখনই ট্রিগার হয় যখন Realtime Database ডেটা আপডেট করা হয়।
  • onValueDeleted() শুধুমাত্র তখনই ট্রিগার হয় যখন Realtime Database ডেটা মুছে ফেলা হয়।

পাইথন

  • on_value_written() Realtime Database ডেটা তৈরি, আপডেট বা মুছে ফেলা হলে ট্রিগার হয়।
  • on_value_created() শুধুমাত্র তখনই ট্রিগার হয় যখন Realtime Database ডেটা তৈরি করা হয়।
  • on_value_updated() শুধুমাত্র তখনই ট্রিগার হয় যখন Realtime Database ডেটা আপডেট করা হয়।
  • on_value_deleted() শুধুমাত্র তখনই ট্রিগার হয় যখন Realtime Database ডেটা মুছে ফেলা হয়।

প্রয়োজনীয় মডিউল আমদানি করুন

আপনার ফাংশন সোর্সে, আপনাকে অবশ্যই SDK মডিউলগুলি আমদানি করতে হবে যা আপনি ব্যবহার করতে চান। এই নমুনার জন্য, Realtime Database লেখার জন্য Firebase Admin SDK মডিউলের সাথে HTTP এবং Realtime Database মডিউলগুলি আমদানি করা প্রয়োজন।

নোড.জেএস

// The Cloud Functions for Firebase SDK to setup triggers and logging.
const {onRequest} = require("firebase-functions/https");
const {onValueCreated} = require("firebase-functions/database");
const {logger} = require("firebase-functions");

// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require("firebase-admin");
admin.initializeApp();

পাইথন

# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import db_fn, https_fn

# The Firebase Admin SDK to access the Firebase Realtime Database.
from firebase_admin import initialize_app, db

app = initialize_app()

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

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

উদাহরণস্বরূপ:

নোড.জেএস

// All Realtime Database instances in default function region us-central1 at path "/user/{uid}"
// There must be at least one Realtime Database present in us-central1.
const onWrittenFunctionDefault = onValueWritten("/user/{uid}", (event) => {
  // …
});

// Instance named "my-app-db-2", at path "/user/{uid}".
// The "my-app-db-2" instance must exist in this region.
const OnWrittenFunctionInstance = onValueWritten(
  {
    ref: "/user/{uid}",
    instance: "my-app-db-2"
    // This example assumes us-central1, but to set location:
    // region: "europe-west1"
  },
  (event) => {
    // …
  }
);

// Instance with "my-app-db-" prefix, at path "/user/{uid}", where uid ends with @gmail.com.
// There must be at least one Realtime Database with "my-app-db-*" prefix in this region.
const onWrittenFunctionInstance = onValueWritten(
  {
    ref: "/user/{uid=*@gmail.com}",
    instance: "my-app-db-*"
    // This example assumes us-central1, but to set location:
    // region: "europe-west1"
  },
  (event) => {
    // …
  }
);

পাইথন

# All Realtime Database instances in default function region us-central1 at path "/user/{uid}"
# There must be at least one Realtime Database present in us-central1.
@db_fn.on_value_written(r"/user/{uid}")
def onwrittenfunctiondefault(event: db_fn.Event[db_fn.Change]):
    # ...
    pass

# Instance named "my-app-db-2", at path "/user/{uid}".
# The "my-app-db-2" instance must exist in this region.
@db_fn.on_value_written(
    reference=r"/user/{uid}",
    instance="my-app-db-2",
    # This example assumes us-central1, but to set location:
    # region="europe-west1",
)
def on_written_function_instance(event: db_fn.Event[db_fn.Change]):
    # ...
    pass

# Instance with "my-app-db-" prefix, at path "/user/{uid}", where uid ends with @gmail.com.
# There must be at least one Realtime Database with "my-app-db-*" prefix in this region.
@db_fn.on_value_written(
    reference=r"/user/{uid=*@gmail.com}",
    instance="my-app-db-*",
    # This example assumes us-central1, but to set location:
    # region="europe-west1",
)
def on_written_function_instance(event: db_fn.Event[db_fn.Change]):
    # ...
    pass

এই প্যারামিটারগুলি আপনার ফাংশনকে Realtime Database ইনস্ট্যান্সের মধ্যে একটি নির্দিষ্ট পথে লেখা পরিচালনা করার নির্দেশ দেয়।

পাথ স্পেসিফিকেশনগুলি পাথ স্পর্শ করে এমন সমস্ত লেখার সাথে মেলে, যার মধ্যে তার নীচের যেকোনো জায়গায় ঘটে যাওয়া লেখাও অন্তর্ভুক্ত। যদি আপনি আপনার ফাংশনের জন্য পাথ /foo/bar হিসাবে সেট করেন, তাহলে এটি এই উভয় অবস্থানের ইভেন্টের সাথে মেলে:

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

উভয় ক্ষেত্রেই, Firebase ব্যাখ্যা করে যে ঘটনাটি /foo/bar এ ঘটে, এবং ইভেন্ট ডেটাতে /foo/bar এ পুরানো এবং নতুন ডেটা অন্তর্ভুক্ত থাকে। যদি ইভেন্ট ডেটা বড় হতে পারে, তাহলে আপনার ডাটাবেসের রুটের কাছাকাছি একটি ফাংশনের পরিবর্তে গভীর পাথে একাধিক ফাংশন ব্যবহার করার কথা বিবেচনা করুন। সেরা পারফরম্যান্সের জন্য, কেবলমাত্র গভীরতম স্তরে ডেটা অনুরোধ করুন।

ওয়াইল্ডকার্ডিং এবং ক্যাপচারিং

ক্যাপচার করার জন্য আপনি {key} , {key=*} , {key=prefix*} , {key=*suffix} ব্যবহার করতে পারেন। একক-সেগমেন্ট ওয়াইল্ডকার্ডিংয়ের জন্য * , prefix* , *suffix ব্যবহার করতে পারেন। দ্রষ্টব্য: ** মাল্টি-সেগমেন্ট ওয়াইল্ডকার্ডিংকে প্রতিনিধিত্ব করে, যা Realtime Database সমর্থন করে না। আন্ডারস্ট্যান্ড পাথ প্যাটার্ন দেখুন।

পাথ ওয়াইল্ডকার্ডিং। আপনি একটি পাথ কম্পোনেন্টকে ওয়াইল্ডকার্ড হিসেবে নির্দিষ্ট করতে পারেন:

  • তারকাচিহ্ন ব্যবহার করে, * । উদাহরণস্বরূপ, foo/* যেকোনো শিশুকে foo/ নীচের নোড শ্রেণিবিন্যাসের এক স্তরের সাথে মেলে।
  • ঠিক তারকাচিহ্ন সম্বলিত একটি অংশ ব্যবহার করে, * । উদাহরণস্বরূপ, foo/app*-us foo/ নীচের যেকোনো চাইল্ড অংশের সাথে app প্রিফিক্স এবং -us প্রত্যয় ব্যবহার করে মিলিত হয়।

ওয়াইল্ডকার্ড সহ পাথগুলি একাধিক ইভেন্টের সাথে মেলাতে পারে, উদাহরণস্বরূপ, একটি একক লেখা থেকে। এর একটি সন্নিবেশ

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

"/foo/*" পাথটি দুবার মিলে যায়: একবার "hello": "world" দিয়ে এবং আবার "firebase": "functions" দিয়ে।

পাথ ক্যাপচারিং। আপনি আপনার ফাংশন কোডে ব্যবহার করার জন্য নামযুক্ত ভেরিয়েবলগুলিতে পাথ ম্যাচ ক্যাপচার করতে পারেন (যেমন /user/{uid} , /user/{uid=*-us} )।

ক্যাপচার ভেরিয়েবলের মানগুলি আপনার ফাংশনের database.DatabaseEvent.params অবজেক্টের মধ্যে উপলব্ধ।

ইনস্ট্যান্স ওয়াইল্ডকার্ডিং। আপনি ওয়াইল্ডকার্ডিং ব্যবহার করে একটি ইনস্ট্যান্স কম্পোনেন্টও নির্দিষ্ট করতে পারেন। একটি ইনস্ট্যান্স ওয়াইল্ডকার্ডে প্রিফিক্স, প্রত্যয় অথবা উভয়ই থাকতে পারে (যেমন my-app-*-prod )।

ওয়াইল্ডকার্ড এবং ক্যাপচার রেফারেন্স

Cloud Functions (দ্বিতীয় প্রজন্ম) এবং Realtime Database ব্যবহার করে, ref এবং instance নির্দিষ্ট করার সময় একটি প্যাটার্ন ব্যবহার করা যেতে পারে। প্রতিটি ট্রিগার ইন্টারফেসে একটি ফাংশন স্কোপ করার জন্য নিম্নলিখিত বিকল্পগুলি থাকবে:

ref উল্লেখ করা হচ্ছে instance উল্লেখ করা হচ্ছে আচরণ
একক ( /foo/bar ) নির্দিষ্ট করে বলা হচ্ছে না ফাংশন অঞ্চলের সকল দৃষ্টান্তের জন্য স্কোপ হ্যান্ডলার।
একক ( /foo/bar ) একক ( 'my-new-db' ) ফাংশন অঞ্চলের নির্দিষ্ট উদাহরণের জন্য স্কোপ হ্যান্ডলার।
একক ( /foo/bar ) প্যাটার্ন ( 'inst-prefix*' ) ফাংশন অঞ্চলের প্যাটার্নের সাথে মেলে এমন সমস্ত উদাহরণের স্কোপ হ্যান্ডলার।
প্যাটার্ন ( /foo/{bar} ) নির্দিষ্ট করে বলা হচ্ছে না ফাংশন অঞ্চলের সকল দৃষ্টান্তের জন্য স্কোপ হ্যান্ডলার।
প্যাটার্ন ( /foo/{bar} ) একক ( 'my-new-db' ) ফাংশন অঞ্চলের নির্দিষ্ট উদাহরণের জন্য স্কোপ হ্যান্ডলার।
প্যাটার্ন ( /foo/{bar} ) প্যাটার্ন ( 'inst-prefix*' ) ফাংশন অঞ্চলের প্যাটার্নের সাথে মেলে এমন সমস্ত উদাহরণের স্কোপ হ্যান্ডলার।

ইভেন্ট ডেটা পরিচালনা করুন

যখন একটি Realtime Database ইভেন্ট ট্রিগার হয়, তখন এটি আপনার হ্যান্ডলার ফাংশনে একটি Event অবজেক্ট পাঠায়। এই অবজেক্টের একটি data প্রোপার্টি থাকে, যা তৈরি এবং মুছে ফেলার ইভেন্টগুলির জন্য তৈরি বা মুছে ফেলা ডেটার একটি স্ন্যাপশট ধারণ করে।

এই উদাহরণে, ফাংশনটি রেফারেন্স করা পাথের জন্য ডেটা পুনরুদ্ধার করে, সেই অবস্থানের স্ট্রিংটিকে বড় হাতের অক্ষরে রূপান্তর করে এবং সেই পরিবর্তিত স্ট্রিংটি ডাটাবেসে লেখে:

নোড.জেএস

// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
// for all databases in 'us-central1'
exports.makeuppercase = onValueCreated(
    "/messages/{pushId}/original",
    (event) => {
    // Grab the current value of what was written to the Realtime Database.
      const original = event.data.val();
      logger.log("Uppercasing", event.params.pushId, original);
      const uppercase = original.toUpperCase();
      // You must return a Promise when performing
      // asynchronous tasks inside a function, such as
      // writing to the Firebase Realtime Database.
      // Setting an "uppercase" sibling in the
      // Realtime Database returns a Promise.
      return event.data.ref.parent.child("uppercase").set(uppercase);
    },
);

পাইথন

@db_fn.on_value_created(reference="/messages/{pushId}/original")
def makeuppercase(event: db_fn.Event[Any]) -> None:
    """Listens for new messages added to /messages/{pushId}/original and
    creates an uppercase version of the message to /messages/{pushId}/uppercase
    """

    # Grab the value that was written to the Realtime Database.
    original = event.data
    if not isinstance(original, str):
        print(f"Not a string: {event.reference}")
        return

    # Use the Admin SDK to set an "uppercase" sibling.
    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    parent = db.reference(event.reference).parent
    if parent is None:
        print("Message can't be root node.")
        return
    parent.child("uppercase").set(upper)

পূর্ববর্তী মান পড়া

write বা update ইভেন্টের জন্য, data প্রোপার্টি হল একটি Change অবজেক্ট যাতে দুটি স্ন্যাপশট থাকে যা ট্রিগারিং ইভেন্টের আগে এবং পরে ডেটা স্টেট উপস্থাপন করে। Change অবজেক্টের একটি before প্রোপার্টি থাকে যা আপনাকে ইভেন্টের আগে Realtime Database কী সংরক্ষিত হয়েছিল তা পরীক্ষা করতে দেয় এবং একটি after প্রোপার্টি যা ইভেন্টটি ঘটার পরে ডেটার স্টেট উপস্থাপন করে।

উদাহরণস্বরূপ, before প্রোপার্টিটি ব্যবহার করে নিশ্চিত করা যেতে পারে যে ফাংশনটি প্রথমবার তৈরি করার সময় কেবল টেক্সটকে বড় হাতের অক্ষরে

নোড.জেএস

  exports makeUppercase = onValueWritten("/messages/{pushId}/original", (event) => {
        // Only edit data when it is first created.
        if (event.data.before.exists()) {
          return null;
        }
        // Exit when the data is deleted.
        if (!event.data.after.exists()) {
          return null;
        }
        // Grab the current value of what was written to the Realtime Database.
        const original = event.data.after.val();
        console.log('Uppercasing', event.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 event.data.after.ref.parent.child('uppercase').set(uppercase);
      });

পাইথন

@db_fn.on_value_written(reference="/messages/{pushId}/original")
def makeuppercase2(event: db_fn.Event[db_fn.Change]) -> None:
    """Listens for new messages added to /messages/{pushId}/original and
    creates an uppercase version of the message to /messages/{pushId}/uppercase
    """

    # Only edit data when it is first created.
    if event.data.before is not None:
        return

    # Exit when the data is deleted.
    if event.data.after is None:
        return

    # Grab the value that was written to the Realtime Database.
    original = event.data.after
    if not hasattr(original, "upper"):
        print(f"Not a string: {event.reference}")
        return

    # Use the Admin SDK to set an "uppercase" sibling.
    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    parent = db.reference(event.reference).parent
    if parent is None:
        print("Message can't be root node.")
        return
    parent.child("uppercase").set(upper)

প্রমাণীকরণ প্রসঙ্গ অ্যাক্সেস করা হচ্ছে

RTDB eventarc ইভেন্ট দ্বারা ট্রিগার করা ফাংশনগুলির জন্য, ইভেন্ট পেলোডে প্রমাণীকরণ প্রসঙ্গ অন্তর্ভুক্ত করা হয়:

  • authtype : ইভেন্টটি ট্রিগার করা প্রিন্সিপালের ধরণ। সম্ভাব্য মানগুলি হল:
    • app_user : ডেভেলপারের অ্যাপ্লিকেশনের একজন শেষ ব্যবহারকারী।
    • admin : একটি পরিষেবা অ্যাকাউন্ট।
    • unauthenticated : একজন অননুমোদিত ব্যবহারকারী।
    • unknown : প্রমাণীকরণ তথ্য অনুপলব্ধ হলে ডিফল্ট।
  • authid : অধ্যক্ষের অনন্য শনাক্তকারী।
    • যদি authtype app_user হয়, তাহলে এটি ব্যবহারকারীর UID।
    • যদি authtype admin হয়, তাহলে এটি পরিষেবা অ্যাকাউন্ট অথবা IAM ব্যবহারকারীর ইমেল।

এই কোডটি শুধুমাত্র বার্তার টেক্সটকে বড় হাতের অক্ষরে রূপান্তরিত করে যদি ফাংশনটি ট্রিগারকারী ব্যবহারকারী অ্যাডমিন না হন। এছাড়াও, কোডটি এটিও পরীক্ষা করে যে বার্তাটি ট্রিগারকারী ব্যবহারকারীই বার্তাটির প্রকৃত প্রেরক কিনা।

নোড.জেএস

// The Cloud Functions for Firebase SDK to setup triggers and logging.
const {onValueWritten} = require("firebase-functions/v2/database");
const {logger} = require("firebase-functions");
const admin = require("firebase-admin");

admin.initializeApp();

exports.dbtrigger = onValueWritten("/messages/{pushId}/original", async (event) => {
  // 1. Check whether authtype is admin. If it is, skip this operation.
  if (event.authType === "admin") {
    logger.log("Modification by admin detected. Skipping uppercase conversion.");
    return null;
  }

  // 2. Retrieve the userID of the sender (assumed sibling node 'senderId')
  const snapshot = await event.data.after.ref.parent.child("senderId").get();
  const senderId = snapshot.val();

  // 3. Check if userID of sender of message = event.authid
  if (senderId !== event.authId) {
    logger.error(`Unauthorized write: senderId (${senderId}) does not match authId (${event.authId})`);
    return null;
  }

  // Grab the value that was written to the Realtime Database.
  const original = event.data.after.val();
  logger.log("Uppercasing", event.params.pushId, original);
  const uppercase = original.toUpperCase();

  // Return the promise to set the "uppercase" sibling node.
  return event.data.after.ref.parent.child("uppercase").set(uppercase);
});

পাইথন

from firebase_functions import db_fn
from firebase_admin import initialize_app, db

initialize_app()

@db_fn.on_value_written(reference="/messages/{pushId}/original")
def makeuppercase(event: db_fn.Event[db_fn.Change]) -> None:
    # 1. Check whether authtype is admin. If it is, skip this operation.
    if event.auth_type == "admin":
        print("Admin user detected. Skipping.")
        return

    # 2. Retrieve the userID of the sender (assumed sibling node: 'senderId')
    parent_ref = db.reference(event.reference).parent
    sender_id = parent_ref.child("senderId").get()

    # 3. Check if userID of sender = event.auth_id
    if sender_id != event.auth_id:
        print(f"Unauthorized: sender_id {sender_id} != auth_id {event.auth_id}")
        return

    # Exit when the data is deleted.
    if event.data.after is None:
        return

    # Grab the value and uppercase it
    original = event.data.after
    if not isinstance(original, str):
        return

    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    parent_ref.child("uppercase").set(upper)