این راهنما برخی از مفاهیم کلیدی در معماری دادهها و بهترین شیوهها برای ساختاردهی دادههای JSON در Firebase Realtime Database شما را پوشش میدهد.
ساختن یک پایگاه داده با ساختار مناسب نیاز به کمی دوراندیشی دارد. از همه مهمتر، شما باید برای نحوه ذخیره و بازیابی دادهها برنامهریزی کنید تا این فرآیند تا حد امکان آسان شود.
نحوه ساختار دادهها: این یک درخت JSON است
تمام دادههای Firebase Realtime Database به صورت اشیاء JSON ذخیره میشوند. میتوانید پایگاه داده را به عنوان یک درخت JSON میزبانی شده توسط ابر در نظر بگیرید. برخلاف پایگاه دادهی SQL، هیچ جدول یا رکوردی وجود ندارد. وقتی دادهها را به درخت JSON اضافه میکنید، به یک گره در ساختار JSON موجود با یک کلید مرتبط تبدیل میشود. میتوانید کلیدهای خودتان، مانند شناسههای کاربری یا نامهای معنایی، را ارائه دهید یا میتوانید آنها را با استفاده از childByAutoId
برای خود فراهم کنید.
برای مثال، یک برنامه چت را در نظر بگیرید که به کاربران اجازه میدهد یک پروفایل اولیه و لیست مخاطبین را ذخیره کنند. یک پروفایل کاربری معمولی در مسیری مانند /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
، شامل همه اعضا و پیامها، برای کلاینت است.
ساختارهای داده مسطح
اگر دادهها به مسیرهای جداگانه تقسیم شوند، که به آن denormalization نیز گفته میشود، میتوان آنها را در صورت نیاز، به طور کارآمد در فراخوانیهای جداگانه دانلود کرد. این ساختار مسطح را در نظر بگیرید:
{ // 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 از گروه، باید در دو جا بهروزرسانی شود.
این یک افزونگی ضروری برای روابط دو طرفه است. این به شما امکان میدهد تا به سرعت و به طور موثر عضویتهای Ada را دریافت کنید، حتی زمانی که لیست کاربران یا گروهها به میلیونها نفر میرسد یا زمانی که قوانین امنیتی Realtime Database مانع از دسترسی به برخی از رکوردها میشود.
این رویکرد، که دادهها را با فهرست کردن شناسهها به عنوان کلید و تنظیم مقدار آن روی true معکوس میکند، بررسی یک کلید را به سادگی خواندن /users/$uid/groups/$group_id
و بررسی null
بودن آن میکند. این شاخص سریعتر و بسیار کارآمدتر از پرسوجو یا اسکن دادهها است.