Cloud Firestore वेब कोडलैब (कोड बनाना सीखना)

1. खास जानकारी

लक्ष्य

इस कोडलैब में, आपको Cloud Firestore की मदद से, रेस्टोरेंट के सुझाव देने वाला वेब ऐप्लिकेशन बनाने का तरीका बताया जाएगा.

img5.png

आपको क्या सीखने को मिलेगा

  • वेब ऐप्लिकेशन से Cloud Firestore में डेटा पढ़ना और लिखना
  • Cloud Firestore में मौजूद डेटा में हुए बदलावों को रीयल टाइम में सुनना
  • Cloud Firestore के डेटा को सुरक्षित रखने के लिए, Firebase Authentication और सुरक्षा के नियमों का इस्तेमाल करना
  • Cloud Firestore की मुश्किल क्वेरी लिखना

आपको इन चीज़ों की ज़रूरत होगी

इस कोडलैब को शुरू करने से पहले, पक्का करें कि आपने ये इंस्टॉल किए हों:

  • npm, जो आम तौर पर Node.js के साथ आता है - Node 16+ का इस्तेमाल करने का सुझाव दिया जाता है
  • आपकी पसंद का आईडीई/टेक्स्ट एडिटर, जैसे कि WebStorm, VS Code या Sublime

2. Firebase प्रोजेक्ट बनाना और उसे सेट अप करना

Firebase प्रोजेक्ट बनाना

  1. अपने Google खाते का इस्तेमाल करके, Firebase कंसोल में साइन इन करें.
  2. नया प्रोजेक्ट बनाने के लिए, बटन पर क्लिक करें. इसके बाद, प्रोजेक्ट का नाम डालें. उदाहरण के लिए, FriendlyEats.
  3. जारी रखें पर क्लिक करें.
  4. अगर आपसे कहा जाए, तो Firebase की शर्तें पढ़ें और स्वीकार करें. इसके बाद, जारी रखें पर क्लिक करें.
  5. (ज़रूरी नहीं) Firebase कंसोल में एआई की मदद पाने की सुविधा चालू करें. इसे "Firebase में Gemini" कहा जाता है.
  6. इस कोडलैब के लिए, आपको Google Analytics की ज़रूरत नहीं है. इसलिए, Google Analytics के विकल्प को टॉगल करके बंद करें.
  7. प्रोजेक्ट बनाएं पर क्लिक करें. इसके बाद, प्रोजेक्ट के प्रोविज़न होने का इंतज़ार करें. इसके बाद, जारी रखें पर क्लिक करें.

Firebase प्रॉडक्ट सेट अप करना

हम जिस ऐप्लिकेशन को बनाने जा रहे हैं वह वेब पर उपलब्ध कुछ Firebase सेवाओं का इस्तेमाल करता है:

  • उपयोगकर्ताओं की आसानी से पहचान करने के लिए, Firebase से पुष्टि करने की सुविधा
  • Cloud Firestore का इस्तेमाल करके, स्ट्रक्चर्ड डेटा को क्लाउड पर सेव किया जा सकता है. साथ ही, डेटा अपडेट होने पर तुरंत सूचना पाई जा सकती है
  • अपनी स्टैटिक ऐसेट को होस्ट और डिलीवर करने के लिए, Firebase होस्टिंग का इस्तेमाल करें

इस कोडलैब के लिए, हमने Firebase Hosting को पहले से ही कॉन्फ़िगर कर दिया है. हालांकि, Firebase Auth और Cloud Firestore के लिए, हम आपको Firebase कंसोल का इस्तेमाल करके, सेवाओं को कॉन्फ़िगर करने और चालू करने का तरीका बताएंगे.

पहचान छिपाकर पुष्टि करने की सुविधा चालू करना

हालांकि, इस कोडलैब में पुष्टि करने पर फ़ोकस नहीं किया गया है, लेकिन हमारे ऐप्लिकेशन में पुष्टि करने का कोई तरीका होना ज़रूरी है. हम बिना नाम के लॉगिन का इस्तेमाल करेंगे. इसका मतलब है कि उपयोगकर्ता को बिना किसी प्रॉम्प्ट के चुपचाप साइन इन कर दिया जाएगा.

आपको बिना पहचान बताए लॉगिन करने की सुविधा चालू करनी होगी.

  1. Firebase कंसोल में, बाईं ओर मौजूद नेविगेशन मेन्यू में बनाएं सेक्शन ढूंढें.
  2. पुष्टि पर क्लिक करें. इसके बाद, साइन-इन करने का तरीका टैब पर क्लिक करें. इसके अलावा, सीधे इस टैब पर जाने के लिए यहां क्लिक करें.
  3. बिना नाम के साइन-इन करने की सुविधा देने वाली कंपनी को चालू करें. इसके बाद, सेव करें पर क्लिक करें.

