เอกสารนี้ครอบคลุมการทำงานกับรายการข้อมูลใน Firebase หากต้องการเรียนรู้พื้นฐานการอ่านและเขียนข้อมูล Firebase โปรดดู อ่านและเขียนข้อมูลบน Android
รับข้อมูลอ้างอิงฐานข้อมูล
หากต้องการอ่านและเขียนข้อมูลจากฐานข้อมูล คุณต้องมีอินสแตนซ์ของ 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()
แต่ละสิ่งเหล่านี้รวมกันจะมีประโยชน์สำหรับการฟังการเปลี่ยนแปลงไปยังโหนดเฉพาะในฐานข้อมูล
ในการฟังเหตุการณ์ย่อยใน DatabaseReference
ให้แนบ ChildEventListener
:
ผู้ฟัง | การโทรกลับเหตุการณ์ | การใช้งานทั่วไป |
---|---|---|
ChildEventListener | onChildAdded() | ดึงรายการของรายการหรือฟังการเพิ่มในรายการของรายการ การเรียกกลับนี้ถูกเรียกใช้หนึ่งครั้งสำหรับแต่ละลูกที่มีอยู่ และจากนั้นอีกครั้งทุกครั้งที่มีการเพิ่มลูกใหม่ไปยังเส้นทางที่ระบุ DataSnapshot ที่ส่งไปยังผู้ฟังมีข้อมูลของเด็กใหม่ |
onChildChanged() | ฟังการเปลี่ยนแปลงรายการในรายการ เหตุการณ์นี้เกิดขึ้นทุกครั้งที่มีการแก้ไขโหนดย่อย รวมถึงการแก้ไขใด ๆ ต่อโหนดย่อย DataSnapshot ที่ส่งไปยังผู้ฟังเหตุการณ์มีข้อมูลที่อัปเดตสำหรับเด็ก | |
onChildRemoved() | ฟังรายการที่ถูกลบออกจากรายการ DataSnapshot ที่ส่งผ่านไปยังการเรียกกลับเหตุการณ์มีข้อมูลสำหรับเด็กที่ถูกลบ | |
onChildMoved() | รับฟังการเปลี่ยนแปลงลำดับของรายการในรายการที่สั่งซื้อ เหตุการณ์นี้ถูกเรียกใช้เมื่อใดก็ตามที่การเรียกกลับ onChildChanged() ถูกทริกเกอร์โดยการอัปเดตที่ทำให้เกิดการจัดลำดับใหม่ของเด็ก ใช้กับข้อมูลที่สั่งด้วย 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
เดียว ซึ่งคุณสามารถวนซ้ำเพื่อเข้าถึงรายการย่อยแต่ละรายการได้
แม้ว่าจะมีการค้นหาที่ตรงกันเพียงรายการเดียว สแนปชอตยังคงเป็นรายการ มันมีเพียงรายการเดียว ในการเข้าถึงรายการ คุณต้องวนซ้ำผลลัพธ์:
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 ของคุณ
หากมีการเพิ่ม Listener หลายครั้งไปยังตำแหน่งข้อมูล จะมีการเรียกหลายครั้งสำหรับแต่ละเหตุการณ์ และคุณต้องแยกออกในจำนวนครั้งเท่ากันเพื่อลบออกทั้งหมด
การเรียก removeEventListener()
บนพาเรนต์ฟังจะไม่ลบฟังที่ลงทะเบียนบนโหนดย่อยโดยอัตโนมัติ ต้องเรียก removeEventListener()
บนตัวฟังย่อยใดๆ เพื่อลบการโทรกลับ
การเรียงลำดับและการกรองข้อมูล
คุณสามารถใช้คลาส Realtime Database Query
เพื่อดึงข้อมูลที่จัดเรียงตามคีย์ ตามค่า หรือตามค่าของลูก คุณยังสามารถกรองผลลัพธ์ที่จัดเรียงเป็นจำนวนเฉพาะของผลลัพธ์หรือช่วงของคีย์หรือค่า
จัดเรียงข้อมูล
ในการดึงข้อมูลที่เรียงลำดับ ให้เริ่มด้วยการระบุหนึ่งในวิธีการเรียงลำดับเพื่อกำหนดวิธีการเรียงลำดับผลลัพธ์:
วิธี | การใช้งาน |
---|---|
orderByChild() | เรียงลำดับผลลัพธ์ตามค่าของคีย์ลูกที่ระบุหรือเส้นทางลูกที่ซ้อนกัน | orderByKey() | ผลลัพธ์การสั่งซื้อโดยปุ่มลูก |
orderByValue() | ลำดับผลลัพธ์ตามค่าลูก |
คุณสามารถใช้วิธีการสั่งซื้อได้ครั้งละ หนึ่ง วิธีเท่านั้น การเรียกใช้เมธอดตามลำดับหลายครั้งในแบบสอบถามเดียวกันทำให้เกิดข้อผิดพลาด
ตัวอย่างต่อไปนี้จะสาธิตวิธีการเรียกดูรายการโพสต์ยอดนิยมของผู้ใช้โดยเรียงตามจำนวนดาว:
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 // ... });
สิ่งนี้กำหนดแบบสอบถามที่เมื่อรวมกับ ผู้ฟังย่อย จะซิงโครไนซ์ไคลเอนต์กับโพสต์ของผู้ใช้จากเส้นทางในฐานข้อมูลตาม ID ผู้ใช้ เรียงลำดับตามจำนวนดาวที่แต่ละโพสต์ได้รับ เทคนิคการใช้ ID เป็นคีย์ดัชนีนี้เรียกว่า data fan out คุณสามารถอ่านเพิ่มเติมได้ใน โครงสร้างฐานข้อมูลของคุณ
การเรียกเมธอด 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 // ... });
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีจัดลำดับประเภทข้อมูลอื่นๆ โปรดดูที่ วิธีจัดลำดับข้อมูลคิวรี
การกรองข้อมูล
ในการกรองข้อมูล คุณสามารถรวมเมธอดขีดจำกัดหรือเมธอดใดๆ เข้ากับเมธอดลำดับตามเมื่อสร้างเคียวรี
วิธี | การใช้งาน |
---|---|
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()
เพื่อตั้งค่าจำนวนลูกสูงสุดที่จะซิงค์สำหรับการโทรกลับที่กำหนด ตัวอย่างเช่น หากคุณใช้ limitToFirst()
เพื่อตั้งค่าขีดจำกัดที่ 100 คุณจะได้รับการโทรกลับ onChildAdded()
เพียง 100 ครั้งเท่านั้น หากคุณมีรายการที่เก็บไว้ในฐานข้อมูล Firebase น้อยกว่า 100 รายการ การเรียกกลับ onChildAdded()
จะเริ่มทำงานสำหรับแต่ละรายการ
เมื่อรายการเปลี่ยนแปลง คุณจะได้รับ onChildAdded()
การโทรกลับสำหรับรายการที่ป้อนคำค้นหา และ 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);
ตัวอย่างนี้กำหนดคิวรีเท่านั้น ในการซิงโครไนซ์ข้อมูลจริงๆ จำเป็นต้องมี Listener แนบมาด้วย
กรองตามคีย์หรือค่า
คุณสามารถใช้ startAt()
, startAfter()
, endAt()
, endBefore()
และ equalTo()
เพื่อเลือกจุดเริ่ม จุดสิ้นสุด และจุดสมมูลสำหรับการค้นหาโดยพลการ สิ่งนี้มีประโยชน์สำหรับการแบ่งหน้าข้อมูลหรือค้นหารายการที่มีรายการย่อยที่มีค่าเฉพาะ
วิธีเรียงลำดับข้อมูลแบบสอบถาม
ส่วนนี้อธิบายวิธีการจัดเรียงข้อมูลตามวิธีการเรียงลำดับตามแต่ละวิธีในคลาส Query
orderByChild
เมื่อใช้ orderByChild()
ข้อมูลที่มีคีย์ลูกที่ระบุจะถูกเรียงลำดับดังนี้:
- ลูกที่มีค่า
null
สำหรับคีย์ลูกที่ระบุมาก่อน - ลูกที่มีค่าเป็น
false
สำหรับคีย์ลูกที่ระบุจะอยู่ถัดไป หากเด็กหลายคนมีค่าเป็นfalse
พวกเขาจะถูกจัดเรียงตาม พจนานุกรม ตามคีย์ - ลูกที่มีค่า
true
สำหรับคีย์ลูกที่ระบุจะอยู่ถัดไป หากลูกหลายคนมีค่าเป็นtrue
จะมีการจัดเรียงตามพจนานุกรมตามคีย์ - เด็กที่มีค่าตัวเลขมาถัดไป เรียงลำดับจากน้อยไปหามาก ถ้าโหนดย่อยหลายโหนดมีค่าตัวเลขเดียวกันสำหรับโหนดย่อยที่ระบุ พวกเขาจะถูกจัดเรียงตามคีย์
- สตริงมาหลังตัวเลขและจัดเรียงตามพจนานุกรมจากน้อยไปหามาก หากโหนดย่อยหลายรายการมีค่าเท่ากันสำหรับโหนดย่อยที่ระบุ ระบบจะเรียงลำดับตามพจนานุกรมตามคีย์
- ออบเจกต์จะอยู่หลังสุดและจัดเรียงตามพจนานุกรมตามคีย์ในลำดับจากน้อยไปหามาก
orderByKey
เมื่อใช้ orderByKey()
เพื่อจัดเรียงข้อมูล ข้อมูลจะถูกส่งกลับตามลำดับคีย์
- เด็กที่มีคีย์ที่สามารถแยกวิเคราะห์เป็นจำนวนเต็ม 32 บิตมาก่อน เรียงลำดับจากน้อยไปหามาก
- เด็กที่มีค่าสตริงเป็นคีย์อยู่ถัดไป จัดเรียงตามพจนานุกรมจากน้อยไปหามาก
orderByValue
เมื่อใช้ orderByValue()
เด็กจะเรียงลำดับตามค่า เกณฑ์การจัดลำดับเหมือนกับใน orderByChild()
ยกเว้นค่าของโหนดจะถูกใช้แทนค่าของคีย์ลูกที่ระบุ