Cloud Functions की मदद से, Firebase Realtime Database में इवेंट मैनेज किए जा सकते हैं. इसके लिए, क्लाइंट कोड को अपडेट करने की ज़रूरत नहीं होती.
Cloud Functions की मदद से, एडमिन के सभी अधिकारों के साथ Realtime Database के ऑपरेशन चलाए जा सकते हैं. साथ ही, यह पक्का किया जा सकता है कि Realtime Database में किए गए हर बदलाव को अलग-अलग प्रोसेस किया जाए. Firebase Realtime Database में बदलाव करने के लिए, DataSnapshot
या Admin SDK का इस्तेमाल किया जा सकता है.
किसी सामान्य लाइफ़साइकल में, 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 इंस्टेंस तय किया जा सकता है. हालांकि, यह ज़रूरी नहीं है. अगर आपने किसी इंस्टेंस के बारे में नहीं बताया है, तो फ़ंक्शन को 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 इवेंट को मैनेज करते समय, डेटा ऑब्जेक्ट के तौर पर 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);
});