เอกสารนี้ครอบคลุมสี่วิธีในการเขียนข้อมูลไปยัง Firebase Realtime Database ของคุณ: ตั้งค่า อัปเดต พุช และธุรกรรม
วิธีการบันทึกข้อมูล
ชุด | เขียนหรือแทนที่ข้อมูลไปยัง เส้นทางที่กำหนด เช่น messages/users/<username> |
อัปเดต | อัปเดตคีย์บางส่วนสำหรับเส้นทางที่กำหนดโดยไม่ต้องแทนที่ข้อมูลทั้งหมด |
ดัน | เพิ่มในรายการข้อมูล ในฐานข้อมูล ทุกครั้งที่คุณพุชโหนดใหม่ไปยังรายการ ฐานข้อมูลของคุณจะสร้างคีย์เฉพาะ เช่น messages/users/<unique-user-id>/<username> |
ธุรกรรม | ใช้ธุรกรรมเมื่อทำงานกับข้อมูลที่ซับซ้อนซึ่งอาจเสียหายจากการอัปเดตพร้อมกัน |
การบันทึกข้อมูล
การดำเนินการเขียนฐานข้อมูลพื้นฐานคือชุดที่บันทึกข้อมูลใหม่ไปยังการอ้างอิงฐานข้อมูลที่ระบุ โดยแทนที่ข้อมูลที่มีอยู่ที่เส้นทางนั้น เพื่อให้เข้าใจถึงชุด เราจะสร้างแอปบล็อกอย่างง่าย ข้อมูลสำหรับแอปของคุณถูกเก็บไว้ที่การอ้างอิงฐานข้อมูลนี้:
ชวา
final FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("server/saving-data/fireblog");
โหนด 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');
หลาม
# Import database module. from firebase_admin import db # Get a database reference to our blog. ref = db.reference('server/saving-data/fireblog')
ไป
// 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()
/ setValue()
เพื่อบันทึกวัตถุผู้ใช้ลงในฐานข้อมูลด้วยชื่อผู้ใช้ ชื่อเต็ม และวันเกิดของผู้ใช้ คุณสามารถส่งชุดสตริง ตัวเลข บูลีน null
อาร์เรย์ หรือวัตถุ JSON ใดๆ การผ่าน null
จะลบข้อมูลในตำแหน่งที่ระบุ ในกรณีนี้ คุณจะส่งวัตถุ:
ชวา
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);
โหนด 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' } });
หลาม
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' } })
ไป
// 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" คุณยังสามารถบันทึกข้อมูลโดยตรงไปยังตำแหน่งย่อย:
ชวา
usersRef.child("alanisawesome").setValueAsync(new User("June 23, 1912", "Alan Turing")); usersRef.child("gracehop").setValueAsync(new User("December 9, 1906", "Grace Hopper"));
โหนด 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' });
หลาม
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' })
ไป
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) }
ตัวอย่างสองตัวอย่างข้างต้น - การเขียนค่าทั้งสองพร้อมกันเป็นวัตถุและเขียนแยกต่างหากไปยังตำแหน่งลูก - จะส่งผลให้ข้อมูลเดียวกันถูกบันทึกลงในฐานข้อมูลของคุณ:
{ "users": { "alanisawesome": { "date_of_birth": "June 23, 1912", "full_name": "Alan Turing" }, "gracehop": { "date_of_birth": "December 9, 1906", "full_name": "Grace Hopper" } } }
ตัวอย่างแรกจะทริกเกอร์เพียงหนึ่งเหตุการณ์ในไคลเอนต์ที่กำลังดูข้อมูล ในขณะที่ตัวอย่างที่สองจะทริกเกอร์สองเหตุการณ์ สิ่งสำคัญคือต้องสังเกตว่าหากข้อมูลมีอยู่แล้วที่ usersRef
วิธีแรกจะเขียนทับ แต่วิธีที่สองจะแก้ไขเฉพาะค่าของโหนดย่อยแต่ละโหนดที่แยกจากกัน ในขณะที่ปล่อยให้ลูกอื่นๆ ของ usersRef
ไม่เปลี่ยนแปลง
การอัปเดตข้อมูลที่บันทึกไว้
หากคุณต้องการเขียนไปยังโหนดย่อยหลายโหนดของตำแหน่งฐานข้อมูลพร้อมกันโดยไม่เขียนทับโหนดย่อยอื่นๆ คุณสามารถใช้วิธีการอัพเดตดังที่แสดงด้านล่าง:
ชวา
DatabaseReference hopperRef = usersRef.child("gracehop"); Map<String, Object> hopperUpdates = new HashMap<>(); hopperUpdates.put("nickname", "Amazing Grace"); hopperRef.updateChildrenAsync(hopperUpdates);
โหนด js
const usersRef = ref.child('users'); const hopperRef = usersRef.child('gracehop'); hopperRef.update({ 'nickname': 'Amazing Grace' });
หลาม
hopper_ref = users_ref.child('gracehop') hopper_ref.update({ 'nickname': 'Amazing Grace' })
ไป
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 here แทน update จะเป็นการลบทั้ง full_name
และ date_of_birth
ออกจาก hopperRef
ของคุณ
Firebase Realtime Database ยังรองรับการอัปเดตหลายเส้นทางอีกด้วย ซึ่งหมายความว่า การอัปเดตสามารถอัปเดตค่าที่ตำแหน่งต่างๆ ในฐานข้อมูลของคุณพร้อมๆ กัน ซึ่งเป็นคุณลักษณะอันทรงพลังที่ช่วยให้คุณ ลดค่าปกติของข้อมูล ได้ เมื่อใช้การอัปเดตหลายเส้นทาง คุณสามารถเพิ่มชื่อเล่นให้กับทั้ง Grace และ Alan ได้พร้อมกัน:
ชวา
Map<String, Object> userUpdates = new HashMap<>(); userUpdates.put("alanisawesome/nickname", "Alan The Machine"); userUpdates.put("gracehop/nickname", "Amazing Grace"); usersRef.updateChildrenAsync(userUpdates);
โหนด js
const usersRef = ref.child('users'); usersRef.update({ 'alanisawesome/nickname': 'Alan The Machine', 'gracehop/nickname': 'Amazing Grace' });
หลาม
users_ref.update({ 'alanisawesome/nickname': 'Alan The Machine', 'gracehop/nickname': 'Amazing Grace' })
ไป
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) }
หลังจากการอัปเดตนี้ ทั้งอลันและเกรซได้เพิ่มชื่อเล่น:
{ "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 แทนด้วยวิธีนี้:
ชวา
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);
โหนด js
const usersRef = ref.child('users'); usersRef.update({ 'alanisawesome': { 'nickname': 'Alan The Machine' }, 'gracehop': { 'nickname': 'Amazing Grace' } });
หลาม
users_ref.update({ 'alanisawesome': { 'nickname': 'Alan The Machine' }, 'gracehop': { 'nickname': 'Amazing Grace' } })
ไป
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" } } }
การเพิ่มการเรียกกลับที่เสร็จสมบูรณ์
ใน Node.js และ Java Admin SDK หากคุณต้องการทราบว่าข้อมูลของคุณได้รับการคอมมิตเมื่อใด คุณสามารถเพิ่มการเรียกกลับให้เสร็จสิ้นได้ ทั้งการตั้งค่าและอัปเดตเมธอดใน SDK เหล่านี้ใช้การเรียกกลับที่สมบูรณ์ซึ่งเป็นทางเลือก ซึ่งจะถูกเรียกใช้เมื่อการเขียนได้รับการคอมมิตไปยังฐานข้อมูล หากการโทรไม่สำเร็จด้วยเหตุผลบางอย่าง การเรียกกลับจะถูกส่งผ่านอ็อบเจ็กต์ข้อผิดพลาดที่ระบุว่าเหตุใดจึงเกิดความล้มเหลว ใน Python และ Go Admin SDK วิธีการเขียนทั้งหมดจะถูกบล็อก นั่นคือ วิธีการเขียนจะไม่ส่งกลับจนกว่าการเขียนจะตกลงกับฐานข้อมูล
ชวา
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."); } } });
โหนด js
dataRef.set('I\'m writing data', (error) => { if (error) { console.log('Data could not be saved.' + error); } else { console.log('Data saved successfully.'); } });
บันทึกรายการข้อมูล
เมื่อสร้างรายการข้อมูล สิ่งสำคัญคือต้องคำนึงถึงธรรมชาติของแอปพลิเคชันส่วนใหญ่ที่มีผู้ใช้หลายคน และปรับโครงสร้างรายการของคุณให้สอดคล้องกัน จากตัวอย่างด้านบน มาเพิ่มบล็อกโพสต์ในแอปของคุณกันดีกว่า สัญชาตญาณแรกของคุณคือการใช้ set เพื่อจัดเก็บรายการย่อยที่มีดัชนีจำนวนเต็มเพิ่มขึ้นโดยอัตโนมัติ ดังต่อไปนี้:
// 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
วิธีนี้จะได้ผลหากผู้เขียนคนเดียวเพิ่มโพสต์ แต่ในแอปพลิเคชันบล็อกที่ทำงานร่วมกันของคุณ ผู้ใช้หลายคนอาจเพิ่มโพสต์พร้อมกัน หากผู้เขียนสองคนเขียนถึง /posts/2
พร้อมกัน โพสต์หนึ่งจะถูกลบโดยอีกโพสต์หนึ่ง
เพื่อแก้ปัญหานี้ ไคลเอนต์ Firebase จัดเตรียมฟังก์ชัน push()
ที่สร้าง คีย์ เฉพาะสำหรับแต่ละลูกใหม่ ด้วยการใช้คีย์ลูกที่ไม่ซ้ำกัน ลูกค้าหลายรายสามารถเพิ่มลูกไปยังตำแหน่งเดียวกันในเวลาเดียวกันโดยไม่ต้องกังวลเกี่ยวกับความขัดแย้งในการเขียน
ชวา
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"));
โหนด 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' });
หลาม
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' })
ไป
// 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 ให้คุณรวมเข้าด้วยกันโดยส่งผ่านข้อมูลที่จะตั้งค่าโดยตรงไปยัง push()
ดังนี้:
ชวา
// No Java equivalent
โหนด js
// This is equivalent to the calls to push().set(...) above postsRef.push({ author: 'gracehop', title: 'Announcing COBOL, a New Programming Language' });;
หลาม
# This is equivalent to the calls to push().set(...) above posts_ref.push({ 'author': 'gracehop', 'title': 'Announcing COBOL, a New Programming Language' })
ไป
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()
จะส่งคืนการอ้างอิงไปยังเส้นทางข้อมูลใหม่ ซึ่งคุณสามารถใช้เพื่อรับคีย์หรือตั้งค่าข้อมูลได้ รหัสต่อไปนี้จะส่งผลให้ข้อมูลเหมือนกับตัวอย่างด้านบน แต่ตอนนี้เราจะสามารถเข้าถึงรหัสเฉพาะที่สร้างขึ้นได้:
ชวา
// 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();
โหนด 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;
หลาม
# 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
ไป
// 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 คุณให้การเรียกกลับสองครั้งแก่การดำเนินการธุรกรรม: ฟังก์ชันการอัพเดตและการเรียกกลับการเสร็จสิ้นที่เป็นทางเลือก ใน Python และ Go การดำเนินการธุรกรรมถูกบล็อก ดังนั้นจึงยอมรับเฉพาะฟังก์ชันอัปเดตเท่านั้น
ฟังก์ชันอัปเดตใช้สถานะปัจจุบันของข้อมูลเป็นอาร์กิวเมนต์และควรส่งคืนสถานะใหม่ที่คุณต้องการเขียน ตัวอย่างเช่น หากคุณต้องการเพิ่มจำนวนการโหวตในบล็อกโพสต์ใดโพสต์หนึ่ง คุณต้องเขียนธุรกรรมดังต่อไปนี้:
ชวา
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"); } });
โหนด js
const upvotesRef = db.ref('server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes'); upvotesRef.transaction((current_value) => { return (current_value || 0) + 1; });
หลาม
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')
ไป
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
หากไม่มีการเขียนค่าเริ่มต้น
หากโค้ดข้างต้นถูกเรียกใช้โดยไม่มีฟังก์ชันธุรกรรม และไคลเอนต์สองรายพยายามเพิ่มค่าพร้อมกัน ทั้งสองจะเขียน 1
เป็นค่าใหม่ ส่งผลให้เพิ่มขึ้นหนึ่งค่าแทนที่จะเป็นสอง
การเชื่อมต่อเครือข่ายและการเขียนแบบออฟไลน์
ไคลเอนต์ Firebase Node.js และ Java จะรักษาเวอร์ชันภายในของข้อมูลที่ใช้งานอยู่ เมื่อมีการเขียนข้อมูล ข้อมูลจะถูกเขียนลงในเวอร์ชันโลคัลนี้ก่อน จากนั้นไคลเอนต์จะซิงโครไนซ์ข้อมูลนั้นกับฐานข้อมูลและกับไคลเอนต์อื่น ๆ บนพื้นฐาน 'ความพยายามอย่างดีที่สุด'
ด้วยเหตุนี้ การเขียนข้อมูลทั้งหมดไปยังฐานข้อมูลจะทริกเกอร์เหตุการณ์ในเครื่องทันที ก่อนที่ข้อมูลใดๆ จะถูกเขียนลงในฐานข้อมูลเสียด้วยซ้ำ ซึ่งหมายความว่าเมื่อคุณเขียนแอปพลิเคชันโดยใช้ Firebase แอปของคุณจะยังคงตอบสนองโดยไม่คำนึงถึงความหน่วงของเครือข่ายหรือการเชื่อมต่ออินเทอร์เน็ต
เมื่อสร้างการเชื่อมต่อใหม่แล้ว เราจะได้รับชุดเหตุการณ์ที่เหมาะสมเพื่อให้ไคลเอ็นต์ "ตามทัน" กับสถานะเซิร์ฟเวอร์ปัจจุบัน โดยไม่ต้องเขียนโค้ดที่กำหนดเองใดๆ
การรักษาความปลอดภัยข้อมูลของคุณ
Firebase Realtime Database มีภาษารักษาความปลอดภัยที่ให้คุณกำหนดได้ว่าผู้ใช้คนใดมีสิทธิ์อ่านและเขียนโหนดต่างๆ ของข้อมูลของคุณ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ การรักษาความปลอดภัยข้อมูลของคุณ