เริ่มต้นใช้งาน
โปรดดูคําแนะนํา Get Started
ก่อนหากยังไม่ได้ตั้งค่าแอปและเข้าถึงฐานข้อมูล
รับ DatabaseReference
หากต้องการเขียนข้อมูลลงในฐานข้อมูล คุณต้องมีอินสแตนซ์ของ DatabaseReference
ดังนี้
// Get the root reference location of the database. firebase::database::DatabaseReference dbref = database->GetReference();
การประหยัดอินเทอร์เน็ต
การเขียนข้อมูลลงใน Firebase Realtime Database มี 4 วิธีดังนี้
วิธีการ | การใช้งานทั่วไป |
---|---|
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
และอัปเดต 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()
พร้อมกัน จากนั้นจะใช้คีย์เพื่อสร้างรายการที่ 2 ในคะแนนของผู้ใช้ที่ /user-scores/$userid/$key
ได้
เมื่อใช้เส้นทางเหล่านี้ คุณจะอัปเดตตำแหน่งหลายตำแหน่งในต้นไม้ JSON ได้พร้อมกันด้วยการเรียกใช้ UpdateChildren()
เพียงครั้งเดียว เช่น ตัวอย่างนี้สร้างรายการใหม่ในตำแหน่งทั้ง 2 ตำแหน่ง การอัปเดตที่เกิดขึ้นพร้อมกันด้วยวิธีนี้มีผลอย่างมาก ไม่ว่าจะเป็นการอัปเดตสำเร็จหรือล้มเหลว
ลบข้อมูล
วิธีที่ง่ายที่สุดในการลบข้อมูลคือการเรียกใช้ RemoveValue()
ตามการอ้างอิงตำแหน่งของข้อมูลนั้น
คุณยังลบได้โดยการระบุ null
Variant
เป็นค่าสำหรับการดำเนินการเขียนอื่น เช่น 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 จะซิงค์ข้อมูลดังกล่าวกับเซิร์ฟเวอร์ฐานข้อมูลระยะไกลและกับไคลเอ็นต์อื่นๆ โดยอิงตาม "ความพยายามที่ดีที่สุด"
ด้วยเหตุนี้ การเขียนทั้งหมดไปยังฐานข้อมูลจะทริกเกอร์เหตุการณ์ในเครื่องทันที ก่อนที่จะมีการเขียนข้อมูลไปยังเซิร์ฟเวอร์ ซึ่งหมายความว่าแอปจะยังคงตอบสนองอยู่เสมอไม่ว่าเครือข่ายจะใช้เวลาในการตอบสนองหรือการเชื่อมต่ออย่างไรก็ตาม
เมื่อมีการเชื่อมต่ออีกครั้ง แอปจะได้รับชุดเหตุการณ์ที่เหมาะสมเพื่อให้ไคลเอ็นต์ซิงค์กับสถานะเซิร์ฟเวอร์ปัจจุบันโดยไม่ต้องเขียนโค้ดที่กำหนดเองใดๆ