ทำงานกับรายการข้อมูล

รับการอ้างอิงฐานข้อมูล

หากต้องการอ่านหรือเขียนข้อมูลจากฐานข้อมูล คุณต้องมีอินสแตนซ์ของ DatabaseReference

DatabaseReference ref = FirebaseDatabase.instance.ref();

การอ่านและการเขียนรายการ

เพิ่มข้อมูลลงในรายการ

ใช้เมธอด push() เพื่อเพิ่มข้อมูลลงในรายการในแอปพลิเคชันแบบหลายผู้ใช้ เมธอด push() จะสร้างคีย์ที่ไม่ซ้ำกันทุกครั้งที่เพิ่มรายการย่อยใหม่ลงในการอ้างอิง Firebase ที่ระบุ การใช้คีย์ที่สร้างขึ้นโดยอัตโนมัติเหล่านี้สำหรับองค์ประกอบใหม่แต่ละรายการในรายการจะช่วยให้ไคลเอ็นต์หลายรายการเพิ่มรายการย่อยลงในตำแหน่งเดียวกันได้พร้อมกันโดยไม่มีข้อขัดแย้งในการเขียน คีย์ที่ไม่ซ้ำกันที่สร้างขึ้นโดย push() จะอิงตามการประทับเวลา ดังนั้นรายการในรายการจะเรียงตามลำดับเวลาโดยอัตโนมัติ

คุณสามารถใช้การอ้างอิงถึงข้อมูลใหม่ที่เมธอด push() แสดงผลเพื่อรับค่าคีย์ที่สร้างขึ้นโดยอัตโนมัติของรายการย่อย หรือตั้งค่าข้อมูลสำหรับรายการย่อย พร็อพเพอร์ตี้ .key ของการอ้างอิง push() จะมีคีย์ที่สร้างขึ้นโดยอัตโนมัติ

คุณสามารถใช้คีย์ที่สร้างขึ้นโดยอัตโนมัติเหล่านี้เพื่อลดความซับซ้อนในการทำให้โครงสร้างข้อมูลแบนราบ ดูข้อมูลเพิ่มเติมได้ที่ตัวอย่างแฟนเอาต์ (Fan-Out) ของข้อมูล

ตัวอย่างเช่น คุณสามารถใช้ push() เพื่อเพิ่มโพสต์ใหม่ลงในรายการโพสต์ในแอปพลิเคชันโซเชียลได้ ดังนี้

DatabaseReference postListRef = FirebaseDatabase.instance.ref("posts");
DatabaseReference newPostRef = postListRef.push();
newPostRef.set({
  // ...
});

รอรับเหตุการณ์ย่อย

ระบบจะทริกเกอร์เหตุการณ์ย่อยเพื่อตอบสนองต่อการดำเนินการที่เฉพาะเจาะจงซึ่งเกิดขึ้นกับรายการย่อยของโหนดจากการดำเนินการต่างๆ เช่น การเพิ่มรายการย่อยใหม่ผ่านเมธอด push() หรือการอัปเดตรายการย่อยผ่านเมธอด update()

เหตุการณ์ การใช้งานทั่วไป
onChildAdded ดึงข้อมูลรายการหรือรอรับการเพิ่มข้อมูลลงในรายการ ระบบจะทริกเกอร์เหตุการณ์นี้ 1 ครั้งสำหรับรายการย่อยที่มีอยู่แต่ละรายการ จากนั้นจะทริกเกอร์อีกครั้ง ทุกครั้งที่เพิ่มรายการย่อยใหม่ลงในเส้นทางที่ระบุ ระบบจะส่งสแนปช็อตที่มีข้อมูลของรายการย่อยใหม่ไปยัง Listener
onChildChanged รอรับการเปลี่ยนแปลงรายการในรายการ ระบบจะทริกเกอร์เหตุการณ์นี้ทุกครั้งที่แก้ไขโหนดรายการย่อย ซึ่งรวมถึง การแก้ไขรายการที่สืบทอดมาจากโหนดรายการย่อย สแนปช็อตที่ส่ง ไปยัง Listener เหตุการณ์จะมีข้อมูลที่อัปเดตของรายการย่อย
onChildRemoved รอรับการนำรายการออกจากรายการ ระบบจะทริกเกอร์เหตุการณ์นี้เมื่อ นำรายการย่อยออก สแนปช็อตที่ส่งไปยังบล็อก Callback จะมีข้อมูลของรายการย่อยที่นำออก
onChildMoved รอรับการเปลี่ยนแปลงลำดับรายการในรายการที่จัดลำดับ เหตุการณ์ onChildMoved จะเกิดขึ้นหลังเหตุการณ์ onChildChanged เสมอ ซึ่งทำให้ลำดับรายการ เปลี่ยนแปลง (ตามเมธอด orderBy ปัจจุบัน)

