ก่อนเริ่มต้น
ก่อนที่จะใช้ Realtime Database, ได้ คุณต้องดำเนินการต่อไปนี้
ลงทะเบียนโปรเจ็กต์ Unity และกำหนดค่าให้ใช้ Firebase
หากโปรเจ็กต์ Unity ใช้ Firebase อยู่แล้ว แสดงว่าโปรเจ็กต์ได้ลงทะเบียนและกำหนดค่าสำหรับ Firebase แล้ว
หากไม่มีโปรเจ็กต์ Unity คุณสามารถดาวน์โหลด แอปตัวอย่างได้
เพิ่ม Firebase Unity SDK (โดยเฉพาะ
FirebaseDatabase.unitypackage) ลงใน โปรเจ็กต์ Unity
โปรดทราบว่าการเพิ่ม Firebase ลงในโปรเจ็กต์ Unity เกี่ยวข้องกับงานทั้งใน Firebaseคอนโซลและในโปรเจ็กต์ Unity ที่เปิดอยู่ (เช่น คุณดาวน์โหลดไฟล์การกำหนดค่า Firebase จากคอนโซล แล้วย้าย ไฟล์เหล่านั้นลงในโปรเจ็กต์ Unity)
การบันทึกข้อมูล
มี 5 วิธีในการเขียนข้อมูลลงใน Firebase Realtime Database ดังนี้
| วิธีการ | การใช้งานทั่วไป |
|---|---|
SetValueAsync() |
เขียนหรือแทนที่ข้อมูลในเส้นทางที่กำหนด เช่น
users/<user-id>/<username>. |
SetRawJsonValueAsync() |
เขียนหรือแทนที่ข้อมูลด้วย Json ดิบ เช่น
users/<user-id>/<username>. |
Push() |
เพิ่มลงในรายการข้อมูล ทุกครั้งที่คุณเรียก
Push(), Firebase จะสร้างคีย์ที่ไม่ซ้ำกันซึ่งใช้เป็นตัวระบุที่ไม่ซ้ำกันได้ด้วย
เช่น
user-scores/<user-id>/<unique-score-id>. |
UpdateChildrenAsync() |
อัปเดตคีย์บางรายการสำหรับเส้นทางที่กำหนดโดยไม่ต้องแทนที่ข้อมูลทั้งหมด |
RunTransaction() |
อัปเดตข้อมูลที่ซับซ้อนซึ่งอาจเสียหายจากการอัปเดตพร้อมกัน |
รับ DatabaseReference
หากต้องการเขียนข้อมูลลงในฐานข้อมูล คุณต้องมีอินสแตนซ์ของ DatabaseReference ดังนี้
using Firebase; using Firebase.Database; public class MyScript: MonoBehaviour { void Start() { // Get the root reference location of the database. DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference; } }
เขียน อัปเดต หรือลบข้อมูลที่การอ้างอิง
การดำเนินการเขียนพื้นฐาน
สำหรับการดำเนินการเขียนพื้นฐาน คุณสามารถใช้ SetValueAsync() เพื่อบันทึกข้อมูลลงในการอ้างอิงที่ระบุ โดยจะแทนที่ข้อมูลที่มีอยู่ที่เส้นทางนั้น คุณสามารถใช้วิธีนี้เพื่อส่งประเภทที่สอดคล้องกับประเภท JSON ที่มีอยู่ดังนี้
stringlongdoubleboolDictionary<string, Object>List<Object>
หากใช้ออบเจ็กต์ C# ที่พิมพ์ คุณสามารถใช้ JsonUtility.ToJson() ในตัวเพื่อแปลงออบเจ็กต์เป็น Json ดิบและเรียก SetRawJsonValueAsync()
เช่น คุณอาจมีคลาสผู้ใช้ที่มีลักษณะดังนี้
public class User { public string username; public string email; public User() { } public User(string username, string email) { this.username = username; this.email = email; } }
คุณสามารถเพิ่มผู้ใช้ด้วย SetRawJsonValueAsync() ได้ดังนี้
private void writeNewUser(string userId, string name, string email) { User user = new User(name, email); string json = JsonUtility.ToJson(user); mDatabaseRef.Child("users").Child(userId).SetRawJsonValueAsync(json); }
การใช้ SetValueAsync() หรือ SetRawJsonValueAsync() ในลักษณะนี้จะเขียนทับข้อมูลในตำแหน่งที่ระบุ รวมถึงโหนดย่อย อย่างไรก็ตาม คุณยังคงอัปเดตโหนดย่อยได้โดยไม่ต้องเขียนออบเจ็กต์ทั้งหมดใหม่ หากต้องการอนุญาตให้ผู้ใช้อัปเดตโปรไฟล์ คุณสามารถอัปเดตชื่อผู้ใช้ได้ดังนี้
mDatabaseRef.Child("users").Child(userId).Child("username").SetValueAsync(name);
เพิ่มลงในรายการข้อมูล
ใช้วิธี Push() เพื่อเพิ่มข้อมูลลงในรายการในแอปพลิเคชันแบบหลายผู้ใช้
วิธี Push() จะสร้างคีย์ที่ไม่ซ้ำกันทุกครั้งที่มีการเพิ่มโหนดย่อยใหม่ลงในการอ้างอิง Firebase ที่ระบุ การใช้คีย์ที่สร้างขึ้นโดยอัตโนมัติเหล่านี้สำหรับองค์ประกอบใหม่แต่ละรายการในรายการจะช่วยให้ไคลเอ็นต์หลายรายการเพิ่มโหนดย่อยลงในตำแหน่งเดียวกันได้พร้อมกันโดยไม่มีข้อขัดแย้งในการเขียน คีย์ที่ไม่ซ้ำกันที่สร้างโดย Push() จะอิงตามการประทับเวลา ดังนั้นรายการในรายการจะเรียงตามลำดับเวลาโดยอัตโนมัติ
คุณสามารถใช้การอ้างอิงถึงข้อมูลใหม่ที่ส่งคืนโดยวิธี Push() เพื่อรับค่าของคีย์ที่สร้างขึ้นโดยอัตโนมัติของโหนดย่อยหรือตั้งค่าข้อมูลสำหรับโหนดย่อย การเรียก Key ในการอ้างอิง Push() จะส่งคืนค่าของคีย์ที่สร้างขึ้นโดยอัตโนมัติ
อัปเดตช่องที่เฉพาะเจาะจง
หากต้องการเขียนลงในโหนดย่อยที่เฉพาะเจาะจงของโหนดพร้อมกันโดยไม่เขียนทับโหนดย่อยอื่นๆ ให้ใช้วิธี UpdateChildrenAsync()
เมื่อเรียก UpdateChildrenAsync() คุณสามารถอัปเดตค่าโหนดย่อยระดับล่างได้โดย
การระบุเส้นทางสำหรับคีย์ หากจัดเก็บข้อมูลไว้ในหลายตำแหน่งเพื่อปรับขนาดให้ดีขึ้น คุณสามารถอัปเดตอินสแตนซ์ทั้งหมดของข้อมูลนั้นได้โดยใช้การกระจายข้อมูล ตัวอย่างเช่น เกมอาจมีคลาส LeaderboardEntry ดังนี้
public class LeaderboardEntry { public string uid; public int score = 0; public LeaderboardEntry() { } public LeaderboardEntry(string uid, int score) { this.uid = uid; this.score = score; } public Dictionary<string, Object> ToDictionary() { Dictionary<string, Object> result = new Dictionary<string, Object>(); result["uid"] = uid; result["score"] = score; return result; } }
หากต้องการสร้าง LeaderboardEntry และอัปเดตลงในฟีดคะแนนล่าสุดและรายการคะแนนของผู้ใช้เองพร้อมกัน เกมจะใช้โค้ดลักษณะนี้
private void WriteNewScore(string userId, int score) { // Create new entry at /user-scores/$userid/$scoreid and at // /leaderboard/$scoreid simultaneously string key = mDatabase.Child("scores").Push().Key; LeaderBoardEntry entry = new LeaderBoardEntry(userId, score); Dictionary<string, Object> entryValues = entry.ToDictionary(); Dictionary<string, Object> childUpdates = new Dictionary<string, Object>(); childUpdates["/scores/" + key] = entryValues; childUpdates["/user-scores/" + userId + "/" + key] = entryValues; mDatabase.UpdateChildrenAsync(childUpdates); }
ตัวอย่างนี้ใช้ Push() เพื่อสร้างรายการในโหนดที่มีรายการสำหรับผู้ใช้ทั้งหมดที่ /scores/$key และดึงคีย์ด้วย Key พร้อมกัน จากนั้นจะใช้คีย์เพื่อสร้างรายการที่ 2 ในคะแนนของผู้ใช้ที่ /user-scores/$userid/$key
การใช้เส้นทางเหล่านี้จะช่วยให้คุณทำการอัปเดตพร้อมกันในหลายตำแหน่งในแผนผัง JSON ได้ด้วยการเรียก UpdateChildrenAsync() เพียงครั้งเดียว เช่น วิธีที่ตัวอย่างนี้สร้างรายการใหม่ในทั้ง 2 ตำแหน่ง การอัปเดตพร้อมกันที่ทำในลักษณะนี้จะเป็นแบบอะตอมมิก กล่าวคือ การอัปเดตทั้งหมดจะสำเร็จหรือล้มเหลวทั้งหมด
ลบข้อมูล
วิธีที่ง่ายที่สุดในการลบข้อมูลคือการเรียก RemoveValue() ในการอ้างอิงถึงตำแหน่งของข้อมูลนั้น
นอกจากนี้ คุณยังลบได้โดยการระบุ null เป็นค่าสำหรับการดำเนินการเขียนอื่นๆ เช่น SetValueAsync() หรือ UpdateChildrenAsync() คุณสามารถใช้เทคนิคนี้กับ UpdateChildrenAsync() เพื่อลบโหนดย่อยหลายรายการในการเรียก API ครั้งเดียว
ทราบเมื่อข้อมูลได้รับการคอมมิต
หากต้องการทราบเมื่อข้อมูลได้รับการคอมมิตไปยังเซิร์ฟเวอร์ Firebase Realtime Database คุณ
สามารถเพิ่มการดำเนินการต่อได้ ทั้ง SetValueAsync() และ UpdateChildrenAsync() จะส่งคืน Task ที่ช่วยให้คุณทราบเมื่อการดำเนินการเสร็จสมบูรณ์ หากการเรียกไม่สำเร็จไม่ว่าด้วยเหตุผลใดก็ตาม IsFaulted ของ Task จะเป็นจริง โดยพร็อพเพอร์ตี้ Exception จะระบุสาเหตุที่ทำให้เกิดข้อผิดพลาด
บันทึกข้อมูลเป็นธุรกรรม
เมื่อทำงานกับข้อมูลที่อาจเสียหายจากการแก้ไขพร้อมกัน
เช่น ตัวนับแบบเพิ่มค่า คุณสามารถใช้การ
ดำเนินการธุรกรรมได้
คุณต้องระบุ Func สำหรับการดำเนินการนี้ Func ในการอัปเดตนี้จะใช้สถานะปัจจุบันของข้อมูลเป็นอาร์กิวเมนต์และส่งคืนสถานะใหม่ที่ต้องการเขียน หากไคลเอ็นต์อื่นเขียนไปยังตำแหน่งก่อนที่จะเขียนค่าใหม่สำเร็จ ระบบจะเรียกฟังก์ชันการอัปเดตอีกครั้งด้วยค่าปัจจุบันใหม่ และจะลองเขียนอีกครั้ง
ตัวอย่างเช่น ในเกม คุณสามารถอนุญาตให้ผู้ใช้อัปเดตลีดเดอร์บอร์ดด้วยคะแนนสูงสุด 5 อันดับได้ดังนี้
private void AddScoreToLeaders(string email, long score, DatabaseReference leaderBoardRef) { leaderBoardRef.RunTransaction(mutableData => { List<object> leaders = mutableData.Value as List<object> if (leaders == null) { leaders = new List<object>(); } else if (mutableData.ChildrenCount >= MaxScores) { long minScore = long.MaxValue; object minVal = null; foreach (var child in leaders) { if (!(child is Dictionary<string, object>)) continue; long childScore = (long) ((Dictionary<string, object>)child)["score"]; if (childScore < minScore) { minScore = childScore; minVal = child; } } if (minScore > score) { // The new score is lower than the existing 5 scores, abort. return TransactionResult.Abort(); } // Remove the lowest score. leaders.Remove(minVal); } // Add the new high score. Dictionary<string, object> newScoreMap = new Dictionary<string, object>(); newScoreMap["score"] = score; newScoreMap["email"] = email; leaders.Add(newScoreMap); mutableData.Value = leaders; return TransactionResult.Success(mutableData); }); }
การใช้ธุรกรรมจะป้องกันไม่ให้ลีดเดอร์บอร์ดไม่ถูกต้องหากผู้ใช้หลายรายบันทึกคะแนนพร้อมกันหรือไคลเอ็นต์มีข้อมูลที่ล้าสมัย หากระบบปฏิเสธธุรกรรม เซิร์ฟเวอร์จะส่งคืนค่าปัจจุบันไปยังไคลเอ็นต์ ซึ่งจะเรียกใช้ธุรกรรมอีกครั้งด้วยค่าที่อัปเดต การดำเนินการนี้จะทำซ้ำจนกว่าระบบจะยอมรับธุรกรรมหรือมีการพยายามมากเกินไป
เขียนข้อมูลแบบออฟไลน์
หากไคลเอ็นต์ขาดการเชื่อมต่อเครือข่าย แอปของคุณจะยังคงทำงานได้อย่างถูกต้อง
ไคลเอ็นต์ทุกรายการที่เชื่อมต่อกับฐานข้อมูล Firebase จะเก็บรักษาข้อมูลที่ใช้งานอยู่เวอร์ชันภายในของตัวเอง เมื่อมีการเขียนข้อมูล ระบบจะเขียนลงในเวอร์ชันภายในนี้ก่อน จากนั้นไคลเอ็นต์ Firebase จะซิงค์ข้อมูลนั้นกับเซิร์ฟเวอร์ฐานข้อมูลระยะไกลและกับไคลเอ็นต์อื่นๆ ตามความสามารถที่ดีที่สุด
ด้วยเหตุนี้ การเขียนทั้งหมดลงในฐานข้อมูลจึงทริกเกอร์เหตุการณ์ภายในทันที ก่อนที่จะมีการเขียนข้อมูลลงในเซิร์ฟเวอร์ ซึ่งหมายความว่าแอปของคุณจะยังคงตอบสนองได้ไม่ว่าจะมีเวลาในการรับส่งข้อมูลผ่านเครือข่ายหรือการเชื่อมต่อเป็นอย่างไร
เมื่อมีการเชื่อมต่ออีกครั้ง แอปของคุณจะได้รับชุดเหตุการณ์ที่เหมาะสมเพื่อให้ไคลเอ็นต์ซิงค์กับสถานะเซิร์ฟเวอร์ปัจจุบันโดยไม่ต้องเขียนโค้ดที่กำหนดเอง