เอกสารนี้ครอบคลุมถึงการทำงานกับรายการข้อมูลใน Firebase หากต้องการดูข้อมูลเบื้องต้นเกี่ยวกับการอ่านและเขียนข้อมูล Firebase โปรดดูอ่านและเขียนข้อมูลใน Android
รับ DatabaseReference
หากต้องการอ่านและเขียนข้อมูลจากฐานข้อมูล คุณต้องมีอินสแตนซ์ของ DatabaseReference
ดังนี้
Kotlin+KTX
private lateinit var database: DatabaseReference // ... database = Firebase.database.reference
Java
private DatabaseReference mDatabase; // ... mDatabase = FirebaseDatabase.getInstance().getReference();
อ่านและเขียนรายการ
ต่อท้ายรายการข้อมูล
ใช้เมธอด push()
เพื่อต่อท้ายรายการในแอปพลิเคชันที่มีผู้ใช้หลายคน
เมธอด push()
จะสร้างคีย์ที่ไม่ซ้ำกันทุกครั้งที่มีการเรียก
ลงในการอ้างอิง Firebase ที่ระบุ ด้วยการใช้สิ่งเหล่านี้
คีย์ที่สร้างขึ้นโดยอัตโนมัติสำหรับองค์ประกอบใหม่แต่ละรายการในรายการ โดยไคลเอ็นต์หลายราย
เพิ่มเด็กไปยังตำแหน่งที่ตั้งเดียวกันพร้อมกันโดยไม่มีความขัดแย้งในการเขียน
คีย์ที่ไม่ซ้ำกันที่ push()
สร้างขึ้นจะอิงตามการประทับเวลา ดังนั้นรายการจึง
จะเรียงตามลำดับเวลาโดยอัตโนมัติ
คุณสามารถใช้การอ้างอิงข้อมูลใหม่ที่แสดงโดยเมธอด push()
เพื่อเรียก
ค่าของคีย์ที่สร้างขึ้นโดยอัตโนมัติของบุตรหลานหรือตั้งค่าข้อมูลสำหรับบุตรหลาน การโทร
getKey()
ในข้อมูลอ้างอิง push()
แสดงผลค่าของแอตทริบิวต์
ที่สร้างโดยอัตโนมัติ
คุณสามารถใช้คีย์ที่สร้างโดยอัตโนมัติเหล่านี้เพื่อลดความซับซ้อนของข้อมูล ใหม่ สำหรับข้อมูลเพิ่มเติม โปรดดูการขยายข้อมูล ตัวอย่าง
คอยฟังเหตุการณ์ย่อย
เมื่อทํางานกับลิสต์ แอปพลิเคชันควรรอฟังเหตุการณ์ย่อยแทนเหตุการณ์ที่มีค่าซึ่งใช้กับออบเจ็กต์เดี่ยว
ระบบจะทริกเกอร์เหตุการณ์ย่อยเพื่อตอบสนองต่อการดำเนินการบางอย่างที่เกิดขึ้นกับ
ย่อยของโหนดจากการดำเนินการ เช่น รายการย่อยใหม่ที่เพิ่มผ่าน
เมธอด push()
หรือย่อยที่กําลังอัปเดตผ่านเมธอด updateChildren()
การใช้ทั้ง 2 อย่างนี้รวมกันอาจมีประโยชน์สำหรับการฟังการเปลี่ยนแปลงของโหนดที่เฉพาะเจาะจง
ในฐานข้อมูล
หากต้องการฟังเหตุการณ์ของเด็กใน DatabaseReference
ให้แนบ
ChildEventListener
:
การส่งแบบฟอร์ม | การติดต่อกลับของเหตุการณ์ | การใช้งานทั่วไป |
---|---|---|
ChildEventListener
| onChildAdded() |
ดึงข้อมูลรายการต่างๆ หรือฟังการเพิ่มในรายการ
ระบบจะเรียกใช้ Callback นี้ 1 ครั้งสำหรับผู้เผยแพร่โฆษณาย่อยที่มีอยู่แต่ละรายการ จากนั้นจะส่งอีกครั้ง
ทุกครั้งที่มีการเพิ่มรายการย่อยใหม่ลงในเส้นทางที่ระบุ DataSnapshot ที่ส่งไปยัง Listener มี
ข้อมูลของเด็กใหม่
|
onChildChanged() |
ฟังการเปลี่ยนแปลงของรายการ เหตุการณ์นี้เริ่มทำงานเมื่อ
มีการแก้ไขโหนดย่อย รวมถึงการแก้ไขรายการสืบทอดของ
โหนดย่อย DataSnapshot ส่งผ่านไปยังกิจกรรม
Listener มีข้อมูลที่อัปเดตแล้วสำหรับบุตรหลาน
|
|
onChildRemoved() |
ฟังรายการที่นําออกจากรายการ
DataSnapshot ที่ส่งไปยัง Callback ของเหตุการณ์มีแอตทริบิวต์
สำหรับบุตรหลานที่ถูกนำออก
|
|
onChildMoved() |
ฟังการเปลี่ยนแปลงลําดับของรายการในรายการที่เรียงลําดับ
เหตุการณ์นี้จะเกิดขึ้นเมื่อ onChildChanged()
Callback จะทริกเกอร์โดยการอัปเดตที่ทำให้เกิดการจัดเรียงรายการย่อยใหม่
โดยจะใช้กับข้อมูลที่เรียงลำดับด้วย orderByChild หรือ orderByValue
|
เช่น แอปบล็อกโซเชียลอาจใช้วิธีการเหล่านี้ ร่วมกันเพื่อตรวจสอบกิจกรรมในความคิดเห็นของโพสต์ ดังที่ปรากฏด้านล่าง:
Kotlin+KTX
val childEventListener = object : ChildEventListener { override fun onChildAdded(dataSnapshot: DataSnapshot, previousChildName: String?) { Log.d(TAG, "onChildAdded:" + dataSnapshot.key!!) // A new comment has been added, add it to the displayed list val comment = dataSnapshot.getValue<Comment>() // ... } override fun onChildChanged(dataSnapshot: DataSnapshot, previousChildName: String?) { Log.d(TAG, "onChildChanged: ${dataSnapshot.key}") // A comment has changed, use the key to determine if we are displaying this // comment and if so displayed the changed comment. val newComment = dataSnapshot.getValue<Comment>() val commentKey = dataSnapshot.key // ... } override fun onChildRemoved(dataSnapshot: DataSnapshot) { Log.d(TAG, "onChildRemoved:" + dataSnapshot.key!!) // A comment has changed, use the key to determine if we are displaying this // comment and if so remove it. val commentKey = dataSnapshot.key // ... } override fun onChildMoved(dataSnapshot: DataSnapshot, previousChildName: String?) { Log.d(TAG, "onChildMoved:" + dataSnapshot.key!!) // A comment has changed position, use the key to determine if we are // displaying this comment and if so move it. val movedComment = dataSnapshot.getValue<Comment>() val commentKey = dataSnapshot.key // ... } override fun onCancelled(databaseError: DatabaseError) { Log.w(TAG, "postComments:onCancelled", databaseError.toException()) Toast.makeText( context, "Failed to load comments.", Toast.LENGTH_SHORT, ).show() } } databaseReference.addChildEventListener(childEventListener)
Java
ChildEventListener childEventListener = new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey()); // A new comment has been added, add it to the displayed list Comment comment = dataSnapshot.getValue(Comment.class); // ... } @Override public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) { Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey()); // A comment has changed, use the key to determine if we are displaying this // comment and if so displayed the changed comment. Comment newComment = dataSnapshot.getValue(Comment.class); String commentKey = dataSnapshot.getKey(); // ... } @Override public void onChildRemoved(DataSnapshot dataSnapshot) { Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey()); // A comment has changed, use the key to determine if we are displaying this // comment and if so remove it. String commentKey = dataSnapshot.getKey(); // ... } @Override public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) { Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey()); // A comment has changed position, use the key to determine if we are // displaying this comment and if so move it. Comment movedComment = dataSnapshot.getValue(Comment.class); String commentKey = dataSnapshot.getKey(); // ... } @Override public void onCancelled(DatabaseError databaseError) { Log.w(TAG, "postComments:onCancelled", databaseError.toException()); Toast.makeText(mContext, "Failed to load comments.", Toast.LENGTH_SHORT).show(); } }; databaseReference.addChildEventListener(childEventListener);
ฟังเหตุการณ์ที่มีคุณค่า
ขณะที่ใช้ ChildEventListener
เป็นวิธีที่แนะนำในการอ่านรายการ
อาจมีการแนบ ValueEventListener
ไปยังรายการได้
ข้อมูลอ้างอิงมีประโยชน์
การแนบ ValueEventListener
กับรายการข้อมูลจะแสดงรายการข้อมูลทั้งหมดเป็น DataSnapshot
รายการเดียว จากนั้นคุณจะวนซ้ำเพื่อเข้าถึงรายการย่อยแต่ละรายการได้
แม้ว่าข้อความค้นหาจะมีผลลัพธ์ที่ตรงกันเพียงรายการเดียว แต่ภาพรวมก็ยังคงเป็น list; จะมีแค่รายการเดียว หากต้องการเข้าถึงรายการ คุณจะต้องวนซ้ำ มากกว่าผลลัพธ์:
Kotlin+KTX
// My top posts by number of stars myTopPostsQuery.addValueEventListener(object : ValueEventListener { override fun onDataChange(dataSnapshot: DataSnapshot) { for (postSnapshot in dataSnapshot.children) { // TODO: handle the post } } override fun onCancelled(databaseError: DatabaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()) // ... } })
Java
// My top posts by number of stars myTopPostsQuery.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) { // TODO: handle the post } } @Override public void onCancelled(@NonNull DatabaseError databaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()); // ... } });
รูปแบบนี้มีประโยชน์เมื่อคุณต้องการดึงข้อมูลย่อยทั้งหมดของรายการ
ในการดำเนินการเดียว แทนที่จะฟัง onChildAdded
เพิ่มเติม
กิจกรรม
ปลดผู้ฟังออก
คุณนำการเรียกกลับออกได้โดยเรียกใช้เมธอด removeEventListener()
ในข้อมูลอ้างอิงฐานข้อมูล Firebase
หากคุณเพิ่มผู้ฟังไปยังตำแหน่งข้อมูลหลายครั้ง หลายครั้งสำหรับแต่ละกิจกรรม และคุณต้องแยกออกจากอุปกรณ์เป็นจำนวนเดียวกัน เพื่อนำออกอย่างสมบูรณ์
การเรียกใช้ removeEventListener()
บน Listener หลักไม่ได้
นำ Listener ที่ลงทะเบียนไว้ในโหนดย่อยออกโดยอัตโนมัติ
ต้องเรียก removeEventListener()
ใน Listener ที่เป็นเด็กด้วย
เพื่อนำการติดต่อกลับ
การจัดเรียงและกรองข้อมูล
คุณสามารถใช้คลาส Realtime Database Query
เพื่อดึงข้อมูลที่จัดเรียงตาม
คีย์ ตามค่า หรือตามค่าของรายการย่อย และคุณยังกรอง
ผลการค้นหาที่จัดเรียงไปยังผลลัพธ์จำนวนหนึ่งๆ หรือช่วงของคีย์ หรือ
จัดเรียงข้อมูล
หากต้องการเรียกดูข้อมูลที่จัดเรียงแล้ว ให้เริ่มด้วยการระบุวิธีการเรียงลำดับตาม วิธีเรียงลำดับผลลัพธ์
วิธีการ | การใช้งาน |
---|---|
orderByChild() |
จัดเรียงผลลัพธ์ตามค่าของคีย์ย่อยที่ระบุหรือเส้นทางย่อยที่ฝังอยู่ |
orderByKey()
| จัดเรียงผลลัพธ์ตามคีย์ย่อย |
orderByValue() |
เรียงลำดับผลลัพธ์ตามค่าย่อย |
คุณใช้วิธีการจัดเรียงได้ครั้งละ 1 วิธีเท่านั้น การเรียกใช้วิธีการสั่งซื้อ การค้นหาเดียวกันหลายครั้งทำให้เกิดข้อผิดพลาด
ตัวอย่างต่อไปนี้แสดงวิธีที่คุณสามารถเรียกข้อมูลรายการของผู้ใช้ โพสต์ยอดนิยมจัดเรียงตามจำนวนดาว
Kotlin+KTX
// My top posts by number of stars val myUserId = uid val myTopPostsQuery = databaseReference.child("user-posts").child(myUserId) .orderByChild("starCount") myTopPostsQuery.addChildEventListener(object : ChildEventListener { // TODO: implement the ChildEventListener methods as documented above // ... })
Java
// My top posts by number of stars String myUserId = getUid(); Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId) .orderByChild("starCount"); myTopPostsQuery.addChildEventListener(new ChildEventListener() { // TODO: implement the ChildEventListener methods as documented above // ... });
สิ่งนี้จะกำหนดการค้นหาที่เมื่อรวมกับผู้ฟังย่อย ซิงค์ไคลเอ็นต์กับโพสต์ของผู้ใช้จากเส้นทางในฐานข้อมูล ตามรหัสผู้ใช้ โดยเรียงลำดับตามจำนวนดาวที่แต่ละโพสต์ได้รับ เทคนิคการใช้รหัสเป็นคีย์ดัชนีเรียกว่าการแยกข้อมูลออก คุณสามารถอ่านข้อมูลเพิ่มเติมได้ในจัดโครงสร้างฐานข้อมูล
การเรียกใช้เมธอด 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()
สาย
Kotlin+KTX
// Most viewed posts val myMostViewedPostsQuery = databaseReference.child("posts") .orderByChild("metrics/views") myMostViewedPostsQuery.addChildEventListener(object : ChildEventListener { // TODO: implement the ChildEventListener methods as documented above // ... })
Java
// Most viewed posts Query myMostViewedPostsQuery = databaseReference.child("posts") .orderByChild("metrics/views"); myMostViewedPostsQuery.addChildEventListener(new ChildEventListener() { // TODO: implement the ChildEventListener methods as documented above // ... });
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีเรียงลำดับข้อมูลประเภทอื่นๆ โปรดดู วิธีเรียงลำดับข้อมูลคำค้นหา
การกรองข้อมูล
ในการกรองข้อมูล คุณสามารถรวมวิธีการจำกัดหรือช่วงเข้ากับ ตามลำดับเมื่อสร้าง Query
วิธีการ | การใช้งาน |
---|---|
limitToFirst() |
กำหนดจำนวนรายการสูงสุดที่จะส่งคืนตั้งแต่ต้น รายการผลลัพธ์ตามลำดับ |
limitToLast() |
กำหนดจำนวนสินค้าสูงสุดที่จะส่งคืนจากสิ้นสุดสินค้าที่สั่งซื้อ รายการผลลัพธ์ |
startAt() |
แสดงรายการที่มากกว่าหรือเท่ากับคีย์หรือค่าที่ระบุ โดยขึ้นอยู่กับวิธีการจัดเรียงที่เลือก |
startAfter() |
แสดงรายการที่มากกว่าคีย์หรือค่าที่ระบุ ขึ้นอยู่กับวิธีการเรียงลำดับที่เลือกไว้ |
endAt() |
แสดงรายการที่น้อยกว่าหรือเท่ากับคีย์หรือค่าที่ระบุ ขึ้นอยู่กับวิธีการเรียงลำดับที่เลือกไว้ |
endBefore() |
แสดงผลรายการที่น้อยกว่าคีย์หรือค่าที่ระบุ ทั้งนี้ขึ้นอยู่กับวิธีการจัดเรียงที่เลือก |
equalTo() |
แสดงรายการผลการค้นหาเท่ากับคีย์หรือค่าที่ระบุ ขึ้นอยู่กับวิธีการเรียงลำดับที่เลือกไว้ |
คุณสามารถรวมฟังก์ชันขีดจำกัดหรือช่วงได้หลายรายการ ซึ่งต่างจากเมธอดการเรียงลำดับ
เช่น คุณสามารถรวมเมธอด startAt()
และ endAt()
เข้าด้วยกันเพื่อจำกัด
ผลลัพธ์เป็นช่วงของค่าที่ระบุ
แม้จะจับคู่คำค้นหาได้เพียงรายการเดียว สแนปชอตจะยังคงเป็นลิสต์ที่มีเพียงรายการเดียว หากต้องการเข้าถึงรายการดังกล่าว คุณต้อง เพื่อวนซ้ำผลลัพธ์:
Kotlin+KTX
// My top posts by number of stars myTopPostsQuery.addValueEventListener(object : ValueEventListener { override fun onDataChange(dataSnapshot: DataSnapshot) { for (postSnapshot in dataSnapshot.children) { // TODO: handle the post } } override fun onCancelled(databaseError: DatabaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()) // ... } })
Java
// My top posts by number of stars myTopPostsQuery.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) { // TODO: handle the post } } @Override public void onCancelled(@NonNull DatabaseError databaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()); // ... } });
จำกัดจำนวนผลการค้นหา
คุณสามารถใช้เมธอด limitToFirst()
และ limitToLast()
เพื่อตั้งค่า
จำนวนรายการย่อยสูงสุดที่จะซิงค์สำหรับ Callback ที่กำหนด เช่น หากใช้ limitToFirst()
เพื่อตั้งค่าขีดจํากัดเป็น 100 รายการ ในช่วงแรกคุณจะได้รับ onChildAdded()
แคลลบ์แบ็กสูงสุด 100 รายการเท่านั้น หากมีรายการที่จัดเก็บไม่ถึง 100 รายการใน
ฐานข้อมูล Firebase Callback onChildAdded()
จะเริ่มทำงานสำหรับแต่ละรายการ
เมื่อรายการมีการเปลี่ยนแปลง คุณจะได้รับ Callback onChildAdded()
รายการสําหรับรายการที่เข้าสู่
ข้อความค้นหาและ Callback onChildRemoved()
รายการสำหรับรายการที่ออกจากข้อความเพื่อให้
จำนวนทั้งหมดจะอยู่ที่ 100
ตัวอย่างต่อไปนี้แสดงวิธีที่แอปการเขียนบล็อกตัวอย่างกำหนดการค้นหาเพื่อดึงข้อมูลรายการโพสต์ล่าสุด 100 รายการของผู้ใช้ทั้งหมด
Kotlin+KTX
// Last 100 posts, these are automatically the 100 most recent // due to sorting by push() keys. databaseReference.child("posts").limitToFirst(100)
Java
// Last 100 posts, these are automatically the 100 most recent // due to sorting by push() keys Query recentPostsQuery = databaseReference.child("posts") .limitToFirst(100);
ตัวอย่างนี้ระบุเฉพาะคำค้นหาเพื่อซิงค์ข้อมูลที่ต้องการ มีผู้ฟังแนบมาด้วย
กรองตามคีย์หรือค่า
คุณจะใช้ startAt()
, startAfter()
, endAt()
, endBefore()
และ
equalTo()
เพื่อเลือกจุดเริ่มต้น สิ้นสุด และจุดสมมูลที่กำหนดเองสำหรับ
การค้นหา ซึ่งอาจเป็นประโยชน์สำหรับการแบ่งหน้าข้อมูลหรือค้นหารายการที่มีรายการย่อยซึ่งมีค่าที่เฉพาะเจาะจง
วิธีเรียงลำดับข้อมูลข้อความค้นหา
ส่วนนี้จะอธิบายวิธีการจัดเรียงข้อมูลตามวิธีการเรียงลำดับแต่ละวิธีใน
Query
ชั้นเรียน
orderByChild
เมื่อใช้ orderByChild()
ข้อมูลที่มีคีย์ย่อยที่ระบุจะเป็น
มีลำดับดังนี้
- เด็กที่มีค่า
null
สำหรับคีย์ย่อยที่ระบุมาแล้ว ก่อน - ผู้เผยแพร่โฆษณาย่อยที่มีค่าเป็น
false
สำหรับคีย์ย่อยที่ระบุ พบกันใหม่ หากเด็กหลายคนมีค่าเป็นfalse
จำนวนจะเป็น จัดเรียงในพจนานุกรมตามคีย์ - ผู้เผยแพร่โฆษณาย่อยที่มีค่าเป็น
true
สำหรับคีย์ย่อยที่ระบุ พบกันใหม่ หากเด็กหลายคนมีค่าเป็นtrue
จำนวนจะเป็น จัดเรียงแบบพจนานุกรมตามคีย์ - เด็กที่มีค่าตัวเลขจะแสดงอยู่ถัดไปโดยเรียงลำดับจากน้อยไปหามาก ถ้า เด็กหลายคนมีค่าตัวเลขเหมือนกันสำหรับผู้เผยแพร่โฆษณาย่อยที่ระบุ โหนดจะจัดเรียงตามคีย์
- สตริงจะอยู่หลังตัวเลขและจัดเรียงตามลําดับตัวอักษรจากน้อยไปมาก กรณีที่รายการย่อยหลายรายการมีค่าเหมือนกันสำหรับรายการย่อยที่ระบุ โหนดจะเรียงลำดับแบบพจนานุกรมตามคีย์
- ออบเจ็กต์อยู่ท้ายสุดและจัดเรียงแบบพจนานุกรมตามคีย์ในลำดับจากน้อยไปมาก
orderByKey
เมื่อใช้ orderByKey()
เพื่อจัดเรียงข้อมูล ระบบจะส่งข้อมูลจากน้อยไปมาก
ตามคีย์
- เด็กที่มีคีย์ซึ่งแยกวิเคราะห์ได้เป็นจำนวนเต็ม 32 บิตจะมาก่อน โดยจัดเรียงจากน้อยไปมาก
- เด็กที่มีค่าสตริงเป็นคีย์ถัดไป ซึ่งจัดเรียงแบบพจนานุกรมจากน้อยไปมาก
orderByValue
เมื่อใช้ orderByValue()
ระบบจะเรียงลำดับรายการย่อยตามค่า เกณฑ์การจัดเรียงจะเหมือนกับใน orderByChild()
ยกเว้นจะใช้ค่าของโหนดแทนค่าของคีย์ย่อยที่ระบุ