จัดโครงสร้างฐานข้อมูลของคุณ

คู่มือนี้ครอบคลุมแนวคิดหลักบางประการเกี่ยวกับสถาปัตยกรรมข้อมูลและ แนวทางปฏิบัติในการจัดโครงสร้างข้อมูล JSON ในฐานข้อมูลเรียลไทม์ของ Firebase

การสร้างฐานข้อมูลที่มีโครงสร้างอย่างเหมาะสมต้องอาศัยความรอบคอบพอสมควร สิ่งสำคัญที่สุดคือคุณต้องวางแผน วิธีบันทึกข้อมูล และ ที่ดึงออกมาในภายหลังเพื่อให้กระบวนการดังกล่าวง่ายที่สุด

ข้อมูลมีโครงสร้างอย่างไร: เป็นแผนผัง 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": { ... }   } } 

ตอนนี้คุณสามารถทำซ้ำผ่านรายการห้องแชทได้ด้วยการดาวน์โหลดเฉพาะ 2-3 ไบต์ต่อการสนทนา เรียกข้อมูลเมตาเพื่อแสดงข้อมูลหรือแสดงได้อย่างรวดเร็ว ห้องแชทใน UI ข้อความสามารถดึงข้อมูลแยกกันและแสดงผลเมื่อมาถึง ทำให้ UI ตอบสนอง และรวดเร็วยิ่งขึ้น

สร้างข้อมูลที่ปรับขนาด

เมื่อสร้างแอป การดาวน์โหลดรายการบางส่วนมักจะดีกว่า กรณีนี้พบได้บ่อยหากรายการมีระเบียนหลายพันรายการ เมื่อความสัมพันธ์นี้เป็นแบบคงที่และเป็นทิศทางเดียว คุณสามารถวาง ออบเจ็กต์ย่อยที่อยู่ภายใต้รายการหลัก

บางครั้ง ความสัมพันธ์นี้เป็นแบบไดนามิกมากขึ้น หรืออาจต้อง เปลี่ยนค่าปกติของข้อมูลนี้ บ่อยครั้งที่คุณสามารถถอดรหัสข้อมูลให้เป็นมาตรฐานเดียวกันได้โดยใช้ข้อความค้นหา เพื่อดึงข้อมูลบางส่วนตามที่กล่าวไว้ใน การจัดเรียงและกรองข้อมูล

แต่ถึงอย่างนั้นก็อาจไม่เพียงพอ เช่น ลองนึกถึงความสัมพันธ์แบบ 2 ทาง ระหว่างผู้ใช้และกลุ่ม ผู้ใช้สามารถอยู่ในกลุ่มได้ และกลุ่มต่างๆ ประกอบด้วย รายชื่อผู้ใช้ เมื่อต้องเลือกว่าผู้ใช้อยู่ในกลุ่มใด อะไรๆ ก็เริ่มซับซ้อน

สิ่งที่ต้องมีคือวิธีสร้างรายการกลุ่มที่ผู้ใช้เป็นสมาชิกอย่างสวยงามและ จะดึงข้อมูลสำหรับกลุ่มเหล่านั้นเท่านั้น ดัชนีของกลุ่มจะช่วย ได้เป็นอย่างดี:

// 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 กลุ่มนั้นต้องมีการอัปเดตใน 2 ที่

นี่เป็นการสำรองที่จำเป็นสำหรับความสัมพันธ์แบบ 2 ทาง ซึ่งช่วยให้คุณ ดึงข้อมูลการเป็นสมาชิกของ Ada ได้อย่างรวดเร็วและมีประสิทธิภาพ แม้เวลาที่แสดงรายชื่อผู้ใช้หรือ กลุ่มขนาดใหญ่ก็ขนาดใหญ่กว่า หลักล้านหรือกฎการรักษาความปลอดภัยของ Realtime Database ป้องกันการเข้าถึงระเบียนบางอย่าง

วิธีนี้เป็นการกลับข้อมูลโดยแสดงรหัสเป็นคีย์และตั้งค่า เป็นจริง ทำให้การตรวจหาคีย์เป็นเรื่องง่ายเหมือนการอ่าน /users/$uid/groups/$group_id และตรวจสอบว่าเป็น null หรือไม่ ดัชนีเร็วขึ้น และมีประสิทธิภาพมากกว่าการค้นหาหรือสแกนหาข้อมูล

ขั้นตอนถัดไป