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);
});