Cloud Firestore के ट्रिगर


Cloud Functions की मदद से, क्लाइंट कोड को अपडेट किए बिना Cloud Firestore में इवेंट मैनेज किए जा सकते हैं. Cloud Firestore में बदलाव, दस्तावेज़ स्नैपशॉट इंटरफ़ेस या Admin SDK की मदद से किए जा सकते हैं.

किसी सामान्य लाइफ़साइकल में, Cloud Firestore फ़ंक्शन ये काम करता है:

  1. यह कुकी, किसी दस्तावेज़ में किए गए बदलावों का इंतज़ार करती है.
  2. यह कुकी, इवेंट होने पर ट्रिगर होती है और अपने टास्क पूरे करती है.
  3. इसे एक ऐसा डेटा ऑब्जेक्ट मिलता है जिसमें तय किए गए दस्तावेज़ में सेव किए गए डेटा का स्नैपशॉट होता है. लिखने या अपडेट करने से जुड़े इवेंट के लिए, डेटा ऑब्जेक्ट में दो स्नैपशॉट होते हैं. ये स्नैपशॉट, इवेंट ट्रिगर होने से पहले और बाद की डेटा की स्थिति को दिखाते हैं.

Firestore इंस्टेंस और फ़ंक्शन की लोकेशन के बीच की दूरी की वजह से, नेटवर्क में ज़्यादा इंतज़ार का समय लग सकता है. परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, फ़ंक्शन की जगह तय करें.

Cloud Firestore फ़ंक्शन ट्रिगर

Cloud Functions for Firebase SDK, functions.firestore ऑब्जेक्ट एक्सपोर्ट करता है. इसकी मदद से, Cloud Firestore के किसी इवेंट से जुड़े हैंडलर बनाए जा सकते हैं.

इवेंट टाइप ट्रिगर
onCreate यह इवेंट तब ट्रिगर होता है, जब किसी दस्तावेज़ में पहली बार कुछ लिखा जाता है.
onUpdate यह तब ट्रिगर होता है, जब कोई दस्तावेज़ पहले से मौजूद हो और उसकी कोई वैल्यू बदल गई हो.
onDelete यह तब ट्रिगर होता है, जब डेटा वाला कोई दस्तावेज़ मिटाया जाता है.
onWrite यह तब ट्रिगर होता है, जब onCreate, onUpdate या onDelete ट्रिगर होता है.

अगर आपने अब तक Cloud Functions for Firebase के लिए कोई प्रोजेक्ट चालू नहीं किया है, तो शुरू करें: अपने पहले फ़ंक्शन लिखें और उन्हें डिप्लॉय करें लेख पढ़ें. इससे आपको Cloud Functions for Firebase प्रोजेक्ट को कॉन्फ़िगर और सेट अप करने में मदद मिलेगी.

Cloud Firestore से ट्रिगर होने वाले फ़ंक्शन लिखना

फ़ंक्शन ट्रिगर तय करना

Cloud Firestore ट्रिगर तय करने के लिए, दस्तावेज़ का पाथ और इवेंट का टाइप तय करें:

Node.js

const functions = require('firebase-functions');

exports.myFunction = functions.firestore
  .document('my-collection/{docId}')
  .onWrite((change, context) => { /* ... */ });

दस्तावेज़ के पाथ, किसी खास दस्तावेज़ या वाइल्डकार्ड पैटर्न को रेफ़रंस कर सकते हैं.

कोई एक दस्तावेज़ चुनें

अगर आपको किसी दस्तावेज़ में किसी भी बदलाव के लिए इवेंट ट्रिगर करना है, तो यहां दिए गए फ़ंक्शन का इस्तेमाल करें.

Node.js

// Listen for any change on document `marie` in collection `users`
exports.myFunctionName = functions.firestore
    .document('users/marie').onWrite((change, context) => {
      // ... Your code here
    });

वाइल्डकार्ड का इस्तेमाल करके, दस्तावेज़ों का ग्रुप तय करना

अगर आपको दस्तावेज़ों के किसी ग्रुप, जैसे कि किसी कलेक्शन में मौजूद किसी भी दस्तावेज़ से ट्रिगर अटैच करना है, तो दस्तावेज़ के आईडी की जगह {wildcard} का इस्तेमाल करें:

