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

เอกสารนี้ครอบคลุมถึงการทำงานกับรายการข้อมูลใน 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:

การส่งแบบฟอร์ม Callback ของเหตุการณ์ การใช้งานทั่วไป
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

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

การเรียกใช้ 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 รายการ ในตอนแรกคุณจะได้รับเฉพาะ เป็น Callback 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() ข้อมูลที่มีคีย์ย่อยที่ระบุจะเป็น มีลำดับดังนี้

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

orderByKey

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

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

orderByValue

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

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