ก่อนเริ่มต้น
คุณต้องทำสิ่งต่อไปนี้ก่อนจึงจะใช้ Realtime Database ได้
ลงทะเบียนโปรเจ็กต์ Unity และกำหนดค่าให้ใช้ Firebase
หากโปรเจ็กต์ Unity ใช้ Firebase อยู่แล้ว แสดงว่าโปรเจ็กต์ดังกล่าวลงทะเบียนและกำหนดค่าสำหรับ Firebase แล้ว
หากไม่มีโปรเจ็กต์ Unity คุณสามารถดาวน์โหลดแอปตัวอย่างได้
เพิ่ม Firebase Unity SDK (โดยเฉพาะ
FirebaseDatabase.unitypackage) ลงในโปรเจ็กต์ Unity
โปรดทราบว่าการเพิ่ม Firebase ลงในโปรเจ็กต์ Unity เกี่ยวข้องกับงานทั้งในคอนโซล Firebase และในโปรเจ็กต์ Unity ที่เปิดอยู่ (เช่น คุณดาวน์โหลดไฟล์การกำหนดค่า Firebase จากคอนโซล แล้วย้ายไฟล์เหล่านั้นไปยังโปรเจ็กต์ Unity)
การจัดโครงสร้างข้อมูล
คู่มือนี้ครอบคลุมแนวคิดหลักบางประการเกี่ยวกับสถาปัตยกรรมข้อมูลและแนวทางปฏิบัติแนะนำในการจัดโครงสร้างข้อมูล JSON ใน Firebase Realtime Database
การสร้างฐานข้อมูลที่มีโครงสร้างอย่างเหมาะสมต้องอาศัยการวางแผนล่วงหน้าพอสมควร ที่สำคัญที่สุดคือ คุณต้องวางแผนวิธีบันทึกข้อมูลและดึงข้อมูลในภายหลังเพื่อให้กระบวนการนั้นง่ายที่สุดเท่าที่จะเป็นไปได้
วิธีจัดโครงสร้างข้อมูล: โครงสร้างแบบต้นไม้ JSON
ข้อมูล Firebase Realtime Database ทั้งหมดจะจัดเก็บเป็นออบเจ็กต์ JSON คุณสามารถคิดว่าฐานข้อมูลเป็นต้นไม้ JSON ที่โฮสต์ในระบบคลาวด์ ซึ่งแตกต่างจากฐานข้อมูล SQL ตรงที่ไม่มีตารางหรือระเบียน เมื่อคุณเพิ่มข้อมูลลงในแผนผัง JSON ข้อมูลดังกล่าวจะกลายเป็นโหนดในโครงสร้าง JSON ที่มีอยู่ซึ่งมีคีย์ที่เชื่อมโยง คุณสามารถระบุคีย์ของคุณเอง เช่น รหัสผู้ใช้หรือชื่อเชิงความหมาย หรือจะระบุคีย์ให้คุณโดยใช้เมธอด Push() ก็ได้
ตัวอย่างเช่น ลองพิจารณาแอปพลิเคชันแชทที่อนุญาตให้ผู้ใช้จัดเก็บโปรไฟล์พื้นฐานและข้อมูลรายชื่อติดต่อ โปรไฟล์ผู้ใช้ทั่วไปจะอยู่ในเส้นทาง เช่น
/users/$uid ผู้ใช้ alovelace อาจมีรายการฐานข้อมูลที่มีลักษณะดังนี้
{ "users": { "alovelace": { "name": "Ada Lovelace", "contacts": { "ghopper": true }, }, "ghopper": { "..." }, "eclarke": { "..." } } }
แม้ว่าฐานข้อมูลจะใช้โครงสร้าง JSON แต่ข้อมูลที่จัดเก็บในฐานข้อมูลสามารถแสดงเป็นประเภทเนทีฟบางประเภทที่สอดคล้องกับประเภท JSON ที่มีอยู่เพื่อช่วยให้คุณเขียนโค้ดที่ดูแลรักษาได้ง่ายขึ้น
แนวทางปฏิบัติแนะนำสำหรับโครงสร้างข้อมูล
หลีกเลี่ยงการซ้อนข้อมูล
เนื่องจาก Firebase Realtime Database อนุญาตให้ซ้อนข้อมูลได้ลึกถึง 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 ทั้งหมด ซึ่งรวมถึงสมาชิกและข้อความทั้งหมดที่ต้องดาวน์โหลดไปยังไคลเอ็นต์
ปรับโครงสร้างข้อมูลให้เป็นแบบแฟลต
หากข้อมูลถูกแยกออกเป็นเส้นทางที่แยกจากกัน หรือที่เรียกว่าการดีนอร์มัลไลเซชัน (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": { "..." } } }
ตอนนี้คุณสามารถทำซ้ำผ่านรายการห้องแชทได้โดยดาวน์โหลดเพียงไม่กี่ไบต์ต่อการสนทนา ซึ่งจะดึงข้อมูลเมตาสำหรับการแสดงรายการหรือแสดงห้องแชทใน 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 หรือไม่ ดัชนีจะทำงานได้เร็วกว่า
และมีประสิทธิภาพมากกว่าการค้นหาหรือสแกนข้อมูล