Node.js

// Listen for changes in all documents in the 'users' collection
exports.useWildcard = functions.firestore
    .document('users/{userId}')
    .onWrite((change, context) => {
      // If we set `/users/marie` to {name: "Marie"} then
      // context.params.userId == "marie"
      // ... and ...
      // change.after.data() == {name: "Marie"}
    });

इस उदाहरण में, users में मौजूद किसी भी दस्तावेज़ के किसी भी फ़ील्ड में बदलाव होने पर, वह userId नाम के वाइल्डकार्ड से मैच करता है.

अगर users में किसी दस्तावेज़ में सब-कलेक्शन हैं और उन सब-कलेक्शन में से किसी एक के दस्तावेज़ में मौजूद फ़ील्ड में बदलाव किया जाता है, तो userId वाइल्डकार्ड ट्रिगर नहीं होता है.

वाइल्डकार्ड से मैच होने वाले मान, दस्तावेज़ के पाथ से निकाले जाते हैं और context.params में सेव किए जाते हैं. आपके पास, कलेक्शन या दस्तावेज़ के आईडी की जगह इस्तेमाल करने के लिए, जितने चाहें उतने वाइल्डकार्ड तय करने का विकल्प होता है. उदाहरण के लिए:

Node.js

// Listen for changes in all documents in the 'users' collection and all subcollections
exports.useMultipleWildcards = functions.firestore
    .document('users/{userId}/{messageCollectionId}/{messageId}')
    .onWrite((change, context) => {
      // If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
      // context.params.userId == "marie";
      // context.params.messageCollectionId == "incoming_messages";
      // context.params.messageId == "134";
      // ... and ...
      // change.after.data() == {body: "Hello"}
    });

इवेंट ट्रिगर

नया दस्तावेज़ बनाए जाने पर किसी फ़ंक्शन को ट्रिगर करना

वाइल्डकार्ड के साथ onCreate() हैंडलर का इस्तेमाल करके, किसी फ़ंक्शन को तब ट्रिगर किया जा सकता है, जब किसी कलेक्शन में कोई नया दस्तावेज़ बनाया जाता है. इस उदाहरण में दिया गया फ़ंक्शन, हर बार नई उपयोगकर्ता प्रोफ़ाइल जोड़े जाने पर createUser को कॉल करता है:

Node.js

