अपने डेटाबेस को स्ट्रक्चर करें

इस गाइड में डेटा आर्किटेक्चर की कुछ अहम बातों और आपके Firebase रीयल टाइम डेटाबेस में JSON डेटा को तैयार करने के सबसे सही तरीकों के बारे में बताया गया है.

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

डेटा को कैसे व्यवस्थित किया जाता है: यह एक JSON ट्री है

Firebase रीयल टाइम डेटाबेस का पूरा डेटा, JSON ऑब्जेक्ट के तौर पर सेव किया जाता है. डेटाबेस को क्लाउड पर होस्ट किए गए JSON ट्री जैसा माना जा सकता है. इसमें कोई टेबल या रिकॉर्ड नहीं होता, जबकि SQL डेटाबेस में कोई टेबल या रिकॉर्ड नहीं होता. जब JSON ट्री में डेटा जोड़ा जाता है, तो यह उससे जुड़ी कुंजी वाले मौजूदा JSON स्ट्रक्चर में नोड बन जाता है. आपके पास यूज़र आईडी या सिमैंटिक नाम जैसी अपनी कुंजियां देने का विकल्प होता है. इसके अलावा, ये कुंजियां आपको push() का इस्तेमाल करके भी दी जा सकती हैं.

अगर आपको अपनी कुंजियां बनानी हैं, तो उन्हें UTF-8 कोड में बदलना ज़रूरी है. ये ज़्यादा से ज़्यादा 768 बाइट की हो सकती हैं. साथ ही, इनमें ., $, #, [, ], / या ASCII कंट्रोल वर्ण 0-31 या 127 नहीं होने चाहिए. खुद भी वैल्यू में ASCII कंट्रोल कैरेक्टर का इस्तेमाल नहीं किया जा सकता.

उदाहरण के लिए, किसी ऐसे चैट ऐप्लिकेशन पर विचार करें जो उपयोगकर्ताओं को बुनियादी प्रोफ़ाइल और संपर्क सूची सेव करने की सुविधा देता हो. एक सामान्य उपयोगकर्ता प्रोफ़ाइल, पाथ पर मौजूद होती है, जैसे कि /users/$uid. उपयोगकर्ता alovelace के पास डेटाबेस एंट्री हो सकती है, जो कुछ इस तरह दिखती है:

{
  "users": {
    "alovelace": {
      "name": "Ada Lovelace",
      "contacts": { "ghopper": true },
    },
    "ghopper": { ... },
    "eclarke": { ... }
  }
}

डेटाबेस में JSON ट्री का इस्तेमाल होता है, लेकिन डेटाबेस में सेव किए गए डेटा को उपलब्ध JSON टाइप के हिसाब से कुछ नेटिव टाइप के तौर पर दिखाया जा सकता है. इससे आपको मैनेज करने लायक कोड लिखने में मदद मिलती है.

डेटा स्ट्रक्चर के लिए सबसे सही तरीके

डेटा को नेस्ट करने से बचना

Firebase रीयल टाइम डेटाबेस, डेटा को 32 लेवल तक नेस्ट करने की सुविधा देता है. इसलिए, हो सकता है कि आप डेटा को डिफ़ॉल्ट स्ट्रक्चर के तौर पर सेट करना चाहें. हालांकि, जब डेटाबेस में किसी जगह पर डेटा फ़ेच किया जाता है, तो इसके सभी चाइल्ड नोड भी वापस आ जाते हैं. साथ ही, जब किसी व्यक्ति को अपने डेटाबेस के नोड में पढ़ने या लिखने का ऐक्सेस दिया जाता है, तो उसे उस नोड के सारे डेटा का ऐक्सेस भी दिया जाता है. इसलिए, बेहतर होगा कि अपने डेटा स्ट्रक्चर को जितना हो सके उतना फ़्लैट रखें.

