Cloud Functions ব্যবহার করে, আপনি ক্লায়েন্ট কোড আপডেট করার প্রয়োজন ছাড়াই Firebase Realtime Database ইভেন্টগুলো পরিচালনা করতে পারেন। Cloud Functions আপনাকে সম্পূর্ণ প্রশাসনিক অধিকারসহ Realtime Database অপারেশন চালানোর সুযোগ দেয় এবং এটি নিশ্চিত করে যে Realtime Database প্রতিটি পরিবর্তন স্বতন্ত্রভাবে প্রক্রিয়া করা হয়। আপনি DataSnapshot অথবা অ্যাডমিন এসডিকে-এর মাধ্যমে Firebase Realtime Database পরিবর্তন আনতে পারেন।
একটি সাধারণ জীবনচক্রে, একটি Firebase Realtime Database ফাংশন নিম্নলিখিত কাজগুলো করে থাকে:
- Realtime Database একটি নির্দিষ্ট অবস্থানে পরিবর্তনের জন্য অপেক্ষা করে।
- কোনো ঘটনা ঘটলে এটি সক্রিয় হয় এবং এর কাজগুলো সম্পাদন করে (এর ব্যবহারের উদাহরণের জন্য Cloud Functions দিয়ে আমি কী করতে পারি?’ দেখুন)।
- একটি ডেটা অবজেক্ট গ্রহণ করে, যেটিতে নির্দিষ্ট ডকুমেন্টে সংরক্ষিত ডেটার একটি স্ন্যাপশট থাকে।
একটি 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 ইনস্ট্যান্স নির্দিষ্ট করুন। আপনি যদি কোনো ইনস্ট্যান্স নির্দিষ্ট না করেন, তাহলে ফাংশনটি ফায়ারবেস প্রজেক্টের ডিফল্ট 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 ইভেন্ট পরিচালনা করার সময়, যে ডেটা অবজেক্টটি ফেরত আসে তা হলো একটি 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);
});