exports.createUser = functions.firestore
    .document('users/{userId}')
    .onCreate((snap, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = snap.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

दस्तावेज़ अपडेट होने पर किसी फ़ंक्शन को ट्रिगर करना

onUpdate() फ़ंक्शन के साथ वाइल्डकार्ड का इस्तेमाल करके, किसी दस्तावेज़ के अपडेट होने पर फ़ंक्शन को ट्रिगर किया जा सकता है. इस उदाहरण में दिया गया फ़ंक्शन, updateUser को तब कॉल करता है, जब कोई उपयोगकर्ता अपनी प्रोफ़ाइल में बदलाव करता है:

Node.js

exports.updateUser = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

दस्तावेज़ मिटाने पर किसी फ़ंक्शन को ट्रिगर करना

वाइल्डकार्ड के साथ onDelete() फ़ंक्शन का इस्तेमाल करके, किसी दस्तावेज़ को मिटाने पर भी कोई फ़ंक्शन ट्रिगर किया जा सकता है. इस उदाहरण में, जब कोई उपयोगकर्ता अपनी प्रोफ़ाइल मिटाता है, तब deleteUser को फ़ंक्शन कॉल किया जाता है:

Node.js

exports.deleteUser = functions.firestore
    .document('users/{userID}')
    .onDelete((snap, context) => {
      // Get an object representing the document prior to deletion
      // e.g. {'name': 'Marie', 'age': 66}
      const deletedValue = snap.data();

      // perform desired operations ...
    });

दस्तावेज़ में हुए सभी बदलावों के लिए किसी फ़ंक्शन को ट्रिगर करना

अगर आपको इस बात से कोई फ़र्क़ नहीं पड़ता कि किस तरह का इवेंट ट्रिगर किया जा रहा है, तो onWrite() फ़ंक्शन का इस्तेमाल करके, Cloud Firestore दस्तावेज़ में हुए सभी बदलावों को सुना जा सकता है. इसके लिए, वाइल्डकार्ड का इस्तेमाल करें. इस उदाहरण में, modifyUser फ़ंक्शन को तब कॉल किया जाता है, जब किसी उपयोगकर्ता को बनाया जाता है, अपडेट किया जाता है या मिटाया जाता है:

Node.js

exports.modifyUser = functions.firestore
    .document('users/{userID}')
    .onWrite((change, context) => {
      // Get an object with the current document value.
      // If the document does not exist, it has been deleted.
      const document = change.after.exists ? change.after.data() : null;

      // Get an object with the previous document value (for update or delete)
      const oldDocument = change.before.data();

      // perform desired operations ...
    });

डेटा पढ़ना और लिखना

जब कोई फ़ंक्शन ट्रिगर होता है, तो वह इवेंट से जुड़े डेटा का स्नैपशॉट उपलब्ध कराता है. इस स्नैपशॉट का इस्तेमाल, उस दस्तावेज़ को पढ़ने या उसमें लिखने के लिए किया जा सकता है जिसने इवेंट को ट्रिगर किया है. इसके अलावा, Firebase Admin SDK का इस्तेमाल करके, अपने डेटाबेस के अन्य हिस्सों को ऐक्सेस किया जा सकता है.

इवेंट का डेटा

पढ़ने से जुड़ा डेटा

किसी फ़ंक्शन के ट्रिगर होने पर, आपको अपडेट किए गए दस्तावेज़ से डेटा चाहिए हो सकता है. इसके अलावा, आपको अपडेट से पहले का डेटा भी चाहिए हो सकता है. अपडेट से पहले के दस्तावेज़ का स्नैपशॉट देखने के लिए, change.before.data() का इस्तेमाल करें. इसी तरह, change.after.data() में अपडेट के बाद दस्तावेज़ के स्नैपशॉट की स्थिति शामिल होती है.

Node.js

exports.updateUser2 = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the current document
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();
    });

प्रॉपर्टी को उसी तरह ऐक्सेस किया जा सकता है जिस तरह किसी अन्य ऑब्जेक्ट को ऐक्सेस किया जाता है. इसके अलावा, कुछ फ़ील्ड ऐक्सेस करने के लिए, get फ़ंक्शन का इस्तेमाल किया जा सकता है:

Node.js

// Fetch data using standard accessors
const age = snap.data().age;
const name = snap.data()['name'];

// Fetch data using built in accessor
const experience = snap.get('experience');

डेटा सेव करने की अनुमति दें

हर फ़ंक्शन इनवोकेशन, आपके Cloud Firestore डेटाबेस में मौजूद किसी खास दस्तावेज़ से जुड़ा होता है. आपके पास उस दस्तावेज़ को DocumentReference के तौर पर ऐक्सेस करने का विकल्प होता है. यह विकल्प, आपके फ़ंक्शन को भेजे गए स्नैपशॉट की ref प्रॉपर्टी में मौजूद होता है.

यह DocumentReference, Cloud Firestore Node.js SDK से आता है. इसमें update(), set(), और remove() जैसे तरीके शामिल होते हैं, ताकि फ़ंक्शन को ट्रिगर करने वाले दस्तावेज़ में आसानी से बदलाव किया जा सके.

Node.js

// Listen for updates to any `user` document.
exports.countNameChanges = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Retrieve the current and previous value
      const data = change.after.data();
      const previousData = change.before.data();

      // We'll only update if the name has changed.
      // This is crucial to prevent infinite loops.
      if (data.name == previousData.name) {
        return null;
      }

      // Retrieve the current count of name changes
      let count = data.name_change_count;
      if (!count) {
        count = 0;
      }

      // Then return a promise of a set operation to update the count
      return change.after.ref.set({
        name_change_count: count + 1
      }, {merge: true});
    });

ट्रिगर इवेंट के बाहर का डेटा

Cloud Functions को भरोसेमंद एनवायरमेंट में एक्ज़ीक्यूट किया जाता है. इसका मतलब है कि उन्हें आपके प्रोजेक्ट में सेवा खाते के तौर पर अनुमति दी गई है. Firebase Admin SDK का इस्तेमाल करके, ये काम किए जा सकते हैं:

Node.js

const admin = require('firebase-admin');
admin.initializeApp();

const db = admin.firestore();

exports.writeToFirestore = functions.firestore
  .document('some/doc')
  .onWrite((change, context) => {
    db.doc('some/otherdoc').set({ ... });
  });

सीमाएं

Cloud Functions के लिए Cloud Firestore ट्रिगर से जुड़ी इन सीमाओं का ध्यान रखें:

  • Cloud Functions (पहली जनरेशन) के लिए, Firestore नेटिव मोड में "(default)" डेटाबेस का होना ज़रूरी है. यह Cloud Firestore नाम वाले डेटाबेस या Datastore मोड के साथ काम नहीं करता. ऐसे मामलों में, इवेंट कॉन्फ़िगर करने के लिए कृपया Cloud Functions (दूसरी जनरेशन) का इस्तेमाल करें.
  • ऑर्डर करने की कोई गारंटी नहीं है. तेज़ी से बदलाव होने पर, फ़ंक्शन को अनचाहे क्रम में कॉल किया जा सकता है.
  • इवेंट कम से कम एक बार डिलीवर किए जाते हैं. हालांकि, एक इवेंट से फ़ंक्शन को कई बार कॉल किया जा सकता है. 'सिर्फ़ एक बार' सिद्धांत पर निर्भर रहने से बचें और आईडम्पोटेंट फ़ंक्शन लिखें.
  • Datastore मोड में Cloud Firestore के लिए, Cloud Functions (दूसरी जनरेशन) की ज़रूरत होती है. Cloud Functions (1st gen) में Datastore मोड काम नहीं करता.
  • ट्रिगर, किसी एक डेटाबेस से जुड़ा होता है. ऐसा ट्रिगर नहीं बनाया जा सकता जो एक से ज़्यादा डेटाबेस से मेल खाता हो.
  • किसी डेटाबेस को मिटाने से, उस डेटाबेस के लिए सेट किए गए ट्रिगर अपने-आप नहीं मिटते. ट्रिगर इवेंट डिलीवर करना बंद कर देता है. हालांकि, यह तब तक मौजूद रहता है, जब तक ट्रिगर को मिटाया नहीं जाता.
  • अगर मैच किया गया कोई इवेंट, अनुरोध के ज़्यादा से ज़्यादा साइज़ से ज़्यादा है, तो हो सकता है कि इवेंट को Cloud Functions (पहली जनरेशन) को न भेजा जाए.
    • अनुरोध के साइज़ की वजह से डिलीवर न किए गए इवेंट, प्लैटफ़ॉर्म लॉग में लॉग किए जाते हैं. साथ ही, इन्हें प्रोजेक्ट के लिए लॉग के इस्तेमाल में गिना जाता है.
    • आपको ये लॉग, लॉग एक्सप्लोरर में मिल सकते हैं. इनमें यह मैसेज होता है: "पहली जनरेशन के लिए तय सीमा से ज़्यादा साइज़ होने की वजह से, इवेंट को Cloud फ़ंक्शन तक नहीं पहुंचाया जा सकता..." error गंभीरता. आपको फ़ंक्शन का नाम, functionName फ़ील्ड में दिखेगा. अगर receiveTimestamp फ़ील्ड में मौजूद समय अभी एक घंटे के अंदर है, तो टाइमस्टैंप से पहले और बाद के स्नैपशॉट के साथ दस्तावेज़ को पढ़कर, इवेंट के असली कॉन्टेंट का पता लगाया जा सकता है.
    • इस तरह की कैडेंस से बचने के लिए, ये काम किए जा सकते हैं:
      • Cloud Functions (दूसरी जनरेशन) पर माइग्रेट और अपग्रेड करें
      • दस्तावेज़ का साइज़ कम करना
      • सवाल में मौजूद Cloud Functions को मिटाएं
    • बहिष्करण का इस्तेमाल करके, लॉगिंग की सुविधा बंद की जा सकती है. हालांकि, ध्यान दें कि उल्लंघन करने वाले इवेंट अब भी डिलीवर नहीं किए जाएंगे.