नेस्ट किए गए डेटा के खराब होने के उदाहरण के लिए, मल्टीप्लाई-नेस्ट की गई संरचना का इस्तेमाल करें:

{
  // This is a poorly nested data architecture, because iterating the children
  // of the "chats" node to get a list of conversation titles requires
  // potentially downloading hundreds of megabytes of messages
  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "messages": {
        "m1": { "sender": "ghopper", "message": "Relay malfunction found. Cause: moth." },
        "m2": { ... },
        // a very long list of messages
      }
    },
    "two": { ... }
  }
}

इस नेस्ट किए गए डिज़ाइन के साथ, डेटा के ज़रिए बार-बार काम करने में समस्या आ जाती है. उदाहरण के लिए, अगर चैट पर की गई बातचीत के टाइटल की सूची बनाने के लिए, सभी सदस्यों और मैसेज के साथ-साथ पूरा chats ट्री क्लाइंट को डाउनलोड करना है, तो उसे भी डाउनलोड करना होगा.

डेटा स्ट्रक्चर को फ़्लैट करें

अगर डेटा को अलग-अलग पाथ में बांटा जाता है, तो इसे डिनॉर्मलाइज़ेशन भी कहा जाता है. ज़रूरत पड़ने पर, इसे अलग-अलग कॉल में बेहतर तरीके से डाउनलोड किया जा सकता है. इस सपाट स्ट्रक्चर का इस्तेमाल करें:

{
  // Chats contains only meta info about each conversation
  // stored under the chats's unique ID
  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
      "timestamp": 1459361875666
    },
    "two": { ... },
    "three": { ... }
  },

  // Conversation members are easily accessible
  // and stored by chat conversation ID
  "members": {
    // we'll talk about indices like this below
    "one": {
      "ghopper": true,
      "alovelace": true,
      "eclarke": true
    },
    "two": { ... },
    "three": { ... }
  },

  // Messages are separate from data we may want to iterate quickly
  // but still easily paginated and queried, and organized by chat
  // conversation ID
  "messages": {
    "one": {
      "m1": {
        "name": "eclarke",
        "message": "The relay seems to be malfunctioning.",
        "timestamp": 1459361875337
      },
      "m2": { ... },
      "m3": { ... }
    },
    "two": { ... },
    "three": { ... }
  }
}

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

स्केल करने वाला डेटा बनाएं

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

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

हालांकि, यह भी हो सकता है कि यह काफ़ी न हो. उदाहरण के लिए, उपयोगकर्ताओं और ग्रुप के बीच दो-तरफ़ा संबंध पर विचार करें. उपयोगकर्ता किसी ग्रुप में शामिल हो सकते हैं और ग्रुप में उपयोगकर्ताओं की सूची होती है. जब यह तय करना होता है कि उपयोगकर्ता किस समूह से है, तो चीज़ें जटिल हो जाती हैं.

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

// An index to track Ada's memberships
{
  "users": {
    "alovelace": {
      "name": "Ada Lovelace",
      // Index Ada's groups in her profile
      "groups": {
         // the value here doesn't matter, just that the key exists
         "techpioneers": true,
         "womentechmakers": true
      }
    },
    ...
  },
  "groups": {
    "techpioneers": {
      "name": "Historical Tech Pioneers",
      "members": {
        "alovelace": true,
        "ghopper": true,
        "eclarke": true
      }
    },
    ...
  }
}

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

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

इस तरीके से, आईडी को कुंजियों के तौर पर जोड़कर और वैल्यू को सही पर सेट करके, डेटा को उलटा जाता है. इससे किसी कुंजी की जांच करना, /users/$uid/groups/$group_id को पढ़ने जितना आसान हो जाता है. साथ ही, यह जांचना भी आसान हो जाता है कि वह null है या नहीं. इंडेक्स ज़्यादा तेज़ है और डेटा को क्वेरी या स्कैन करने की तुलना में ज़्यादा बेहतर तरीके से काम करता है.

अगले चरण