การใช้เหตุการณ์เหล่านี้ร่วมกันอาจมีประโยชน์สำหรับการรอรับการเปลี่ยนแปลงโหนดที่เฉพาะเจาะจงในฐานข้อมูล ตัวอย่างเช่น แอปบล็อกโซเชียลอาจใช้เมธอดเหล่านี้ร่วมกันเพื่อตรวจสอบกิจกรรมในความคิดเห็นของโพสต์ ดังที่แสดงด้านล่าง

final commentsRef = FirebaseDatabase.instance.ref("post-comments/$postId");
commentsRef.onChildAdded.listen((event) {
  // A new comment has been added, so add it to the displayed list.
});
commentsRef.onChildChanged.listen((event) {
  // A comment has changed; use the key to determine if we are displaying this
  // comment and if so displayed the changed comment.
});
commentsRef.onChildRemoved.listen((event) {
  // A comment has been removed; use the key to determine if we are displaying
  // this comment and if so remove it.
});

รอรับเหตุการณ์ Value

แม้ว่าการรอรับเหตุการณ์ย่อยจะเป็นวิธีที่แนะนำในการอ่านรายการข้อมูล แต่ก็มีบางสถานการณ์ที่การรอรับเหตุการณ์ Value ในการอ้างอิงรายการมีประโยชน์

การแนบ Listener value กับรายการข้อมูลจะแสดงผลรายการข้อมูลทั้งหมดเป็นสแนปช็อตเดียว ซึ่งคุณสามารถวนซ้ำเพื่อเข้าถึงรายการย่อยแต่ละรายการได้

แม้ว่าจะมีผลการค้นหาที่ตรงกับคำค้นหาเพียงรายการเดียว แต่สแนปช็อตก็ยังคงเป็นรายการ ซึ่งมีเพียงรายการเดียว หากต้องการเข้าถึงรายการ คุณต้องวนซ้ำผลลัพธ์ ดังนี้

myTopPostsQuery.onValue.listen((event) {
  for (final child in event.snapshot.children) {
    // Handle the post.
  }
}, onError: (error) {
  // Error.
});

รูปแบบนี้อาจมีประโยชน์เมื่อคุณต้องการดึงข้อมูลรายการย่อยทั้งหมดของรายการในการดำเนินการเดียว แทนที่จะรอรับเหตุการณ์การเพิ่มรายการย่อยเพิ่มเติม

การจัดเรียงและการกรองข้อมูล

คุณสามารถใช้คลาส Query เพื่อดึงข้อมูลที่จัดเรียงตามคีย์ ตามค่า หรือตามค่าของรายการย่อย นอกจากนี้ คุณยังกรองผลลัพธ์ที่จัดเรียงแล้วให้แสดงผลลัพธ์ตามจำนวนที่เฉพาะเจาะจง หรือตามช่วงคีย์หรือค่าที่ต้องการได้ด้วย

จัดเรียงข้อมูล

หากต้องการดึงข้อมูลที่จัดเรียงแล้ว ให้เริ่มต้นด้วยการระบุเมธอด orderBy อย่างใดอย่างหนึ่งเพื่อกำหนดวิธีจัดเรียงผลลัพธ์

เมธอด การใช้งาน
orderByChild() จัดเรียงผลลัพธ์ตามค่าของคีย์รายการย่อยที่ระบุหรือเส้นทางรายการย่อยที่ซ้อนกัน
orderByKey() จัดเรียงผลลัพธ์ตามคีย์รายการย่อย
orderByValue() จัดเรียงผลลัพธ์ตามค่ารายการย่อย

คุณใช้เมธอด orderBy ได้เพียงเมธอดเดียว ในแต่ละครั้ง การเรียกเมธอดการจัดเรียงลำดับหลายครั้งในการค้นหาเดียวกันจะทำให้เกิดข้อผิดพลาด

ตัวอย่างต่อไปนี้แสดงวิธีดึงข้อมูลรายการโพสต์ยอดนิยมของผู้ใช้ที่จัดเรียงตามจำนวนดาว

final myUserId = FirebaseAuth.instance.currentUser?.uid;
final topUserPostsRef = FirebaseDatabase.instance
    .ref("user-posts/$myUserId")
    .orderByChild("starCount");

ตัวอย่างนี้กำหนดการค้นหาที่เมื่อรวมกับ Listener รายการย่อย แล้ว จะซิงค์ไคลเอ็นต์กับโพสต์ของผู้ใช้จากเส้นทางในฐานข้อมูล ตามรหัสผู้ใช้ โดยจัดเรียงตามจำนวนดาวที่แต่ละโพสต์ได้รับ เทคนิคการใช้รหัสเป็นคีย์ดัชนีนี้เรียกว่าการกระจายข้อมูล คุณสามารถอ่าน ข้อมูลเพิ่มเติมเกี่ยวกับเทคนิคนี้ได้ใน หัวข้อการจัดโครงสร้างฐานข้อมูล