img7.png

इससे ऐप्लिकेशन को वेब ऐप्लिकेशन ऐक्सेस करने वाले उपयोगकर्ताओं के लिए, बिना किसी सूचना के साइन इन करने की अनुमति मिल जाएगी. ज़्यादा जानने के लिए, पहचान छिपाकर पुष्टि करने से जुड़े दस्तावेज़ पढ़ें.

Cloud Firestore चालू करना

यह ऐप्लिकेशन, Cloud Firestore का इस्तेमाल करके रेस्टोरेंट की जानकारी और रेटिंग सेव करता है और उन्हें ऐक्सेस करता है.

आपको Cloud Firestore चालू करना होगा. Firebase कंसोल के बनाएं सेक्शन में, Firestore डेटाबेस पर क्लिक करें. Cloud Firestore विंडो में, डेटाबेस बनाएं पर क्लिक करें.

Cloud Firestore में डेटा का ऐक्सेस, सुरक्षा नियमों के ज़रिए कंट्रोल किया जाता है. हम इस कोडलैब में बाद में नियमों के बारे में ज़्यादा बात करेंगे. हालांकि, शुरू करने के लिए हमें अपने डेटा पर कुछ बुनियादी नियम सेट करने होंगे. Firebase कंसोल के नियम टैब में जाकर, यहां दिए गए नियम जोड़ें. इसके बाद, पब्लिश करें पर क्लिक करें.

rules_version = '2';
service cloud.firestore {

  // Determine if the value of the field "key" is the same
  // before and after the request.
  function unchanged(key) {
    return (key in resource.data)
      && (key in request.resource.data)
      && (resource.data[key] == request.resource.data[key]);
  }

  match /databases/{database}/documents {
    // Restaurants:
    //   - Authenticated user can read
    //   - Authenticated user can create/update (for demo purposes only)
    //   - Updates are allowed if no fields are added and name is unchanged
    //   - Deletes are not allowed (default)
    match /restaurants/{restaurantId} {
      allow read: if request.auth != null;
      allow create: if request.auth != null;
      allow update: if request.auth != null
                    && (request.resource.data.keys() == resource.data.keys())
                    && unchanged("name");

      // Ratings:
      //   - Authenticated user can read
      //   - Authenticated user can create if userId matches
      //   - Deletes and updates are not allowed (default)
      match /ratings/{ratingId} {
        allow read: if request.auth != null;
        allow create: if request.auth != null
                      && request.resource.data.userId == request.auth.uid;
      }
    }
  }
}

हम इन नियमों और इनके काम करने के तरीके के बारे में, कोडलैब में बाद में चर्चा करेंगे.

3. सैंपल कोड पाना

कमांड लाइन से GitHub रिपॉज़िटरी का क्लोन बनाएं:

git clone https://github.com/firebase/friendlyeats-web

सैंपल कोड को 📁friendlyeats-web डायरेक्ट्री में क्लोन किया जाना चाहिए. अब से, इस डायरेक्ट्री से अपने सभी निर्देश चलाएं:

cd friendlyeats-web/vanilla-js

स्टार्टर ऐप्लिकेशन इंपोर्ट करना

अपने IDE (WebStorm, Atom, Sublime, Visual Studio Code...) का इस्तेमाल करके, 📁friendlyeats-web डायरेक्ट्री खोलें या इंपोर्ट करें. इस डायरेक्ट्री में, कोडलैब के लिए शुरुआती कोड मौजूद है. इसमें, रेस्टोरेंट के सुझाव देने वाला ऐसा ऐप्लिकेशन शामिल है जो फ़िलहाल काम नहीं कर रहा है. हम इस कोडलैब के दौरान इसे काम करने लायक बनाएंगे. इसलिए, आपको जल्द ही उस डायरेक्ट्री में मौजूद कोड में बदलाव करना होगा.

4. Firebase कमांड-लाइन इंटरफ़ेस इंस्टॉल करना

Firebase कमांड लाइन इंटरफ़ेस (सीएलआई) की मदद से, वेब ऐप्लिकेशन को स्थानीय तौर पर चलाया जा सकता है. साथ ही, वेब ऐप्लिकेशन को Firebase होस्टिंग पर डिप्लॉय किया जा सकता है.

  1. सीएलआई को इंस्टॉल करने के लिए, यह npm कमांड चलाएं:
npm -g install firebase-tools
  1. यह पुष्टि करें कि सीएलआई सही तरीके से इंस्टॉल किया गया है. इसके लिए, यह कमांड चलाएं:
