เริ่ม
ดูคู่มือ Get Started
ก่อนหากคุณยังไม่ได้ตั้งค่าแอปและเข้าถึงฐานข้อมูล
รับการอ้างอิงฐานข้อมูล
ในการเขียนข้อมูลลงฐานข้อมูล คุณต้องมีอินสแตนซ์ของ DatabaseReference
:
// Get the root reference location of the database. firebase::database::DatabaseReference dbref = database->GetReference();
การบันทึกข้อมูล
มีสี่วิธีในการเขียนข้อมูลไปยังฐานข้อมูลเรียลไทม์ของ Firebase:
วิธี | การใช้งานทั่วไป |
---|---|
SetValue() | เขียนหรือแทนที่ข้อมูลไปยังพาธที่กำหนด เช่น users/<user-id>/<username> |
PushChild() | เพิ่มลงในรายการข้อมูล ทุกครั้งที่คุณเรียกใช้ Push() Firebase จะสร้างคีย์เฉพาะที่สามารถใช้เป็นตัวระบุเฉพาะได้ เช่น user-scores/<user-id>/<unique-score-id> |
UpdateChildren() | อัปเดตคีย์บางส่วนสำหรับเส้นทางที่กำหนดโดยไม่ต้องแทนที่ข้อมูลทั้งหมด |
RunTransaction() | อัปเดตข้อมูลที่ซับซ้อนซึ่งอาจเสียหายจากการอัปเดตพร้อมกัน |
เขียน อัปเดต หรือลบข้อมูลที่อ้างอิง
การดำเนินการเขียนขั้นพื้นฐาน
สำหรับการดำเนินการเขียนขั้นพื้นฐาน คุณสามารถใช้ SetValue()
เพื่อบันทึกข้อมูลลงในการอ้างอิงที่ระบุ โดยแทนที่ข้อมูลใดๆ ที่มีอยู่ในเส้นทางนั้น คุณสามารถใช้วิธีนี้เพื่อส่งประเภทที่ JSON ยอมรับผ่านประเภทตัวแปรที่รองรับ:
- Null (จะเป็นการลบข้อมูล)
- จำนวนเต็ม (64 บิต)
- ตัวเลขจุดลอยตัวที่มีความแม่นยำสองเท่า
- บูลีน
- สตริง
- เวกเตอร์ของแวเรียนต์
- แผนผังของสตริงกับตัวแปร
การใช้ SetValue()
ในลักษณะนี้จะเขียนทับข้อมูลที่ตำแหน่งที่ระบุ รวมถึงโหนดย่อยด้วย อย่างไรก็ตาม คุณยังคงสามารถอัปเดตรายการย่อยได้โดยไม่ต้องเขียนออบเจ็กต์ใหม่ทั้งหมด หากคุณต้องการอนุญาตให้ผู้ใช้อัปเดตโปรไฟล์ของตน คุณสามารถอัปเดตชื่อผู้ใช้ได้ดังนี้:
dbref.Child("users").Child(userId).Child("username").SetValue(name);
ผนวกเข้ากับรายการข้อมูล
ใช้เมธอด PushChild()
เพื่อผนวกข้อมูลเข้ากับรายการในแอปพลิเคชันที่มีผู้ใช้หลายคน เมธอด PushChild()
จะสร้างคีย์ที่ไม่ซ้ำทุกครั้งที่มีการเพิ่มรายการย่อยใหม่ลงในการอ้างอิง Firebase ที่ระบุ ด้วยการใช้คีย์ที่สร้างขึ้นอัตโนมัติเหล่านี้สำหรับองค์ประกอบใหม่แต่ละรายการในรายการ ไคลเอนต์หลายรายสามารถเพิ่มลูกไปยังตำแหน่งเดียวกันในเวลาเดียวกันได้โดยไม่มีข้อขัดแย้งในการเขียน คีย์เฉพาะที่สร้างโดย PushChild()
จะขึ้นอยู่กับการประทับเวลา ดังนั้นรายการต่างๆ จะถูกเรียงลำดับตามลำดับเวลาโดยอัตโนมัติ
คุณสามารถใช้การอ้างอิงไปยังข้อมูลใหม่ที่ส่งกลับโดยเมธอด PushChild()
เพื่อรับค่าของคีย์ที่สร้างขึ้นอัตโนมัติของเด็กหรือตั้งค่าข้อมูลสำหรับเด็ก การเรียก GetKey()
ในการอ้างอิง PushChild()
จะส่งคืนค่าของคีย์ที่สร้างขึ้นอัตโนมัติ
อัปเดตฟิลด์เฉพาะ
หากต้องการเขียนไปยังโหนดย่อยที่ระบุพร้อมกันโดยไม่ต้องเขียนทับโหนดย่อยอื่นๆ ให้ใช้เมธอด UpdateChildren()
เมื่อเรียก UpdateChildren()
คุณสามารถอัปเดตค่าลูกระดับล่างได้โดยการระบุเส้นทางสำหรับคีย์ หากข้อมูลถูกจัดเก็บไว้ในหลายตำแหน่งเพื่อให้ปรับขนาดได้ดีขึ้น คุณสามารถอัปเดต อินสแตนซ์ทั้งหมดของข้อมูลนั้นได้โดยใช้การกระจายข้อมูล ตัวอย่างเช่น เกมอาจมีคลาส LeaderboardEntry
เช่นนี้
class LeaderboardEntry { std::string uid; int score = 0; public: LeaderboardEntry() { } LeaderboardEntry(std::string uid, int score) { this->uid = uid; this->score = score; } std::map<std::string, Object> ToMap() { std::map<string, Variant> result = new std::map<string, Variant>(); result["uid"] = Variant(uid); result["score"] = Variant(score); return result; } }
หากต้องการสร้าง LeaderboardEntry
และอัปเดตเป็นฟีดคะแนนล่าสุดและรายการคะแนนของผู้ใช้ไปพร้อมกัน เกมจะใช้รหัสต่อไปนี้:
void WriteNewScore(std::string userId, int score) { // Create new entry at /user-scores/$userid/$scoreid and at // /leaderboard/$scoreid simultaneously std::string key = dbref.Child("scores").PushChild().GetKey(); LeaderBoardEntry entry = new LeaderBoardEntry(userId, score); std::map<std::string, Variant> entryValues = entry.ToMap(); std::map<string, Variant> childUpdates = new std::map<string, Variant>(); childUpdates["/scores/" + key] = entryValues; childUpdates["/user-scores/" + userId + "/" + key] = entryValues; dbref.UpdateChildren(childUpdates); }
ตัวอย่างนี้ใช้ PushChild()
เพื่อสร้างรายการในโหนดที่มีรายการสำหรับผู้ใช้ทั้งหมดที่ /scores/$key
และดึงข้อมูลคีย์พร้อมกันด้วย key()
จากนั้นคีย์จะสามารถนำมาใช้เพื่อสร้างรายการที่สองในคะแนนของผู้ใช้ที่ /user-scores/$userid/$key
เมื่อใช้เส้นทางเหล่านี้ คุณสามารถดำเนินการอัปเดตพร้อมกันไปยังหลายตำแหน่งในแผนผัง JSON ได้ด้วยการเรียก UpdateChildren()
เพียงครั้งเดียว เช่น วิธีสร้างรายการใหม่ในตัวอย่างนี้ในทั้งสองตำแหน่ง การอัปเดตพร้อมกันที่ทำในลักษณะนี้เป็นแบบอะตอมมิก: การอัปเดตทั้งหมดสำเร็จหรือการอัปเดตทั้งหมดล้มเหลว
ลบข้อมูล
วิธีที่ง่ายที่สุดในการลบข้อมูลคือการเรียก RemoveValue()
โดยอ้างอิงถึงตำแหน่งของข้อมูลนั้น
คุณยังสามารถลบได้โดยระบุ Variant
เป็นค่า null
สำหรับการดำเนินการเขียนอื่น เช่น SetValue()
หรือ UpdateChildren()
คุณสามารถใช้เทคนิคนี้กับ UpdateChildren()
เพื่อลบรายการย่อยหลายรายการในการเรียก API ครั้งเดียว
รู้ว่าเมื่อใดที่ข้อมูลของคุณถูกผูกมัด
หากต้องการทราบว่าเมื่อใดที่ข้อมูลของคุณถูกส่งไปยังเซิร์ฟเวอร์ Firebase Realtime Database ให้ตรวจสอบผลลัพธ์ ในอนาคต เพื่อความสำเร็จ
บันทึกข้อมูลเป็นธุรกรรม
เมื่อทำงานกับข้อมูลที่อาจเสียหายจากการแก้ไขที่เกิดขึ้นพร้อมกัน เช่น ตัวนับส่วนเพิ่ม คุณสามารถใช้ การดำเนินการธุรกรรม ได้ คุณให้การดำเนินการนี้มีฟังก์ชัน DoTransaction
ฟังก์ชันอัพเดตนี้รับสถานะปัจจุบันของข้อมูลเป็นอาร์กิวเมนต์และส่งกลับสถานะใหม่ที่คุณต้องการเขียน หากไคลเอ็นต์อื่นเขียนไปยังตำแหน่งก่อนที่จะเขียนค่าใหม่ของคุณสำเร็จ ฟังก์ชันอัปเดตของคุณจะถูกเรียกอีกครั้งด้วยค่าปัจจุบันใหม่ และลองเขียนอีกครั้ง
ตัวอย่างเช่น ในเกม คุณสามารถอนุญาตให้ผู้ใช้อัปเดตกระดานผู้นำที่มีคะแนนสูงสุด 5 คะแนน:
void AddScoreToLeaders(std::string email, long score, DatabaseReference leaderBoardRef) { leaderBoardRef.RunTransaction([](firebase::database::MutableData* mutableData) { if (mutableData.children_count() >= MaxScores) { long minScore = LONG_MAX; MutableData *minVal = null; std::vector<MutableData> children = mutableData.children(); std::vector<MutableData>::iterator it; for (it = children.begin(); it != children.end(); ++it) { if (!it->value().is_map()) continue; long childScore = (long)it->Child("score").value().int64_value(); if (childScore < minScore) { minScore = childScore; minVal = &*it; } } if (minScore > score) { // The new score is lower than the existing 5 scores, abort. return kTransactionResultAbort; } // Remove the lowest score. children.Remove(minVal); } // Add the new high score. std::map<std::string, Variant> newScoreMap = new std::map<std::string, Variant>(); newScoreMap["score"] = score; newScoreMap["email"] = email; children.Add(newScoreMap); mutableData->set_value(children); return kTransactionResultSuccess; }); }
การใช้ธุรกรรมจะป้องกันไม่ให้ลีดเดอร์บอร์ดไม่ถูกต้องหากผู้ใช้หลายคนบันทึกคะแนนพร้อมกันหรือลูกค้ามีข้อมูลเก่า หากธุรกรรมถูกปฏิเสธ เซิร์ฟเวอร์จะส่งคืนค่าปัจจุบันไปยังไคลเอนต์ ซึ่งจะดำเนินการธุรกรรมอีกครั้งด้วยมูลค่าที่อัปเดต สิ่งนี้จะเกิดขึ้นซ้ำจนกว่าธุรกรรมจะได้รับการยอมรับหรือมีความพยายามมากเกินไป
เขียนข้อมูลแบบออฟไลน์
หากไคลเอ็นต์ขาดการเชื่อมต่อเครือข่าย แอปของคุณจะทำงานต่อไปได้อย่างถูกต้อง
ไคลเอนต์ทุกตัวที่เชื่อมต่อกับฐานข้อมูล Firebase จะรักษาเวอร์ชันภายในของข้อมูลที่ใช้งานอยู่ เมื่อมีการเขียนข้อมูล ข้อมูลจะถูกเขียนลงในเวอร์ชันท้องถิ่นนี้ก่อน จากนั้นไคลเอนต์ Firebase จะซิงโครไนซ์ข้อมูลนั้นกับเซิร์ฟเวอร์ฐานข้อมูลระยะไกลและกับไคลเอนต์อื่น ๆ ตาม "ความพยายามอย่างดีที่สุด"
ด้วยเหตุนี้ การเขียนทั้งหมดไปยังฐานข้อมูลจะทริกเกอร์เหตุการณ์ภายในเครื่องทันที ก่อนที่ข้อมูลใดๆ จะถูกเขียนไปยังเซิร์ฟเวอร์ ซึ่งหมายความว่าแอปของคุณยังคงตอบสนองโดยไม่คำนึงถึงเวลาแฝงของเครือข่ายหรือการเชื่อมต่อ
เมื่อสร้างการเชื่อมต่ออีกครั้ง แอปของคุณจะได้รับชุดเหตุการณ์ที่เหมาะสมเพื่อให้ไคลเอ็นต์ซิงค์กับสถานะเซิร์ฟเวอร์ปัจจุบัน โดยไม่ต้องเขียนโค้ดที่กำหนดเองใดๆ