การเรียกเมธอด orderByChild() จะระบุคีย์รายการย่อยที่จะใช้จัดเรียงผลลัพธ์ ในกรณีนี้ ระบบจะจัดเรียงโพสต์ตามค่าของรายการย่อย ที่เกี่ยวข้อง "starCount" นอกจากนี้ คุณยังจัดเรียงการค้นหาตามรายการย่อยที่ซ้อนกันได้ด้วย ในกรณีที่คุณมีข้อมูลลักษณะดังนี้

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

ในกรณีนี้ เราสามารถจัดเรียงองค์ประกอบรายการตามค่าที่ซ้อนอยู่ใต้คีย์ metrics ได้โดยการระบุเส้นทางสัมพัทธ์ไปยังรายการย่อยที่ซ้อนกันในการเรียก orderByChild()

final mostViewedPosts =
    FirebaseDatabase.instance.ref('posts').orderByChild('metrics/views');

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีจัดเรียงข้อมูลประเภทอื่นๆ ได้ที่ หัวข้อ วิธีจัดเรียงข้อมูลการค้นหา

การกรองข้อมูล

หากต้องการกรองข้อมูล คุณสามารถรวมเมธอด limit หรือ range ใดก็ได้กับเมธอดการจัดเรียงลำดับ เมื่อสร้างการค้นหา

เมธอด การใช้งาน
limitToFirst() กำหนดจำนวนสูงสุดของรายการที่จะแสดงผลจากจุดเริ่มต้นของ รายการผลลัพธ์ที่จัดเรียงแล้ว
limitToLast() กำหนดจำนวนสูงสุดของรายการที่จะแสดงผลจากจุดสิ้นสุดของรายการผลลัพธ์ที่จัดเรียงแล้ว
startAt() แสดงรายการที่มากกว่าหรือเท่ากับคีย์หรือค่าที่ระบุ ทั้งนี้ขึ้นอยู่กับเมธอดการจัดเรียงลำดับที่เลือก
startAfter() แสดงรายการที่มากกว่าคีย์หรือค่าที่ระบุ ทั้งนี้ขึ้นอยู่กับเมธอดการจัดเรียงลำดับที่เลือก
endAt() แสดงรายการที่น้อยกว่าหรือเท่ากับคีย์หรือค่าที่ระบุ ทั้งนี้ขึ้นอยู่กับเมธอดการจัดเรียงลำดับที่เลือก
endBefore() แสดงรายการที่น้อยกว่าคีย์หรือค่าที่ระบุ ทั้งนี้ขึ้นอยู่กับเมธอดการจัดเรียงลำดับที่เลือก
equalTo() แสดงรายการที่เท่ากับคีย์หรือค่าที่ระบุ ทั้งนี้ขึ้นอยู่กับเมธอดการจัดเรียงลำดับที่เลือก

คุณสามารถรวมฟังก์ชัน limit หรือ range หลายฟังก์ชันได้ ซึ่งแตกต่างจากเมธอด orderBy ตัวอย่างเช่น คุณสามารถรวมเมธอด startAt() และ endAt() เพื่อจำกัดผลลัพธ์ให้แสดงเฉพาะค่าในช่วงที่ระบุ

จำกัดจำนวนผลลัพธ์

คุณสามารถใช้เมธอด limitToFirst() และ limitToLast() เพื่อกำหนดจำนวนสูงสุดของรายการย่อยที่จะซิงค์สำหรับเหตุการณ์ที่กำหนด ตัวอย่างเช่น หากคุณใช้ limitToFirst() เพื่อกำหนดขีดจำกัดไว้ที่ 100 คุณจะได้รับเหตุการณ์ onChildAdded ไม่เกิน 100 เหตุการณ์ในตอนแรก หากคุณเก็บรายการไว้ในฐานข้อมูล Firebase น้อยกว่า 100 รายการ ระบบจะทริกเกอร์เหตุการณ์ onChildAdded สำหรับแต่ละรายการ

เมื่อรายการมีการเปลี่ยนแปลง คุณจะได้รับเหตุการณ์ onChildAdded สำหรับรายการที่เข้าสู่การค้นหา และเหตุการณ์ onChildRemoved สำหรับรายการที่ออกจากผลการค้นหา เพื่อให้จำนวนรวมยังคงอยู่ที่ 100 รายการ