firebase --version

पक्का करें कि Firebase CLI का वर्शन v7.4.0 या उसके बाद का हो.

  1. यहां दी गई कमांड चलाकर, Firebase CLI को अनुमति दें:
firebase login

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

  1. पक्का करें कि आपकी कमांड लाइन, आपके ऐप्लिकेशन की लोकल डायरेक्ट्री को ऐक्सेस कर रही हो.
  2. अपने ऐप्लिकेशन को Firebase प्रोजेक्ट से जोड़ने के लिए, यह कमांड चलाएं:
firebase use --add
  1. जब कहा जाए, तब अपना प्रोजेक्ट आईडी चुनें. इसके बाद, अपने Firebase प्रोजेक्ट को कोई दूसरा नाम दें.

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

  1. कमांड लाइन में दिए गए बाकी निर्देशों का पालन करें.

5. लोकल सर्वर चलाएं

अब हम अपने ऐप्लिकेशन पर काम शुरू करने के लिए तैयार हैं! आइए, अपने ऐप्लिकेशन को स्थानीय तौर पर चलाएं!

  1. Firebase CLI का यह निर्देश चलाएं:
firebase emulators:start --only hosting
  1. आपकी कमांड लाइन में यह जवाब दिखना चाहिए:
hosting: Local server: http://localhost:5000

हम अपने ऐप्लिकेशन को स्थानीय तौर पर चलाने के लिए, Firebase होस्टिंग एम्युलेटर का इस्तेमाल कर रहे हैं. अब वेब ऐप्लिकेशन, http://localhost:5000 पर उपलब्ध होना चाहिए.

  1. अपने ऐप्लिकेशन को http://localhost:5000 पर खोलें.

आपको FriendlyEats की अपनी कॉपी दिखेगी, जो आपके Firebase प्रोजेक्ट से कनेक्ट की गई है.

ऐप्लिकेशन, आपके Firebase प्रोजेक्ट से अपने-आप कनेक्ट हो गया है. साथ ही, आपको बिना किसी सूचना के, गुमनाम उपयोगकर्ता के तौर पर साइन इन कर दिया गया है.

img2.png

6. Cloud Firestore में डेटा लिखना

इस सेक्शन में, हम Cloud Firestore में कुछ डेटा लिखेंगे, ताकि हम ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) को भर सकें. इसे Firebase कंसोल के ज़रिए मैन्युअल तरीके से किया जा सकता है. हालांकि, हम इसे ऐप्लिकेशन में ही करेंगे, ताकि Cloud Firestore में डेटा लिखने का तरीका दिखाया जा सके.

डेटा मॉडल

Firestore के डेटा को कलेक्शन, दस्तावेज़, फ़ील्ड, और सब-कलेक्शन में बांटा जाता है. हम हर रेस्टोरेंट को एक दस्तावेज़ के तौर पर, टॉप-लेवल के कलेक्शन में सेव करेंगे. इस कलेक्शन का नाम restaurants होगा.

img3.png

बाद में, हम हर समीक्षा को हर रेस्टोरेंट के ratings नाम की सब-कलेक्शन में सेव करेंगे.

img4.png

Firestore में रेस्टोरेंट जोड़ना

हमारे ऐप्लिकेशन में मुख्य मॉडल ऑब्जेक्ट, रेस्टोरेंट है. आइए, एक ऐसा कोड लिखते हैं जो restaurants कलेक्शन में रेस्टोरेंट का दस्तावेज़ जोड़ता है.

  1. डाउनलोड की गई फ़ाइलों में जाकर, scripts/FriendlyEats.Data.js खोलें.
  2. FriendlyEats.prototype.addRestaurant फ़ंक्शन ढूंढें.
  3. पूरे फ़ंक्शन को इस कोड से बदलें.

FriendlyEats.Data.js

FriendlyEats.prototype.addRestaurant = function(data) {
  var collection = firebase.firestore().collection('restaurants');
  return collection.add(data);
};

ऊपर दिया गया कोड, restaurants कलेक्शन में एक नया दस्तावेज़ जोड़ता है. दस्तावेज़ का डेटा, सामान्य JavaScript ऑब्जेक्ट से मिलता है. इसके लिए, हम सबसे पहले Cloud Firestore कलेक्शन का रेफ़रंस पाते हैं restaurants इसके बाद, डेटा को add करते हैं.

आइए, रेस्टोरेंट जोड़ें!

  1. अपने ब्राउज़र में FriendlyEats ऐप्लिकेशन पर वापस जाएं और उसे रीफ़्रेश करें.
  2. मॉक डेटा जोड़ें पर क्लिक करें.

