เอกสารนี้ครอบคลุม 4 วิธีในการเขียนข้อมูลลงใน Firebase Realtime Database ได้แก่ set, update, push และการรองรับธุรกรรม
วิธีประหยัดอินเทอร์เน็ต
| ตั้งค่า | เขียนหรือแทนที่ข้อมูลในเส้นทางที่กำหนด เช่น messages/users/<username> |
| อัปเดต | อัปเดตคีย์บางรายการสำหรับเส้นทางที่กำหนดโดยไม่ต้องแทนที่ข้อมูลทั้งหมด |
| พุช | เพิ่มลงในรายการข้อมูลในฐานข้อมูล ทุกครั้งที่คุณพุชโหนดใหม่ไปยังรายการ ฐานข้อมูลจะสร้างคีย์ที่ไม่ซ้ำกัน เช่น messages/users/<unique-user-id>/<username> |
| ธุรกรรม | ใช้ธุรกรรมเมื่อทำงานกับข้อมูลที่ซับซ้อนซึ่งอาจเสียหายจากการอัปเดตพร้อมกัน |
กำลังบันทึกข้อมูล
การดำเนินการเขียนฐานข้อมูลพื้นฐานคือชุดที่บันทึกข้อมูลใหม่ไปยังการอ้างอิงฐานข้อมูลที่ระบุ โดยแทนที่ข้อมูลที่มีอยู่ในเส้นทางนั้น เพื่อให้เข้าใจ set เราจะสร้างแอปบล็อกง่ายๆ ข้อมูลสำหรับแอปของคุณจะจัดเก็บไว้ที่ข้อมูลอ้างอิงฐานข้อมูลนี้
Java
final FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("server/saving-data/fireblog");
Node.js
// Import Admin SDK const { getDatabase } = require('firebase-admin/database'); // Get a database reference to our blog const db = getDatabase(); const ref = db.ref('server/saving-data/fireblog');
Python
# Import database module. from firebase_admin import db # Get a database reference to our blog. ref = db.reference('server/saving-data/fireblog')
Go
// Create a database client from App. client, err := app.Database(ctx) if err != nil { log.Fatalln("Error initializing database client:", err) } // Get a database reference to our blog. ref := client.NewRef("server/saving-data/fireblog")
มาเริ่มด้วยการบันทึกข้อมูลผู้ใช้กัน เราจะจัดเก็บผู้ใช้แต่ละรายตามชื่อผู้ใช้ที่ไม่ซ้ำกัน และจะจัดเก็บชื่อนามสกุลและวันเกิดของผู้ใช้ด้วย เนื่องจากผู้ใช้แต่ละรายจะมีชื่อผู้ใช้ที่ไม่ซ้ำกัน การใช้เมธอด set ที่นี่จึงเหมาะสมกว่าการใช้เมธอด push เนื่องจากคุณมีคีย์อยู่แล้วและไม่จำเป็นต้องสร้างคีย์ใหม่
ก่อนอื่น ให้สร้างการอ้างอิงฐานข้อมูลไปยังข้อมูลผู้ใช้ จากนั้นใช้ set() / setValue() เพื่อบันทึกออบเจ็กต์ผู้ใช้ลงในฐานข้อมูลพร้อมชื่อผู้ใช้ ชื่อเต็ม และวันเกิดของผู้ใช้ คุณสามารถส่งชุดสตริง ตัวเลข บูลีน null อาร์เรย์ หรือออบเจ็กต์ JSON ใดก็ได้ การส่ง null จะนำข้อมูลในตำแหน่งที่ระบุออก ในกรณีนี้ คุณจะส่งออบเจ็กต์ให้ดังนี้
Java
public static class User { public String date_of_birth; public String full_name; public String nickname; public User(String dateOfBirth, String fullName) { // ... } public User(String dateOfBirth, String fullName, String nickname) { // ... } } DatabaseReference usersRef = ref.child("users"); Map<String, User> users = new HashMap<>(); users.put("alanisawesome", new User("June 23, 1912", "Alan Turing")); users.put("gracehop", new User("December 9, 1906", "Grace Hopper")); usersRef.setValueAsync(users);
Node.js
const usersRef = ref.child('users'); usersRef.set({ alanisawesome: { date_of_birth: 'June 23, 1912', full_name: 'Alan Turing' }, gracehop: { date_of_birth: 'December 9, 1906', full_name: 'Grace Hopper' } });
Python
users_ref = ref.child('users') users_ref.set({ 'alanisawesome': { 'date_of_birth': 'June 23, 1912', 'full_name': 'Alan Turing' }, 'gracehop': { 'date_of_birth': 'December 9, 1906', 'full_name': 'Grace Hopper' } })
Go
// User is a json-serializable type. type User struct { DateOfBirth string `json:"date_of_birth,omitempty"` FullName string `json:"full_name,omitempty"` Nickname string `json:"nickname,omitempty"` } usersRef := ref.Child("users") err := usersRef.Set(ctx, map[string]*User{ "alanisawesome": { DateOfBirth: "June 23, 1912", FullName: "Alan Turing", }, "gracehop": { DateOfBirth: "December 9, 1906", FullName: "Grace Hopper", }, }) if err != nil { log.Fatalln("Error setting value:", err) }
เมื่อบันทึกออบเจ็กต์ JSON ลงในฐานข้อมูล ระบบจะแมปพร็อพเพอร์ตี้ออบเจ็กต์กับตำแหน่งย่อยของฐานข้อมูลโดยอัตโนมัติในลักษณะที่ซ้อนกัน ตอนนี้หากคุณไปที่ URL https://docs-examples.firebaseio.com/server/saving-data/fireblog/users/alanisawesome/full_name คุณจะเห็นค่า "Alan Turing" นอกจากนี้ คุณยังบันทึกข้อมูลไปยังตำแหน่งย่อยได้โดยตรงด้วย โดยทำดังนี้
Java
usersRef.child("alanisawesome").setValueAsync(new User("June 23, 1912", "Alan Turing")); usersRef.child("gracehop").setValueAsync(new User("December 9, 1906", "Grace Hopper"));
Node.js
const usersRef = ref.child('users'); usersRef.child('alanisawesome').set({ date_of_birth: 'June 23, 1912', full_name: 'Alan Turing' }); usersRef.child('gracehop').set({ date_of_birth: 'December 9, 1906', full_name: 'Grace Hopper' });
Python
users_ref.child('alanisawesome').set({ 'date_of_birth': 'June 23, 1912', 'full_name': 'Alan Turing' }) users_ref.child('gracehop').set({ 'date_of_birth': 'December 9, 1906', 'full_name': 'Grace Hopper' })
Go
if err := usersRef.Child("alanisawesome").Set(ctx, &User{ DateOfBirth: "June 23, 1912", FullName: "Alan Turing", }); err != nil { log.Fatalln("Error setting value:", err) } if err := usersRef.Child("gracehop").Set(ctx, &User{ DateOfBirth: "December 9, 1906", FullName: "Grace Hopper", }); err != nil { log.Fatalln("Error setting value:", err) }
ตัวอย่าง 2 รายการข้างต้น ซึ่งก็คือการเขียนค่าทั้ง 2 ค่าพร้อมกันเป็นออบเจ็กต์และการเขียนค่าแยกกันไปยังตำแหน่งย่อย จะส่งผลให้ระบบบันทึกข้อมูลเดียวกันลงในฐานข้อมูล ดังนี้
{
"users": {
"alanisawesome": {
"date_of_birth": "June 23, 1912",
"full_name": "Alan Turing"
},
"gracehop": {
"date_of_birth": "December 9, 1906",
"full_name": "Grace Hopper"
}
}
}
ตัวอย่างแรกจะทริกเกอร์เหตุการณ์เดียวในไคลเอ็นต์ที่กำลังดูข้อมูลอยู่ ส่วนตัวอย่างที่ 2 จะทริกเกอร์ 2 เหตุการณ์ โปรดทราบว่าหากมีข้อมูลอยู่ที่ usersRef อยู่แล้ว วิธีแรกจะเขียนทับข้อมูลดังกล่าว แต่วิธีที่ 2 จะแก้ไขเฉพาะค่าของโหนดระดับย่อยที่แยกกันแต่ละโหนด โดยปล่อยให้โหนดระดับย่อยอื่นๆ ของ usersRef ไม่เปลี่ยนแปลง
กำลังอัปเดตข้อมูลที่บันทึกไว้
หากต้องการเขียนไปยังโหนดย่อยหลายโหนดของตำแหน่งฐานข้อมูลพร้อมกันโดยไม่เขียนทับโหนดย่อยอื่นๆ คุณสามารถใช้วิธีอัปเดตดังที่แสดงด้านล่าง
Java
DatabaseReference hopperRef = usersRef.child("gracehop"); Map<String, Object> hopperUpdates = new HashMap<>(); hopperUpdates.put("nickname", "Amazing Grace"); hopperRef.updateChildrenAsync(hopperUpdates);
Node.js
const usersRef = ref.child('users'); const hopperRef = usersRef.child('gracehop'); hopperRef.update({ 'nickname': 'Amazing Grace' });
Python
hopper_ref = users_ref.child('gracehop') hopper_ref.update({ 'nickname': 'Amazing Grace' })
Go
hopperRef := usersRef.Child("gracehop") if err := hopperRef.Update(ctx, map[string]interface{}{ "nickname": "Amazing Grace", }); err != nil { log.Fatalln("Error updating child:", err) }
การดำเนินการนี้จะอัปเดตข้อมูลของ Grace ให้รวมชื่อเล่นของเธอด้วย หากคุณใช้ set ที่นี่แทน update ระบบจะลบทั้ง full_name และ date_of_birth ออกจาก hopperRef
Firebase Realtime Database ยังรองรับการอัปเดตแบบหลายเส้นทางด้วย ซึ่งหมายความว่าตอนนี้การอัปเดตสามารถอัปเดตค่าในหลายตำแหน่งในฐานข้อมูลพร้อมกันได้ ซึ่งเป็นฟีเจอร์ที่มีประสิทธิภาพซึ่งช่วยให้คุณดีนอร์มัลไลซ์ข้อมูลได้ เมื่อใช้การอัปเดตแบบหลายเส้นทาง คุณจะเพิ่มชื่อเล่นให้กับทั้ง Grace และ Alan ได้พร้อมกัน ดังนี้
Java
Map<String, Object> userUpdates = new HashMap<>(); userUpdates.put("alanisawesome/nickname", "Alan The Machine"); userUpdates.put("gracehop/nickname", "Amazing Grace"); usersRef.updateChildrenAsync(userUpdates);
Node.js
const usersRef = ref.child('users'); usersRef.update({ 'alanisawesome/nickname': 'Alan The Machine', 'gracehop/nickname': 'Amazing Grace' });
Python
users_ref.update({ 'alanisawesome/nickname': 'Alan The Machine', 'gracehop/nickname': 'Amazing Grace' })
Go
if err := usersRef.Update(ctx, map[string]interface{}{ "alanisawesome/nickname": "Alan The Machine", "gracehop/nickname": "Amazing Grace", }); err != nil { log.Fatalln("Error updating children:", err) }
หลังจากอัปเดตนี้ ทั้ง Alan และ Grace จะมีชื่อเล่นเพิ่มเข้ามา ดังนี้
{
"users": {
"alanisawesome": {
"date_of_birth": "June 23, 1912",
"full_name": "Alan Turing",
"nickname": "Alan The Machine"
},
"gracehop": {
"date_of_birth": "December 9, 1906",
"full_name": "Grace Hopper",
"nickname": "Amazing Grace"
}
}
}โปรดทราบว่าการพยายามอัปเดตออบเจ็กต์โดยการเขียนออบเจ็กต์ที่มีเส้นทางรวมอยู่ด้วยจะส่งผลให้เกิดลักษณะการทำงานที่แตกต่างกัน มาดูสิ่งที่จะเกิดขึ้นหากคุณพยายามอัปเดต Grace และ Alan ด้วยวิธีนี้แทน
Java
Map<String, Object> userNicknameUpdates = new HashMap<>(); userNicknameUpdates.put("alanisawesome", new User(null, null, "Alan The Machine")); userNicknameUpdates.put("gracehop", new User(null, null, "Amazing Grace")); usersRef.updateChildrenAsync(userNicknameUpdates);
Node.js
const usersRef = ref.child('users'); usersRef.update({ 'alanisawesome': { 'nickname': 'Alan The Machine' }, 'gracehop': { 'nickname': 'Amazing Grace' } });
Python
users_ref.update({ 'alanisawesome': { 'nickname': 'Alan The Machine' }, 'gracehop': { 'nickname': 'Amazing Grace' } })
Go
if err := usersRef.Update(ctx, map[string]interface{}{ "alanisawesome": &User{Nickname: "Alan The Machine"}, "gracehop": &User{Nickname: "Amazing Grace"}, }); err != nil { log.Fatalln("Error updating children:", err) }
ซึ่งจะส่งผลให้เกิดลักษณะการทำงานที่แตกต่างกัน กล่าวคือ การเขียนทับโหนด /users ทั้งหมด
{
"users": {
"alanisawesome": {
"nickname": "Alan The Machine"
},
"gracehop": {
"nickname": "Amazing Grace"
}
}
}การเพิ่ม Callback การดำเนินการเสร็จสมบูรณ์
ใน Node.js และ Java Admin SDK หากต้องการทราบว่าระบบคอมมิตข้อมูลเมื่อใด คุณสามารถเพิ่ม Callback สำหรับการดำเนินการเสร็จสมบูรณ์ได้ ทั้งเมธอด set และ update ใน SDK เหล่านี้จะใช้ Callback การดำเนินการให้เสร็จสมบูรณ์ (ไม่บังคับ) ซึ่งจะเรียกใช้เมื่อมีการคอมมิตการเขียนลงในฐานข้อมูล หากการเรียกไม่สำเร็จเนื่องจากสาเหตุบางประการ ระบบจะส่งออบเจ็กต์ข้อผิดพลาดไปยัง Callback เพื่อระบุสาเหตุที่เกิดความล้มเหลว ใน Python และ Go Admin SDK เมธอดการเขียนทั้งหมดจะบล็อก กล่าวคือ เมธอดการเขียนจะไม่แสดงผลจนกว่าจะมีการคอมมิตการเขียนลงในฐานข้อมูล
Java
DatabaseReference dataRef = ref.child("data"); dataRef.setValue("I'm writing data", new DatabaseReference.CompletionListener() { @Override public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) { if (databaseError != null) { System.out.println("Data could not be saved " + databaseError.getMessage()); } else { System.out.println("Data saved successfully."); } } });
Node.js
dataRef.set('I\'m writing data', (error) => { if (error) { console.log('Data could not be saved.' + error); } else { console.log('Data saved successfully.'); } });
การบันทึกรายการข้อมูล
เมื่อสร้างรายการข้อมูล คุณควรคำนึงถึงลักษณะการใช้งานแบบหลายคนหนึ่งเครื่องของแอปพลิเคชันส่วนใหญ่และปรับโครงสร้างรายการให้สอดคล้องกัน จากตัวอย่างข้างต้น เราจะเพิ่มบล็อกโพสต์ลงในแอปของคุณ สัญชาตญาณแรกของคุณอาจเป็นการใช้ชุดเพื่อจัดเก็บรายการย่อยที่มีดัชนีจำนวนเต็มที่เพิ่มขึ้นโดยอัตโนมัติ ดังนี้
// NOT RECOMMENDED - use push() instead! { "posts": { "0": { "author": "gracehop", "title": "Announcing COBOL, a New Programming Language" }, "1": { "author": "alanisawesome", "title": "The Turing Machine" } } }
หากผู้ใช้เพิ่มโพสต์ใหม่ ระบบจะจัดเก็บเป็น /posts/2 วิธีนี้จะได้ผลก็ต่อเมื่อมีผู้เขียนเพียงคนเดียวที่เพิ่มโพสต์ แต่ในแอปพลิเคชันบล็อกที่ทำงานร่วมกัน ผู้ใช้หลายคนอาจเพิ่มโพสต์พร้อมกัน หากผู้เขียน 2 คนเขียนไปยัง /posts/2 พร้อมกัน โพสต์หนึ่งจะถูกลบโดยอีกโพสต์หนึ่ง
เพื่อแก้ปัญหานี้ ไคลเอ็นต์ Firebase มีฟังก์ชัน push() ที่สร้างคีย์ที่ไม่ซ้ำกันสำหรับโหนดย่อยใหม่แต่ละโหนด การใช้คีย์ย่อยที่ไม่ซ้ำกันช่วยให้ไคลเอ็นต์หลายรายเพิ่มรายการย่อยไปยังตำแหน่งเดียวกันพร้อมกันได้โดยไม่ต้องกังวลเกี่ยวกับความขัดแย้งในการเขียน
Java
public static class Post { public String author; public String title; public Post(String author, String title) { // ... } } DatabaseReference postsRef = ref.child("posts"); DatabaseReference newPostRef = postsRef.push(); newPostRef.setValueAsync(new Post("gracehop", "Announcing COBOL, a New Programming Language")); // We can also chain the two calls together postsRef.push().setValueAsync(new Post("alanisawesome", "The Turing Machine"));
Node.js
const newPostRef = postsRef.push(); newPostRef.set({ author: 'gracehop', title: 'Announcing COBOL, a New Programming Language' }); // we can also chain the two calls together postsRef.push().set({ author: 'alanisawesome', title: 'The Turing Machine' });
Python
posts_ref = ref.child('posts') new_post_ref = posts_ref.push() new_post_ref.set({ 'author': 'gracehop', 'title': 'Announcing COBOL, a New Programming Language' }) # We can also chain the two calls together posts_ref.push().set({ 'author': 'alanisawesome', 'title': 'The Turing Machine' })
Go
// Post is a json-serializable type. type Post struct { Author string `json:"author,omitempty"` Title string `json:"title,omitempty"` } postsRef := ref.Child("posts") newPostRef, err := postsRef.Push(ctx, nil) if err != nil { log.Fatalln("Error pushing child node:", err) } if err := newPostRef.Set(ctx, &Post{ Author: "gracehop", Title: "Announcing COBOL, a New Programming Language", }); err != nil { log.Fatalln("Error setting value:", err) } // We can also chain the two calls together if _, err := postsRef.Push(ctx, &Post{ Author: "alanisawesome", Title: "The Turing Machine", }); err != nil { log.Fatalln("Error pushing child node:", err) }
คีย์ที่ไม่ซ้ำกันจะอิงตามการประทับเวลา ดังนั้นระบบจะจัดเรียงรายการตามลำดับเวลาโดยอัตโนมัติ เนื่องจาก Firebase สร้างคีย์ที่ไม่ซ้ำกันสำหรับบล็อกโพสต์แต่ละรายการ จึงไม่มีความขัดแย้งในการเขียนเกิดขึ้นหากผู้ใช้หลายคนเพิ่มโพสต์พร้อมกัน ตอนนี้ข้อมูลฐานข้อมูลของคุณจะมีลักษณะดังนี้
{
"posts": {
"-JRHTHaIs-jNPLXOQivY": {
"author": "gracehop",
"title": "Announcing COBOL, a New Programming Language"
},
"-JRHTHaKuITFIhnj02kE": {
"author": "alanisawesome",
"title": "The Turing Machine"
}
}
}
ใน JavaScript, Python และ Go รูปแบบการเรียก push() แล้วเรียก set() ทันทีเป็นรูปแบบที่พบบ่อยมาก Firebase SDK จึงให้คุณรวมทั้ง 2 เมธอดเข้าด้วยกันได้โดยส่งข้อมูลที่จะตั้งค่าไปยัง push() โดยตรง ดังนี้
Java
// No Java equivalentNode.js
// This is equivalent to the calls to push().set(...) above postsRef.push({ author: 'gracehop', title: 'Announcing COBOL, a New Programming Language' });;
Python
# This is equivalent to the calls to push().set(...) above posts_ref.push({ 'author': 'gracehop', 'title': 'Announcing COBOL, a New Programming Language' })
Go
if _, err := postsRef.Push(ctx, &Post{ Author: "gracehop", Title: "Announcing COBOL, a New Programming Language", }); err != nil { log.Fatalln("Error pushing child node:", err) }
การรับคีย์ที่ไม่ซ้ำกันซึ่งสร้างโดย push()
การเรียกใช้ push() จะแสดงผลการอ้างอิงไปยังเส้นทางข้อมูลใหม่ ซึ่งคุณสามารถใช้เพื่อรับคีย์หรือตั้งค่าข้อมูลให้กับคีย์ได้ โค้ดต่อไปนี้จะส่งผลให้ได้ข้อมูลเดียวกับตัวอย่างด้านบน แต่ตอนนี้เราจะเข้าถึงคีย์ที่ไม่ซ้ำกันซึ่งสร้างขึ้นได้
Java
// Generate a reference to a new location and add some data using push() DatabaseReference pushedPostRef = postsRef.push(); // Get the unique ID generated by a push() String postId = pushedPostRef.getKey();
Node.js
// Generate a reference to a new location and add some data using push() const newPostRef = postsRef.push(); // Get the unique key generated by push() const postId = newPostRef.key;
Python
# Generate a reference to a new location and add some data using push() new_post_ref = posts_ref.push() # Get the unique key generated by push() post_id = new_post_ref.key
Go
// Generate a reference to a new location and add some data using Push() newPostRef, err := postsRef.Push(ctx, nil) if err != nil { log.Fatalln("Error pushing child node:", err) } // Get the unique key generated by Push() postID := newPostRef.Key
ดังที่เห็น คุณสามารถรับค่าของคีย์ที่ไม่ซ้ำกันได้จากข้อมูลอ้างอิง push()
ในส่วนถัดไปเกี่ยวกับการดึงข้อมูล เราจะเรียนรู้วิธีอ่านข้อมูลนี้จากฐานข้อมูล Firebase
การบันทึกข้อมูลธุรกรรม
เมื่อทำงานกับข้อมูลที่ซับซ้อนซึ่งอาจเสียหายจากการแก้ไขที่เกิดขึ้นพร้อมกัน เช่น ตัวนับแบบเพิ่มทีละน้อย SDK จะมีการดำเนินการธุรกรรม
ใน Java และ Node.js คุณจะให้ Callback 2 รายการแก่การดำเนินการธุรกรรม ได้แก่ ฟังก์ชันอัปเดตและ Callback การดำเนินการเสร็จสมบูรณ์ (ไม่บังคับ) ใน Python และ Go การดำเนินการธุรกรรมจะบล็อก ดังนั้นจึงยอมรับเฉพาะฟังก์ชันการอัปเดตเท่านั้น
ฟังก์ชันอัปเดตจะใช้สถานะปัจจุบันของข้อมูลเป็นอาร์กิวเมนต์และควรแสดงผลสถานะใหม่ที่ต้องการซึ่งคุณต้องการเขียน ตัวอย่างเช่น หากต้องการเพิ่มจำนวนการโหวตเห็นด้วยในบล็อกโพสต์ที่เฉพาะเจาะจง คุณจะต้องเขียนธุรกรรมดังต่อไปนี้
Java
DatabaseReference upvotesRef = ref.child("server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes"); upvotesRef.runTransaction(new Transaction.Handler() { @Override public Transaction.Result doTransaction(MutableData mutableData) { Integer currentValue = mutableData.getValue(Integer.class); if (currentValue == null) { mutableData.setValue(1); } else { mutableData.setValue(currentValue + 1); } return Transaction.success(mutableData); } @Override public void onComplete( DatabaseError databaseError, boolean committed, DataSnapshot dataSnapshot) { System.out.println("Transaction completed"); } });
Node.js
const upvotesRef = db.ref('server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes'); upvotesRef.transaction((current_value) => { return (current_value || 0) + 1; });
Python
def increment_votes(current_value): return current_value + 1 if current_value else 1 upvotes_ref = db.reference('server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes') try: new_vote_count = upvotes_ref.transaction(increment_votes) print('Transaction completed') except db.TransactionAbortedError: print('Transaction failed to commit')
Go
fn := func(t db.TransactionNode) (interface{}, error) { var currentValue int if err := t.Unmarshal(¤tValue); err != nil { return nil, err } return currentValue + 1, nil } ref := client.NewRef("server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes") if err := ref.Transaction(ctx, fn); err != nil { log.Fatalln("Transaction failed to commit:", err) }
ตัวอย่างด้านบนจะตรวจสอบว่าตัวนับเป็น null หรือยังไม่ได้เพิ่มขึ้น เนื่องจากสามารถเรียกธุรกรรมด้วย null ได้หากไม่มีการเขียนค่าเริ่มต้น
หากโค้ดด้านบนทำงานโดยไม่มีฟังก์ชันธุรกรรมและไคลเอ็นต์ 2 รายพยายามเพิ่มค่าพร้อมกัน ทั้ง 2 รายจะเขียน 1 เป็นค่าใหม่ ส่งผลให้มีการเพิ่มค่าเพียงครั้งเดียวแทนที่จะเป็น 2 ครั้ง
การเชื่อมต่อเครือข่ายและการเขียนแบบออฟไลน์
ไคลเอ็นต์ Firebase Node.js และ Java จะเก็บรักษาเวอร์ชันภายในของข้อมูลที่ใช้งานอยู่ของตนเอง เมื่อมีการเขียนข้อมูล ระบบจะเขียนลงในเวอร์ชันในเครื่องนี้ก่อน จากนั้นไคลเอ็นต์จะซิงค์ข้อมูลดังกล่าวกับฐานข้อมูลและไคลเอ็นต์อื่นๆ ตามความสามารถสูงสุด
ด้วยเหตุนี้ การเขียนทั้งหมดลงในฐานข้อมูลจะทริกเกอร์เหตุการณ์ในเครื่องทันที ก่อนที่จะมีการเขียนข้อมูลลงในฐานข้อมูลด้วยซ้ำ ซึ่งหมายความว่าเมื่อคุณเขียนแอปพลิเคชันโดยใช้ Firebase แอปจะยังคงตอบสนองได้ไม่ว่าเวลาในการตอบสนองของเครือข่ายหรือการเชื่อมต่ออินเทอร์เน็ตจะเป็นอย่างไร
เมื่อสร้างการเชื่อมต่อใหม่แล้ว เราจะได้รับชุดเหตุการณ์ที่เหมาะสมเพื่อให้ไคลเอ็นต์ "ตามทัน" สถานะเซิร์ฟเวอร์ปัจจุบัน โดยไม่ต้องเขียนโค้ดที่กำหนดเอง
การรักษาความปลอดภัยของข้อมูล
Firebase Realtime Database มีภาษาด้านความปลอดภัยที่ช่วยให้คุณกำหนดได้ว่าผู้ใช้รายใดมีสิทธิ์อ่านและเขียนในโหนดต่างๆ ของข้อมูล อ่านข้อมูลเพิ่มเติมได้ในหัวข้อรักษาความปลอดภัยให้ข้อมูลของคุณ