এই নির্দেশিকায় ডেটা আর্কিটেকচারের কিছু মূল ধারণা এবং আপনার Firebase Realtime Database JSON ডেটা কাঠামোবদ্ধ করার সর্বোত্তম অনুশীলনগুলো আলোচনা করা হয়েছে।
একটি যথাযথভাবে কাঠামোবদ্ধ ডেটাবেস তৈরি করতে যথেষ্ট পূর্বচিন্তার প্রয়োজন হয়। সবচেয়ে গুরুত্বপূর্ণ হলো, ডেটা কীভাবে সংরক্ষণ করা হবে এবং পরবর্তীতে তা পুনরুদ্ধার করা হবে, তার পরিকল্পনা করা, যাতে এই প্রক্রিয়াটি যতটা সম্ভব সহজ হয়।
ডেটার গঠন: এটি একটি JSON ট্রি
Firebase Realtime Database সমস্ত ডেটা JSON অবজেক্ট হিসেবে সংরক্ষিত থাকে। আপনি এই ডেটাবেসটিকে একটি ক্লাউড-হোস্টেড JSON ট্রি হিসেবে ভাবতে পারেন। SQL ডেটাবেসের মতো এতে কোনো টেবিল বা রেকর্ড নেই। যখন আপনি JSON ট্রি-তে ডেটা যোগ করেন, তখন তা একটি সংশ্লিষ্ট কী (key) সহ বিদ্যমান JSON কাঠামোর একটি নোড হয়ে যায়। আপনি আপনার নিজস্ব কী (key) যেমন ইউজার আইডি বা সিমান্টিক নাম প্রদান করতে পারেন, অথবা push() মেথড ব্যবহার করে সেগুলো আপনার জন্য সরবরাহ করা হতে পারে।
উদাহরণস্বরূপ, এমন একটি চ্যাট অ্যাপ্লিকেশনের কথা ভাবুন যা ব্যবহারকারীদের একটি সাধারণ প্রোফাইল এবং পরিচিতি তালিকা সংরক্ষণ করার সুযোগ দেয়। একটি সাধারণ ব্যবহারকারী প্রোফাইল /users/$uid মতো একটি পাথে অবস্থিত থাকে। alovelace নামের ব্যবহারকারীর একটি ডাটাবেস এন্ট্রি থাকতে পারে যা দেখতে অনেকটা এইরকম:
{ "users": { "alovelace": { "name": "Ada Lovelace", "contacts": { "ghopper": true }, }, "ghopper": { "..." }, "eclarke": { "..." } } }
যদিও ডাটাবেসটি একটি JSON ট্রি ব্যবহার করে, তবুও ডাটাবেসে সংরক্ষিত ডেটাকে উপলব্ধ JSON টাইপগুলোর সাথে সঙ্গতিপূর্ণ নির্দিষ্ট নেটিভ টাইপ হিসেবে উপস্থাপন করা যেতে পারে, যা আপনাকে আরও রক্ষণাবেক্ষণযোগ্য কোড লিখতে সাহায্য করে।
ডেটা কাঠামোর জন্য সর্বোত্তম অনুশীলন
নেস্টিং ডেটা এড়িয়ে চলুন
যেহেতু Firebase Realtime Database ৩২ স্তর পর্যন্ত ডেটা নেস্ট করার সুযোগ দেয়, তাই আপনার মনে হতে পারে যে এটাই ডিফল্ট কাঠামো হওয়া উচিত। তবে, যখন আপনি আপনার ডেটাবেসের কোনো অবস্থান থেকে ডেটা ফেচ করেন, তখন আপনি তার সমস্ত চাইল্ড নোডও পেয়ে যান। এছাড়াও, যখন আপনি আপনার ডেটাবেসের কোনো নোডে কাউকে রিড বা রাইট অ্যাক্সেস দেন, তখন আপনি তাকে সেই নোডের অধীনে থাকা সমস্ত ডেটাতেও অ্যাক্সেস দিয়ে দেন। তাই, বাস্তবে, আপনার ডেটা কাঠামো যতটা সম্ভব ফ্ল্যাট রাখাই সবচেয়ে ভালো।
নেস্টেড ডেটা কেন খারাপ, তার একটি উদাহরণ হিসেবে নিম্নলিখিত একাধিক-নেস্টেড কাঠামোটি বিবেচনা করুন:
{ // 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": { "..." } } }
এখন প্রতিটি কথোপকথনের জন্য মাত্র কয়েক বাইট ডেটা ডাউনলোড করে রুমের তালিকার মধ্যে দিয়ে যাওয়া সম্ভব, যা UI-তে রুম তালিকাভুক্ত বা প্রদর্শন করার জন্য দ্রুত মেটাডেটা সংগ্রহ করে। মেসেজগুলো আলাদাভাবে সংগ্রহ করে আসার সাথে সাথেই প্রদর্শন করা যায়, ফলে UI-টি রেসপন্সিভ এবং দ্রুত থাকে।
এমন ডেটা তৈরি করুন যা পরিমাপযোগ্য।
অ্যাপ তৈরি করার সময়, প্রায়শই একটি তালিকার উপসেট ডাউনলোড করা শ্রেয়। বিশেষ করে যদি তালিকাটিতে হাজার হাজার রেকর্ড থাকে, তবে এটি বেশি প্রচলিত। যখন এই সম্পর্কটি স্থির এবং একমুখী হয়, তখন আপনি সহজেই চাইল্ড অবজেক্টগুলোকে প্যারেন্টের অধীনে নেস্ট করতে পারেন।
কখনও কখনও, এই সম্পর্কটি আরও গতিশীল হয়, অথবা এই ডেটাকে ডিনরমালাইজ করার প্রয়োজন হতে পারে। অনেক সময়, ‘ডেটা পুনরুদ্ধার’ অংশে যেমন আলোচনা করা হয়েছে, একটি কোয়েরি ব্যবহার করে ডেটার একটি উপসেট পুনরুদ্ধার করার মাধ্যমে ডেটাকে ডিনরমালাইজ করা যায়।
কিন্তু এমনকি এটাও অপর্যাপ্ত হতে পারে। উদাহরণস্বরূপ, ব্যবহারকারী এবং গ্রুপের মধ্যে একটি দ্বিমুখী সম্পর্কের কথা বিবেচনা করুন। ব্যবহারকারীরা একটি গ্রুপের সদস্য হতে পারে, এবং গ্রুপগুলো ব্যবহারকারীদের একটি তালিকা নিয়ে গঠিত। যখন একজন ব্যবহারকারী কোন কোন গ্রুপের অন্তর্ভুক্ত হবে তা নির্ধারণ করার সময় আসে, তখন বিষয়টি জটিল হয়ে ওঠে।
একজন ব্যবহারকারী কোন কোন গ্রুপের সদস্য, তা তালিকাভুক্ত করার এবং শুধুমাত্র সেই গ্রুপগুলোর ডেটা সংগ্রহ করার একটি মার্জিত উপায় প্রয়োজন। এক্ষেত্রে গ্রুপগুলোর একটি ইনডেক্স অনেক সাহায্য করতে পারে:
// 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 } }, // ... } }
আপনি হয়তো লক্ষ্য করবেন যে, এটি অ্যাডার রেকর্ড এবং গ্রুপ—উভয়ের অধীনেই সম্পর্কটি সংরক্ষণ করার মাধ্যমে কিছু ডেটার পুনরাবৃত্তি ঘটায়। এখন, alovelace একটি গ্রুপের অধীনে ইনডেক্স করা আছে এবং techpioneers অ্যাডার প্রোফাইলে তালিকাভুক্ত। সুতরাং, গ্রুপ থেকে অ্যাডাকে মুছে ফেলতে হলে, এটি দুটি জায়গাতেই আপডেট করতে হবে।
দ্বিমুখী সম্পর্কের জন্য এটি একটি প্রয়োজনীয় অতিরিক্ত ব্যবস্থা। এটি আপনাকে দ্রুত এবং দক্ষতার সাথে অ্যাডার মেম্বারশিপগুলো সংগ্রহ করতে সাহায্য করে, এমনকি যখন ব্যবহারকারী বা গ্রুপের তালিকা লক্ষ লক্ষ ছাড়িয়ে যায় অথবা যখন Realtime Database নিরাপত্তা বিধি কিছু রেকর্ডে প্রবেশে বাধা দেয়।
এই পদ্ধতিটি, যেখানে আইডিগুলোকে কী (key) হিসেবে তালিকাভুক্ত করে এবং ভ্যালু 'true' সেট করে ডেটাকে উল্টে দেওয়া হয়, তা কোনো কী-কে যাচাই করাকে /users/$uid/groups/$group_id পড়ে সেটি null কিনা তা পরীক্ষা করার মতোই সহজ করে তোলে। ডেটা কোয়েরি বা স্ক্যান করার চেয়ে ইনডেক্স দ্রুততর এবং অনেক বেশি কার্যকর।