ऐप्लिकेशन, रेस्टोरेंट के ऑब्जेक्ट का एक रैंडम सेट अपने-आप जनरेट करेगा. इसके बाद, आपके addRestaurant फ़ंक्शन को कॉल करेगा. हालांकि, आपको अपने वेब ऐप्लिकेशन में अभी डेटा नहीं दिखेगा, क्योंकि हमें अब भी डेटा फिर से पाने की सुविधा लागू करनी है (कोड लैब का अगला सेक्शन).

हालांकि, अगर Firebase कंसोल में Cloud Firestore टैब पर जाएं, तो अब आपको restaurants कलेक्शन में नए दस्तावेज़ दिखने चाहिए!

img6.png

बधाई हो, आपने वेब ऐप्लिकेशन से Cloud Firestore में डेटा लिख लिया है!

अगले सेक्शन में, आपको Cloud Firestore से डेटा वापस पाने और उसे अपने ऐप्लिकेशन में दिखाने का तरीका बताया जाएगा.

7. Cloud Firestore से डेटा दिखाना

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

सबसे पहले, हम ऐसी क्वेरी बनाते हैं जो रेस्टोरेंट की डिफ़ॉल्ट और फ़िल्टर नहीं की गई सूची दिखाएगी.

  1. फ़ाइल scripts/FriendlyEats.Data.js पर वापस जाएं.
  2. FriendlyEats.prototype.getAllRestaurants फ़ंक्शन ढूंढें.
  3. पूरे फ़ंक्शन को इस कोड से बदलें.

FriendlyEats.Data.js

FriendlyEats.prototype.getAllRestaurants = function(renderer) {
  var query = firebase.firestore()
      .collection('restaurants')
      .orderBy('avgRating', 'desc')
      .limit(50);

  this.getDocumentsInQuery(query, renderer);
};

ऊपर दिए गए कोड में, हमने एक क्वेरी बनाई है. यह क्वेरी, restaurants नाम के टॉप-लेवल कलेक्शन से ज़्यादा से ज़्यादा 50 रेस्टोरेंट को वापस लाएगी. इन रेस्टोरेंट को औसत रेटिंग के हिसाब से क्रम में लगाया गया है. फ़िलहाल, सभी की रेटिंग शून्य है. इस क्वेरी को डिक्लेयर करने के बाद, हम इसे getDocumentsInQuery() तरीके पर भेजते हैं. यह तरीका, डेटा को लोड और रेंडर करने के लिए ज़िम्मेदार होता है.

हम स्नैपशॉट लिसनर जोड़कर ऐसा करेंगे.

  1. फ़ाइल scripts/FriendlyEats.Data.js पर वापस जाएं.
  2. FriendlyEats.prototype.getDocumentsInQuery फ़ंक्शन ढूंढें.
  3. पूरे फ़ंक्शन को इस कोड से बदलें.

FriendlyEats.Data.js

FriendlyEats.prototype.getDocumentsInQuery = function(query, renderer) {
  query.onSnapshot(function(snapshot) {
    if (!snapshot.size) return renderer.empty(); // Display "There are no restaurants".

    snapshot.docChanges().forEach(function(change) {
      if (change.type === 'removed') {
        renderer.remove(change.doc);
      } else {
        renderer.display(change.doc);
      }
    });
  });
};

ऊपर दिए गए कोड में, query.onSnapshot हर बार क्वेरी के नतीजे में बदलाव होने पर, अपने कॉलबैक को ट्रिगर करेगा.

  • पहली बार, क्वेरी के पूरे नतीजे के साथ कॉलबैक ट्रिगर होता है. इसका मतलब है कि Cloud Firestore से पूरा restaurants कलेक्शन. इसके बाद, यह सभी दस्तावेज़ों को renderer.display फ़ंक्शन को पास करता है.
  • किसी दस्तावेज़ को मिटाने पर, change.type की वैल्यू removed के बराबर हो जाती है. इसलिए, इस मामले में हम एक ऐसे फ़ंक्शन को कॉल करेंगे जो रेस्टोरेंट को यूज़र इंटरफ़ेस (यूआई) से हटा देगा.

अब हमने दोनों तरीकों को लागू कर दिया है. ऐप्लिकेशन को रीफ़्रेश करें और पुष्टि करें कि Firebase कंसोल में पहले दिखने वाले रेस्टोरेंट अब ऐप्लिकेशन में दिख रहे हैं. अगर आपने इस सेक्शन को पूरा कर लिया है, तो इसका मतलब है कि आपका ऐप्लिकेशन अब Cloud Firestore के साथ डेटा को पढ़ और लिख रहा है!