ตัวอย่างต่อไปนี้แสดงวิธีที่แอปบล็อกตัวอย่างกำหนดการค้นหาเพื่อดึงข้อมูลรายการโพสต์ล่าสุด 100 รายการจากผู้ใช้ทั้งหมด

final recentPostsRef = FirebaseDatabase.instance.ref('posts').limitToLast(100);

ตัวอย่างนี้กำหนดการค้นหาเท่านั้น หากต้องการซิงค์ข้อมูลจริง คุณต้องแนบ Listener

กรองตามคีย์หรือค่า

คุณสามารถใช้ startAt(), startAfter(), endAt(), endBefore() และ equalTo() เพื่อเลือกจุดเริ่มต้น จุดสิ้นสุด และจุดเทียบเท่าที่กำหนดเองสำหรับการค้นหา ซึ่งอาจมีประโยชน์สำหรับการแบ่งหน้าข้อมูลหรือการค้นหารายการที่มีรายการย่อยที่มีค่าที่เฉพาะเจาะจง

วิธีจัดเรียงข้อมูลการค้นหา

ส่วนนี้จะอธิบายวิธีจัดเรียงข้อมูลตามเมธอด orderBy แต่ละเมธอดในคลาส Query

orderByChild

เมื่อใช้ orderByChild() ระบบจะจัดเรียงข้อมูลที่มีคีย์รายการย่อยที่ระบุไว้ดังนี้

  1. รายการย่อยที่มีค่า null สำหรับคีย์รายการย่อยที่ระบุจะแสดง ก่อน
  2. รายการย่อยที่มีค่า false สำหรับคีย์รายการย่อยที่ระบุ จะแสดงถัดไป หากรายการย่อยหลายรายการมีค่า false ระบบจะจัดเรียงรายการย่อยเหล่านั้น ตามลำดับพจนานุกรมตามคีย์
  3. รายการย่อยที่มีค่า true สำหรับคีย์รายการย่อยที่ระบุ จะแสดงถัดไป หากรายการย่อยหลายรายการมีค่า true ระบบจะจัดเรียงรายการย่อยเหล่านั้น ตามลำดับพจนานุกรมตามคีย์
  4. รายการย่อยที่มีค่าเป็นตัวเลขจะแสดงถัดไป โดยจัดเรียงจากน้อยไปมาก หากรายการย่อยหลายรายการมีค่าตัวเลขเดียวกันสำหรับโหนดรายการย่อยที่ระบุ ระบบจะจัดเรียงรายการย่อยเหล่านั้นตามคีย์
  5. สตริงจะแสดงหลังตัวเลขและจัดเรียงตามลำดับพจนานุกรมจากน้อยไปมาก หากรายการย่อยหลายรายการมีค่าเดียวกันสำหรับโหนดรายการย่อยที่ระบุ ระบบจะจัดเรียงรายการย่อยเหล่านั้นตามลำดับพจนานุกรมตามคีย์
  6. ออบเจ็กต์จะแสดงเป็นรายการสุดท้ายและจัดเรียงตามลำดับพจนานุกรมตามคีย์จากน้อยไปมาก

orderByKey

เมื่อใช้ orderByKey() เพื่อจัดเรียงข้อมูล ระบบจะแสดงผลข้อมูลตามลำดับจากน้อยไปมากตามคีย์

  1. รายการย่อยที่มีคีย์ที่แยกวิเคราะห์เป็นจำนวนเต็ม 32 บิตได้จะแสดงก่อน โดยจัดเรียงจากน้อยไปมาก
  2. รายการย่อยที่มีค่าสตริงเป็นคีย์จะแสดงถัดไป โดยจัดเรียงตามลำดับพจนานุกรมจากน้อยไปมาก

orderByValue

เมื่อใช้ orderByValue() ระบบจะจัดเรียงรายการย่อยตามค่า เกณฑ์การจัดเรียงจะเหมือนกับใน orderByChild() ยกเว้นว่าจะใช้ค่าของโหนดแทนค่าของคีย์รายการย่อยที่ระบุ

ยกเลิกการแนบ Listener

ระบบจะนำ Callback ออกโดยการเรียกเมธอด off() ในการอ้างอิงฐานข้อมูล Firebase

คุณสามารถนำ Listener รายการเดียวออกได้โดยส่ง Listener เป็นพารามิเตอร์ไปยัง off() การเรียก off() ในตำแหน่งที่ไม่มีอาร์กิวเมนต์จะนำ Listener ทั้งหมดในตำแหน่งนั้นออก

การเรียก off() ใน Listener หลักจะไม่นำ Listener ที่ลงทะเบียนในโหนดรายการย่อยออกโดยอัตโนมัติ คุณต้องเรียก off() ใน Listener รายการย่อยด้วยเพื่อนำ Callback ออก

ขั้นตอนถัดไป