रेस्टोरेंट की सूची में बदलाव होने पर, यह लिसनर अपने-आप अपडेट होता रहेगा. Firebase कंसोल पर जाकर, किसी रेस्टोरेंट को मैन्युअल तरीके से मिटाएं या उसका नाम बदलें. आपको बदलाव तुरंत अपनी साइट पर दिखेंगे!

img5.png

8. Get() डेटा

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

हमें एक ऐसा तरीका लागू करना होगा जो तब ट्रिगर हो, जब कोई उपयोगकर्ता आपके ऐप्लिकेशन में किसी रेस्टोरेंट पर क्लिक करे.

  1. अपनी फ़ाइल scripts/FriendlyEats.Data.js पर वापस जाएं.
  2. FriendlyEats.prototype.getRestaurant फ़ंक्शन ढूंढें.
  3. पूरे फ़ंक्शन को इस कोड से बदलें.

FriendlyEats.Data.js

FriendlyEats.prototype.getRestaurant = function(id) {
  return firebase.firestore().collection('restaurants').doc(id).get();
};

इस तरीके को लागू करने के बाद, आपको हर रेस्टोरेंट के पेज दिखेंगे. सूची में मौजूद किसी रेस्टोरेंट पर क्लिक करें. इसके बाद, आपको रेस्टोरेंट की ज़्यादा जानकारी वाला पेज दिखेगा:

img1.png

फ़िलहाल, रेटिंग नहीं जोड़ी जा सकतीं. हमें अब भी कोडलैब में रेटिंग जोड़ने की सुविधा लागू करनी है.

9. डेटा को क्रम से लगाना और फ़िल्टर करना

फ़िलहाल, हमारा ऐप्लिकेशन रेस्टोरेंट की सूची दिखाता है. हालांकि, इसमें लोगों की ज़रूरतों के हिसाब से फ़िल्टर करने का कोई विकल्प नहीं है. इस सेक्शन में, फ़िल्टर करने की सुविधा चालू करने के लिए, Cloud Firestore की ऐडवांस क्वेरी का इस्तेमाल किया जाएगा.

यहां सभी Dim Sum रेस्टोरेंट फ़ेच करने के लिए, सामान्य क्वेरी का एक उदाहरण दिया गया है:

var filteredQuery = query.where('category', '==', 'Dim Sum')

नाम से ही पता चलता है कि where() तरीके से, हमारी क्वेरी सिर्फ़ उन सदस्यों को डाउनलोड करेगी जिनके फ़ील्ड, हमारी तय की गई पाबंदियों को पूरा करते हैं. इस मामले में, यह सिर्फ़ उन रेस्टोरेंट की जानकारी डाउनलोड करेगा जहां category, Dim Sum है.

हमारे ऐप्लिकेशन में, उपयोगकर्ता कई फ़िल्टर को एक साथ इस्तेमाल करके खास क्वेरी बना सकता है. जैसे, "सैन फ़्रांसिस्को में पिज़्ज़ा" या "लॉस एंजेलिस में सीफ़ूड, लोकप्रियता के हिसाब से क्रम में लगाया गया".

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

  1. अपनी फ़ाइल scripts/FriendlyEats.Data.js पर वापस जाएं.
  2. FriendlyEats.prototype.getFilteredRestaurants फ़ंक्शन ढूंढें.
  3. पूरे फ़ंक्शन को इस कोड से बदलें.

FriendlyEats.Data.js

FriendlyEats.prototype.getFilteredRestaurants = function(filters, renderer) {
  var query = firebase.firestore().collection('restaurants');

  if (filters.category !== 'Any') {
    query = query.where('category', '==', filters.category);
  }

  if (filters.city !== 'Any') {
    query = query.where('city', '==', filters.city);
  }

  if (filters.price !== 'Any') {
    query = query.where('price', '==', filters.price.length);
  }

  if (filters.sort === 'Rating') {
    query = query.orderBy('avgRating', 'desc');
  } else if (filters.sort === 'Reviews') {
    query = query.orderBy('numRatings', 'desc');
  }

  this.getDocumentsInQuery(query, renderer);
};

ऊपर दिए गए कोड में, उपयोगकर्ता के इनपुट के आधार पर एक कॉम्पाउंड क्वेरी बनाने के लिए, कई where फ़िल्टर और एक orderBy क्लॉज़ जोड़ा गया है. अब हमारी क्वेरी में सिर्फ़ वे रेस्टोरेंट दिखेंगे जो उपयोगकर्ता की ज़रूरतों के मुताबिक हैं.

अपने ब्राउज़र में FriendlyEats ऐप्लिकेशन को रीफ़्रेश करें. इसके बाद, पुष्टि करें कि कीमत, शहर, और कैटगरी के हिसाब से फ़िल्टर किया जा सकता है. जांच करते समय, आपको अपने ब्राउज़र के JavaScript कंसोल में गड़बड़ियां दिखेंगी. ये गड़बड़ियां इस तरह दिखेंगी:

The query requires an index. You can create it here: https://console.firebase.google.com/project/project-id/database/firestore/indexes?create_composite=...

ये गड़बड़ियां इसलिए होती हैं, क्योंकि Cloud Firestore को ज़्यादातर कंपाउंड क्वेरी के लिए इंडेक्स की ज़रूरत होती है. क्वेरी के लिए इंडेक्स की ज़रूरत होने से, Cloud Firestore बड़े पैमाने पर तेज़ी से काम करता है.

गड़बड़ी के मैसेज में दिए गए लिंक को खोलने पर, Firebase कंसोल में इंडेक्स बनाने का यूज़र इंटरफ़ेस (यूआई) अपने-आप खुल जाएगा. इसमें सही पैरामीटर पहले से भरे होंगे. अगले सेक्शन में, हम इस ऐप्लिकेशन के लिए ज़रूरी इंडेक्स लिखेंगे और उन्हें डिप्लॉय करेंगे.

10. इंडेक्स डिप्लॉय करना

अगर हमें अपने ऐप्लिकेशन में हर पाथ को एक्सप्लोर नहीं करना है और इंडेक्स बनाने के हर लिंक को फ़ॉलो नहीं करना है, तो Firebase CLI का इस्तेमाल करके एक साथ कई इंडेक्स आसानी से डिप्लॉय किए जा सकते हैं.

  1. आपके ऐप्लिकेशन की डाउनलोड की गई लोकल डायरेक्ट्री में, आपको firestore.indexes.json फ़ाइल मिलेगी.

इस फ़ाइल में, फ़िल्टर के सभी संभावित कॉम्बिनेशन के लिए ज़रूरी सभी इंडेक्स के बारे में बताया गया है.

firestore.indexes.json

{
 "indexes": [
   {
     "collectionGroup": "restaurants",
     "queryScope": "COLLECTION",
     "fields": [
       { "fieldPath": "city", "order": "ASCENDING" },
       { "fieldPath": "avgRating", "order": "DESCENDING" }
     ]
   },

   ...

 ]
}
  1. इन इंडेक्स को डिप्लॉय करने के लिए, यह कमांड इस्तेमाल करें:
firebase deploy --only firestore:indexes

कुछ मिनटों के बाद, आपके इंडेक्स लाइव हो जाएंगे और गड़बड़ी के मैसेज हट जाएंगे.

11. लेन-देन में डेटा लिखना

इस सेक्शन में, हम उपयोगकर्ताओं के लिए रेस्टोरेंट की समीक्षाएं सबमिट करने की सुविधा जोड़ेंगे. अब तक, हमारे सभी राइट ऑपरेशन एटॉमिक और आसान रहे हैं. अगर इनमें से किसी में कोई गड़बड़ी होती है, तो हम उपयोगकर्ता को फिर से कोशिश करने के लिए कहेंगे या हमारा ऐप्लिकेशन अपने-आप लिखने की कोशिश करेगा.

हमारे ऐप्लिकेशन का इस्तेमाल करने वाले कई लोग, किसी रेस्टोरेंट को रेटिंग देना चाहेंगे. इसलिए, हमें कई बार डेटा पढ़ने और लिखने की प्रोसेस को मैनेज करना होगा. सबसे पहले, समीक्षा सबमिट करनी होगी. इसके बाद, रेस्टोरेंट की रेटिंग count और average rating को अपडेट करना होगा. अगर इनमें से कोई एक ऑपरेशन पूरा नहीं होता है, तो डेटाबेस में मौजूद डेटा में अंतर आ जाता है. ऐसा इसलिए होता है, क्योंकि डेटाबेस के एक हिस्से में मौजूद डेटा, दूसरे हिस्से में मौजूद डेटा से मेल नहीं खाता.

Cloud Firestore में ट्रांज़ैक्शन की सुविधा उपलब्ध है. इसकी मदद से, हम एक ही ऐटम ऑपरेशन में कई बार डेटा पढ़ और लिख सकते हैं. इससे यह पक्का होता है कि हमारा डेटा एक जैसा बना रहे.

  1. अपनी फ़ाइल scripts/FriendlyEats.Data.js पर वापस जाएं.
  2. FriendlyEats.prototype.addRating फ़ंक्शन ढूंढें.
  3. पूरे फ़ंक्शन को इस कोड से बदलें.

FriendlyEats.Data.js

FriendlyEats.prototype.addRating = function(restaurantID, rating) {
  var collection = firebase.firestore().collection('restaurants');
  var document = collection.doc(restaurantID);
  var newRatingDocument = document.collection('ratings').doc();

  return firebase.firestore().runTransaction(function(transaction) {
    return transaction.get(document).then(function(doc) {
      var data = doc.data();

      var newAverage =
          (data.numRatings * data.avgRating + rating.rating) /
          (data.numRatings + 1);

      transaction.update(document, {
        numRatings: data.numRatings + 1,
        avgRating: newAverage
      });
      return transaction.set(newRatingDocument, rating);
    });
  });
};

ऊपर दिए गए ब्लॉक में, हमने रेस्टोरेंट के दस्तावेज़ में avgRating और numRatings की संख्या वाली वैल्यू को अपडेट करने के लिए, एक लेन-देन ट्रिगर किया है. साथ ही, हम नई rating को ratings सब-कलेक्शन में जोड़ते हैं.

12. अपने डेटा को सुरक्षित रखना

इस कोडलैब की शुरुआत में, हमने अपने ऐप्लिकेशन के लिए सुरक्षा के नियम सेट किए थे, ताकि ऐप्लिकेशन के ऐक्सेस को सीमित किया जा सके.

firestore.rules

rules_version = '2';
service cloud.firestore {

  // Determine if the value of the field "key" is the same
  // before and after the request.
  function unchanged(key) {
    return (key in resource.data)
      && (key in request.resource.data)
      && (resource.data[key] == request.resource.data[key]);
  }

  match /databases/{database}/documents {
    // Restaurants:
    //   - Authenticated user can read
    //   - Authenticated user can create/update (for demo purposes only)
    //   - Updates are allowed if no fields are added and name is unchanged
    //   - Deletes are not allowed (default)
    match /restaurants/{restaurantId} {
      allow read: if request.auth != null;
      allow create: if request.auth != null;
      allow update: if request.auth != null
                    && (request.resource.data.keys() == resource.data.keys())
                    && unchanged("name");

      // Ratings:
      //   - Authenticated user can read
      //   - Authenticated user can create if userId matches
      //   - Deletes and updates are not allowed (default)
      match /ratings/{ratingId} {
        allow read: if request.auth != null;
        allow create: if request.auth != null
                      && request.resource.data.userId == request.auth.uid;
      }
    }
  }
}

इन नियमों के तहत, ऐक्सेस को सीमित किया जाता है, ताकि क्लाइंट सिर्फ़ सुरक्षित बदलाव कर सकें. उदाहरण के लिए:

  • रेस्टोरेंट के दस्तावेज़ में किए गए अपडेट से सिर्फ़ रेटिंग में बदलाव हो सकता है. नाम या अन्य ऐसे डेटा में बदलाव नहीं किया जा सकता जिसे बदला नहीं जा सकता.
  • रेटिंग सिर्फ़ तब बनाई जा सकती हैं, जब उपयोगकर्ता आईडी, साइन इन किए गए उपयोगकर्ता से मेल खाता हो. इससे स्पूफ़िंग को रोका जा सकता है.

Firebase कंसोल के बजाय, Firebase CLI का इस्तेमाल करके भी अपने Firebase प्रोजेक्ट में नियम डिप्लॉय किए जा सकते हैं. आपकी वर्किंग डायरेक्ट्री में मौजूद firestore.rules फ़ाइल में, ऊपर दिए गए नियम पहले से मौजूद हैं. अगर आपको Firebase कंसोल के बजाय, अपने लोकल फ़ाइल सिस्टम से इन नियमों को डिप्लॉय करना है, तो यह कमांड चलाएं:

firebase deploy --only firestore:rules

13. नतीजा

इस कोडलैब में, आपने Cloud Firestore की मदद से बुनियादी और ऐडवांस रीड और राइट ऑपरेशन करने का तरीका सीखा. साथ ही, सुरक्षा नियमों की मदद से डेटा ऐक्सेस को सुरक्षित करने का तरीका भी सीखा. आपको पूरा समाधान quickstarts-js repository में मिलेगा.

Cloud Firestore के बारे में ज़्यादा जानने के लिए, यहां दिए गए संसाधन देखें:

14. [ज़रूरी नहीं] ऐप्लिकेशन की जांच की सुविधा लागू करना

Firebase App Check की मदद से, आपके ऐप्लिकेशन को सुरक्षित रखा जा सकता है. यह आपके ऐप्लिकेशन पर आने वाले अवांछित ट्रैफ़िक की पुष्टि करने और उसे रोकने में मदद करता है. इस चरण में, reCAPTCHA Enterprise के साथ App Check जोड़कर, अपनी सेवाओं के ऐक्सेस को सुरक्षित किया जाएगा.

सबसे पहले, आपको App Check और reCaptcha को चालू करना होगा.

reCaptcha Enterprise चालू करना

  1. Cloud Console में, सुरक्षा सेक्शन में जाकर reCaptcha Enterprise को ढूंढें और चुनें.
  2. दिए गए निर्देशों के मुताबिक सेवा चालू करें. इसके बाद, की बनाएं पर क्लिक करें.
  3. दिए गए निर्देशों के मुताबिक, डिसप्ले नेम डालें. इसके बाद, प्लैटफ़ॉर्म टाइप के तौर पर वेबसाइट चुनें.
  4. डिप्लॉय किए गए यूआरएल को डोमेन की सूची में जोड़ें. साथ ही, पक्का करें कि "चेकबॉक्स चैलेंज का इस्तेमाल करें" विकल्प नहीं चुना गया हो.
  5. की बनाएं पर क्लिक करें. इसके बाद, जनरेट की गई की को किसी सुरक्षित जगह पर सेव करके रखें. आपको इस चरण में बाद में इसकी ज़रूरत होगी.

App Check की सुविधा चालू करना

  1. Firebase कंसोल में, बाएं पैनल में मौजूद Build सेक्शन पर जाएं.
  2. App Check पर क्लिक करें. इसके बाद, शुरू करें बटन पर क्लिक करें या सीधे कंसोल पर जाएं.
  3. रजिस्टर करें पर क्लिक करें. इसके बाद, जब आपसे कहा जाए, तब reCaptcha Enterprise की कुंजी डालें. इसके बाद, सेव करें पर क्लिक करें.
  4. एपीआई व्यू में, स्टोरेज को चुनें और लागू करें पर क्लिक करें. Cloud Firestore के लिए भी ऐसा ही करें.

अब App Check लागू हो जाना चाहिए! ऐप्लिकेशन को रीफ़्रेश करें और रेस्टोरेंट की प्रोफ़ाइल बनाने/देखने की कोशिश करें. आपको गड़बड़ी का यह मैसेज दिखेगा:

Uncaught Error in snapshot listener: FirebaseError: [code=permission-denied]: Missing or insufficient permissions.

इसका मतलब है कि App Check, डिफ़ॉल्ट रूप से ऐसे अनुरोधों को ब्लॉक कर रहा है जिनकी पुष्टि नहीं हुई है. अब अपने ऐप्लिकेशन में पुष्टि करने की सुविधा जोड़ें.

FriendlyEats.View.js फ़ाइल पर जाएं. इसके बाद, initAppCheck फ़ंक्शन को अपडेट करें और App Check को शुरू करने के लिए, अपनी reCaptcha कुंजी जोड़ें.

FriendlyEats.prototype.initAppCheck = function() {
    var appCheck = firebase.appCheck();
    appCheck.activate(
    new firebase.appCheck.ReCaptchaEnterpriseProvider(
      /* reCAPTCHA Enterprise site key */
    ),
    true // Set to true to allow auto-refresh.
  );
};

appCheck इंस्टेंस को आपकी कुंजी वाले ReCaptchaEnterpriseProvider से शुरू किया जाता है. साथ ही, isTokenAutoRefreshEnabled आपके ऐप्लिकेशन में टोकन को अपने-आप रीफ़्रेश होने की अनुमति देता है.

लोकल टेस्टिंग चालू करने के लिए, FriendlyEats.js फ़ाइल में वह सेक्शन ढूंढें जहाँ ऐप्लिकेशन को शुरू किया गया है. इसके बाद, FriendlyEats.prototype.initAppCheck फ़ंक्शन में यह लाइन जोड़ें:

if(isLocalhost) {
  self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
}

इससे आपके लोकल वेब ऐप्लिकेशन की कंसोल में, इस तरह का डीबग टोकन लॉग होगा:

App Check debug token: 8DBDF614-649D-4D22-B0A3-6D489412838B. You will need to add it to your app's App Check settings in the Firebase console for it to work.

अब Firebase कंसोल में, App Check के ऐप्लिकेशन व्यू पर जाएं.

ओवरफ़्लो मेन्यू पर क्लिक करें और डीबग टोकन मैनेज करें चुनें.

इसके बाद, डीबग टोकन जोड़ें पर क्लिक करें और अपनी कंसोल से डीबग टोकन को चिपकाएं.

बधाई हो! अब आपके ऐप्लिकेशन में App Check की सुविधा काम करनी चाहिए.