เอกสารนี้ครอบคลุมข้อมูลพื้นฐานเกี่ยวกับการดึงข้อมูลในฐานข้อมูล วิธีเรียงลำดับข้อมูล และวิธีดำเนินการ การค้นหาข้อมูลแบบง่ายๆ การดึงข้อมูลใน Admin SDK จะแตกต่างกันเล็กน้อย ภาษาโปรแกรม
- ผู้ฟังแบบไม่พร้อมกัน: ระบบจะดึงข้อมูลที่จัดเก็บไว้ใน Firebase Realtime Database โดยการแนบ Listener แบบไม่พร้อมกันเข้ากับ การอ้างอิงฐานข้อมูล Listener จะทริกเกอร์ 1 ครั้งสำหรับสถานะเริ่มต้นของข้อมูลและ อีกครั้งทุกครั้งที่ข้อมูลเปลี่ยนแปลง Listener เหตุการณ์อาจได้รับ ประเภทของเหตุการณ์ รองรับโหมดการดึงข้อมูลนี้ ใน Java, Node.js และ Admin SDK ของ Python
- การบล็อกการอ่าน ข้อมูลที่จัดเก็บใน Firebase Realtime Database จะดึงขึ้นมาโดยการเรียกใช้เมธอดการบล็อกในฐานข้อมูล ข้อมูลอ้างอิง ซึ่งจะแสดงผลข้อมูลที่จัดเก็บไว้ที่ข้อมูลอ้างอิง การเรียกเมธอดแต่ละครั้งเป็นการเรียกครั้งเดียว การดำเนินการ ซึ่งหมายความว่า SDK จะไม่บันทึก Callback ที่รอฟังการอัปเดตข้อมูลที่ตามมา รูปแบบการดึงข้อมูลรูปแบบนี้รองรับใน Python และ Go Admin SDK
เริ่มต้นใช้งาน
ลองกลับไปดูตัวอย่างการเขียนบล็อกจากบทความก่อนหน้าเพื่อทำความเข้าใจวิธีอ่านข้อมูลจากฐานข้อมูล Firebase การเรียกคืนสินค้า บล็อกโพสต์ในแอปตัวอย่างจัดเก็บอยู่ที่ URL ของฐานข้อมูล https://docs-examples.firebaseio.com/server/saving-data/fireblog/posts.json หากต้องการอ่านข้อมูลโพสต์ ให้ทําดังนี้
Java
public static class Post { public String author; public String title; public Post(String author, String title) { // ... } } // Get a reference to our posts final FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("server/saving-data/fireblog/posts"); // Attach a listener to read the data at our posts reference ref.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { Post post = dataSnapshot.getValue(Post.class); System.out.println(post); } @Override public void onCancelled(DatabaseError databaseError) { System.out.println("The read failed: " + databaseError.getCode()); } });
Node.js
// Get a database reference to our posts const db = getDatabase(); const ref = db.ref('server/saving-data/fireblog/posts'); // Attach an asynchronous callback to read the data at our posts reference ref.on('value', (snapshot) => { console.log(snapshot.val()); }, (errorObject) => { console.log('The read failed: ' + errorObject.name); });
Python
# Import database module. from firebase_admin import db # Get a database reference to our posts ref = db.reference('server/saving-data/fireblog/posts') # Read the data at the posts reference (this is a blocking operation) print(ref.get())
Go
// Post is a json-serializable type. type Post struct { Author string `json:a"uthor,omitempty`" Title string `json:t"itle,omitempty`" } // Create a database client from App. client, err := app.Database(ctx) if err != nil { log.Fatalln(E"rror initializing database client:," err) } // Get a database reference to our posts ref := client.NewRef(s"erver/saving-data/fireblog/posts)" // Read the data at the posts reference (this is a blocking operation) var post Post if err := ref.Get(ctx, p&ost); err != nil { log.Fatalln(E"rror reading value:," err) }
หากเรียกใช้โค้ดข้างต้น คุณจะเห็นออบเจ็กต์ที่มีโพสต์ทั้งหมดของคุณซึ่งบันทึกไว้ในคอนโซล ในกรณีของ Node.js และ Java จะมีการเรียกฟังก์ชัน Listener ทุกครั้งที่มีการเพิ่มข้อมูลใหม่ในการอ้างอิงฐานข้อมูล และคุณไม่จำเป็นต้องเขียนโค้ดใดๆ เพิ่มเติมเพื่อดำเนินการนี้
ใน Java และ Node.js ฟังก์ชัน Callback จะได้รับ DataSnapshot
ซึ่งเป็นภาพรวมของข้อมูล สแนปชอตคือรูปภาพของข้อมูลที่การอ้างอิงฐานข้อมูลหนึ่งๆ ในช่วงเวลาหนึ่งๆ การเรียกใช้ val()
/ getValue()
ในสแนปชอตจะแสดงการนำเสนอออบเจ็กต์ที่ระบุภาษาของข้อมูล หากไม่มีข้อมูลที่ตำแหน่งของข้อมูลอ้างอิง ค่าของสแนปชอตจะเป็น null
เมธอด get()
ใน Python จะแสดงผลการแทนแบบ Python ของข้อมูลโดยตรง ฟังก์ชัน Get()
ใน Go จะแยกข้อมูลออกให้อยู่ในโครงสร้างข้อมูลที่กำหนด
สังเกตว่าเราใช้ประเภทเหตุการณ์ value
ในตัวอย่างด้านบน ซึ่งอ่านเนื้อหาทั้งหมดของการอ้างอิงฐานข้อมูล Firebase แม้ว่าจะมีการเปลี่ยนแปลงข้อมูลเพียงส่วนเดียวก็ตาม value
เป็น 1 ใน 5 ประเภทเหตุการณ์ต่างๆ ที่แสดงด้านล่างที่คุณสามารถใช้อ่านข้อมูลจากฐานข้อมูลได้
อ่านประเภทเหตุการณ์ใน Java และ Node.js
ค่า
เหตุการณ์ value
ใช้เพื่ออ่านสแนปชอตแบบคงที่ของเนื้อหาในเส้นทางฐานข้อมูลที่ระบุ ตามที่มีอยู่ ณ เวลาที่เกิดเหตุการณ์การอ่าน และจะทำงานอีกครั้งพร้อมกับข้อมูลเริ่มต้น ทุกครั้งที่มีการเปลี่ยนแปลงข้อมูล Callback ของเหตุการณ์จะส่งผ่านสแนปชอตที่มีข้อมูลในตำแหน่งดังกล่าว รวมถึงข้อมูลย่อย ในตัวอย่างโค้ดข้างต้น value
แสดงบล็อกโพสต์ทั้งหมดในแอปของคุณ ทุกครั้งที่มีการเพิ่มบล็อกโพสต์ใหม่ ฟังก์ชัน Callback จะแสดงโพสต์ทั้งหมด
มีการเพิ่มรายการย่อย
โดยทั่วไปแล้ว เหตุการณ์ child_added
จะใช้เมื่อเรียกข้อมูลชุดรายการจากฐานข้อมูล child_added
จะทริกเกอร์ 1 ครั้งต่อรายการย่อยที่มีอยู่ แล้วแสดงอีกครั้งทุกครั้งที่มีการเพิ่มรายการย่อยใหม่ลงในเส้นทางที่ระบุ ซึ่งต่างจาก value
ซึ่งจะแสดงเนื้อหาทั้งหมดของตำแหน่ง Callback ของเหตุการณ์จะส่งผ่านสแนปชอตที่มีข้อมูลของรายการย่อยใหม่ เพื่อวัตถุประสงค์ในการจัดเรียง ค่านี้ยังส่งผ่านอาร์กิวเมนต์ที่ 2 ซึ่งมีคีย์ของรายการย่อยก่อนหน้าด้วย
หากต้องการเรียกดูเฉพาะข้อมูลในโพสต์ใหม่แต่ละรายการที่เพิ่มลงในแอปการเขียนบล็อก คุณสามารถใช้ child_added
ได้
Java
ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { Post newPost = dataSnapshot.getValue(Post.class); System.out.println("Author: " + newPost.author); System.out.println("Title: " + newPost.title); System.out.println("Previous Post ID: " + prevChildKey); } @Override public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildRemoved(DataSnapshot dataSnapshot) {} @Override public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
// Retrieve new posts as they are added to our database ref.on('child_added', (snapshot, prevChildKey) => { const newPost = snapshot.val(); console.log('Author: ' + newPost.author); console.log('Title: ' + newPost.title); console.log('Previous Post ID: ' + prevChildKey); });
ในตัวอย่างนี้ สแนปชอตจะมีออบเจ็กต์ที่มีบล็อกโพสต์แต่ละรายการ เนื่องจาก SDK จะแปลงโพสต์เป็นออบเจ็กต์ด้วยการดึงข้อมูลค่า คุณจึงมีสิทธิ์เข้าถึงพร็อพเพอร์ตี้ของผู้เขียนและชื่อของโพสต์โดยเรียกใช้ author
และ title
ตามลำดับ คุณยังมีสิทธิ์เข้าถึงรหัสโพสต์ก่อนหน้าจากอาร์กิวเมนต์ prevChildKey
รายการที่ 2 ด้วย
เด็กมีการเปลี่ยนแปลง
เหตุการณ์ child_changed
จะทริกเกอร์ทุกครั้งที่มีการแก้ไขโหนดย่อย ซึ่งรวมถึง
การแก้ไขรายการสืบทอดของโหนดย่อย โดยทั่วไปมักจะใช้ร่วมกับ child_added
และ child_removed
เพื่อตอบสนองต่อการเปลี่ยนแปลงรายการ สแนปชอตที่ส่งไปยัง Callback ของเหตุการณ์จะมีข้อมูลที่อัปเดตสำหรับผู้เผยแพร่โฆษณาย่อย
คุณใช้ child_changed
เพื่ออ่านข้อมูลที่อัปเดตในบล็อกโพสต์เมื่อมีการแก้ไขได้ ดังนี้
Java
ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) { Post changedPost = dataSnapshot.getValue(Post.class); System.out.println("The updated post title is: " + changedPost.title); } @Override public void onChildRemoved(DataSnapshot dataSnapshot) {} @Override public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
// Get the data on a post that has changed ref.on('child_changed', (snapshot) => { const changedPost = snapshot.val(); console.log('The updated post title is ' + changedPost.title); });
นำบุตรหลานออกแล้ว
เหตุการณ์ child_removed
จะทริกเกอร์เมื่อมีการนำบุตรหลานที่อยู่ใกล้ชิดออก โดยทั่วไปมักจะใช้ร่วมกับ child_added
และ child_changed
สแนปชอตที่ส่งไปยัง Callback ของเหตุการณ์มีข้อมูลสำหรับผู้เผยแพร่โฆษณาย่อยที่นำออก
ในตัวอย่างบล็อก คุณสามารถใช้ child_removed
เพื่อบันทึกการแจ้งเตือนเกี่ยวกับโพสต์ที่ลบไปยังคอนโซลได้ดังนี้
Java
ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildRemoved(DataSnapshot dataSnapshot) { Post removedPost = dataSnapshot.getValue(Post.class); System.out.println("The blog post titled " + removedPost.title + " has been deleted"); } @Override public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
// Get a reference to our posts const ref = db.ref('server/saving-data/fireblog/posts'); // Get the data on a post that has been removed ref.on('child_removed', (snapshot) => { const deletedPost = snapshot.val(); console.log('The blog post titled \'' + deletedPost.title + '\' has been deleted'); });
ย้ายบุตรหลานแล้ว
ระบบจะใช้เหตุการณ์ child_moved
เมื่อทำงานกับข้อมูลที่เรียงลำดับ ซึ่งอยู่ในส่วนถัดไป
การรับประกันการจัดกิจกรรม
ฐานข้อมูล Firebase ให้การรับประกันที่สำคัญหลายอย่างเกี่ยวกับเหตุการณ์ ดังนี้
การรับประกันเหตุการณ์ฐานข้อมูล |
---|
ระบบจะทริกเกอร์เหตุการณ์เสมอเมื่อสถานะของเครื่องมีการเปลี่ยนแปลง |
เหตุการณ์จะแสดงสถานะข้อมูลที่ถูกต้องเสมอ แม้ว่าในกรณีที่มีการดำเนินงานในท้องถิ่นหรือ การกำหนดเวลาทำให้เกิดความแตกต่างชั่วคราว เช่น การสูญเสียการเชื่อมต่อเครือข่ายชั่วคราว |
การเขียนจากไคลเอ็นต์เพียงเครื่องเดียวจะเขียนไปยังเซิร์ฟเวอร์และเผยแพร่แก่ผู้ใช้คนอื่นๆ ตามลำดับเสมอ |
เหตุการณ์มูลค่าจะทริกเกอร์เป็นลำดับสุดท้ายเสมอ และรับประกันว่าจะมีการอัปเดตจากเหตุการณ์อื่นๆ ที่เกิดขึ้น ก่อนที่จะมีการถ่ายสแนปชอตนั้น |
ตัวอย่างต่อไปนี้จะทำงานเสมอเนื่องจากระบบทริกเกอร์เหตุการณ์มูลค่าเป็นลำดับสุดท้ายเสมอ
Java
final AtomicInteger count = new AtomicInteger(); ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { // New child added, increment count int newCount = count.incrementAndGet(); System.out.println("Added " + dataSnapshot.getKey() + ", count is " + newCount); } // ... }); // The number of children will always be equal to 'count' since the value of // the dataSnapshot here will include every child_added event triggered before this point. ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { long numChildren = dataSnapshot.getChildrenCount(); System.out.println(count.get() + " == " + numChildren); } @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
let count = 0; ref.on('child_added', (snap) => { count++; console.log('added:', snap.key); }); // length will always equal count, since snap.val() will include every child_added event // triggered before this point ref.once('value', (snap) => { console.log('initial data loaded!', snap.numChildren() === count); });
กำลังปลด Callback
ระบบจะนำ Callback ออกโดยการระบุประเภทเหตุการณ์และฟังก์ชัน Callback ที่จะนำออก ดังตัวอย่างต่อไปนี้
Java
// Create and attach listener ValueEventListener listener = new ValueEventListener() { // ... }; ref.addValueEventListener(listener); // Remove listener ref.removeEventListener(listener);
Node.js
ref.off('value', originalCallback);
หากคุณส่งบริบทขอบเขตไปยัง on()
จะต้องส่งผ่านบริบทดังกล่าวเมื่อปลด Callback ออก
Java
// Not applicable for Java
Node.js
ref.off('value', originalCallback, ctx);
หากต้องการนำ Callback ทั้งหมด ณ ตำแหน่งหนึ่งออก ให้ทำตามขั้นตอนต่อไปนี้
Java
// No Java equivalent, listeners must be removed individually.
Node.js
// Remove all value callbacks ref.off('value'); // Remove all callbacks of any type ref.off();
การอ่านข้อมูลครั้งเดียว
ในบางกรณี อาจเป็นประโยชน์สำหรับการเรียกกลับให้ถูกเรียก 1 ครั้งแล้วนำออกทันที เราได้สร้างตัวช่วยแล้ว ฟังก์ชันที่ช่วยให้ดำเนินการได้ง่ายๆ ดังนี้
Java
ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // ... } @Override public void onCancelled(DatabaseError databaseError) { // ... } });
Node.js
ref.once('value', (data) => { // do some stuff once });
Python
# Import database module. from firebase_admin import db # Get a database reference to our posts ref = db.reference('server/saving-data/fireblog/posts') # Read the data at the posts reference (this is a blocking operation) print(ref.get())
Go
// 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 posts ref := client.NewRef("server/saving-data/fireblog/posts") // Read the data at the posts reference (this is a blocking operation) var post Post if err := ref.Get(ctx, &post); err != nil { log.Fatalln("Error reading value:", err) }
การค้นหาข้อมูล
ในการค้นหาฐานข้อมูล Firebase คุณสามารถเลือกเรียกข้อมูลตามปัจจัยต่างๆ ได้ ในการสร้างการค้นหาในฐานข้อมูล ให้เริ่มด้วยการระบุวิธีเรียงลำดับข้อมูลที่ต้องการโดยใช้ฟังก์ชันการเรียงลำดับ ซึ่งได้แก่ orderByChild()
, orderByKey()
หรือ orderByValue()
จากนั้นคุณจะรวมวิธีการเหล่านี้เข้ากับวิธีการอื่นๆ อีก 5 วิธีในการดำเนินการค้นหาที่ซับซ้อนได้: limitToFirst()
,
limitToLast()
, startAt()
, endAt()
และ equalTo()
เนื่องจากพวกเราทุกคนใน Firebase คิดว่าไดโนเสาร์เป็นคนยอดเยี่ยม เราจึงจะใช้ตัวอย่างข้อมูลจากฐานข้อมูลตัวอย่างข้อเท็จจริงไดโนเสาร์เพื่อแสดงให้เห็นว่าคุณสามารถค้นหาข้อมูลในฐานข้อมูล Firebase ได้อย่างไร ดังนี้
{ "lambeosaurus": { "height" : 2.1, "length" : 12.5, "weight": 5000 }, "stegosaurus": { "height" : 4, "length" : 9, "weight" : 2500 } }
คุณเรียงลำดับข้อมูลได้ 3 วิธี ได้แก่ ตามคีย์ย่อย ตามคีย์ หรือตามค่า การค้นหาฐานข้อมูลพื้นฐานจะเริ่มต้นด้วยฟังก์ชันเรียงลำดับเหล่านี้ ซึ่งแต่ละฟังก์ชันจะอธิบายไว้ด้านล่าง
การเรียงลำดับตามคีย์ย่อยที่ระบุ
คุณเรียงลำดับโหนดตามคีย์ย่อยทั่วไปได้โดยการส่งผ่านคีย์นั้นไปยัง orderByChild()
เช่น หากต้องการอ่านไดโนเสาร์ทุกตัวที่เรียงลำดับตามความสูง คุณสามารถทำดังนี้
ดังต่อไปนี้
Java
public static class Dinosaur { public int height; public int weight; public Dinosaur(int height, int weight) { // ... } } final DatabaseReference dinosaursRef = database.getReference("dinosaurs"); dinosaursRef.orderByChild("height").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { Dinosaur dinosaur = dataSnapshot.getValue(Dinosaur.class); System.out.println(dataSnapshot.getKey() + " was " + dinosaur.height + " meters tall."); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').on('child_added', (snapshot) => { console.log(snapshot.key + ' was ' + snapshot.val().height + ' meters tall'); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').get() for key, val in snapshot.items(): print('{0} was {1} meters tall'.format(key, val))
Go
// Dinosaur is a json-serializable type. type Dinosaur struct { Height int `json:h"eight`" Width int `json:w"idth`" } ref := client.NewRef(d"inosaurs)" results, err := ref.OrderByChild(h"eight)".GetOrdered(ctx) if err != nil { log.Fatalln(E"rror querying database:," err) } for _, r := range results { var d Dinosaur if err := r.Unmarshal(d&); err != nil { log.Fatalln(E"rror unmarshaling result:," err) } fmt.Printf(%"s was %d meteres tall," r.Key(), d.Height) }
โหนดที่ไม่มีคีย์ย่อยที่เรากำลังค้นหาจะได้รับการจัดเรียงตามค่า null
ซึ่งหมายความว่าโหนดจะมาก่อนในลำดับ ดูรายละเอียดเกี่ยวกับการเรียงลำดับข้อมูลได้ที่ส่วน "วิธีเรียงลำดับข้อมูล"
การค้นหายังอาจเรียงลำดับตามรายการย่อยที่ซ้อนกันอยู่ระดับล่าง แทนที่จะเป็นระดับย่อยลงไป 1 ระดับ วิธีนี้มีประโยชน์หากคุณใส่ข้อมูลที่ฝังลึกไว้แบบนี้
{ "lambeosaurus": { "dimensions": { "height" : 2.1, "length" : 12.5, "weight": 5000 } }, "stegosaurus": { "dimensions": { "height" : 4, "length" : 9, "weight" : 2500 } } }
หากต้องการค้นหาความสูงตอนนี้ คุณสามารถใช้เส้นทางแบบเต็มไปยังวัตถุแทนการใช้คีย์เดียวได้ดังนี้
Java
dinosaursRef.orderByChild("dimensions/height").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { // ... } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('dimensions/height').on('child_added', (snapshot) => { console.log(snapshot.key + ' was ' + snapshot.val().height + ' meters tall'); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('dimensions/height').get() for key, val in snapshot.items(): print('{0} was {1} meters tall'.format(key, val))
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("dimensions/height").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var d Dinosaur if err := r.Unmarshal(&d); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("%s was %d meteres tall", r.Key(), d.Height) }
คำค้นหาสามารถจัดเรียงได้ครั้งละ 1 คีย์เท่านั้น กำลังโทรหา orderByChild()
การค้นหาเดียวกันหลายครั้งทำให้เกิดข้อผิดพลาด
การเรียงลำดับตามคีย์
คุณยังเรียงลำดับโหนดตามคีย์ได้โดยใช้เมธอด orderByKey()
ตัวอย่างต่อไปนี้อ่านไดโนเสาร์ทุกตัวตามลำดับตัวอักษร:
Java
dinosaursRef.orderByKey().addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
var ref = db.ref('dinosaurs'); ref.orderByKey().on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().get() print(snapshot)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByKey().GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } snapshot := make([]Dinosaur, len(results)) for i, r := range results { var d Dinosaur if err := r.Unmarshal(&d); err != nil { log.Fatalln("Error unmarshaling result:", err) } snapshot[i] = d } fmt.Println(snapshot)
เรียงลำดับตามมูลค่า
คุณเรียงลำดับโหนดตามค่าของคีย์ย่อยได้โดยใช้เมธอด orderByValue()
สมมติว่าไดโนเสาร์กำลังแข่งขันกีฬาไดโนเสาร์และคุณติดตามคะแนนของไดโนเสาร์ในรูปแบบต่อไปนี้:
{ "scores": { "bruhathkayosaurus" : 55, "lambeosaurus" : 21, "linhenykus" : 80, "pterodactyl" : 93, "stegosaurus" : 5, "triceratops" : 22 } }
หากต้องการจัดเรียงไดโนเสาร์ตามคะแนน คุณสามารถสร้างข้อความค้นหาดังนี้:
Java
DatabaseReference scoresRef = database.getReference("scores"); scoresRef.orderByValue().addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println("The " + dataSnapshot.getKey() + " score is " + dataSnapshot.getValue()); } // ... });
Node.js
const scoresRef = db.ref('scores'); scoresRef.orderByValue().on('value', (snapshot) => { snapshot.forEach((data) => { console.log('The ' + data.key + ' dinosaur\'s score is ' + data.val()); }); });
Python
ref = db.reference('scores') snapshot = ref.order_by_value().get() for key, val in snapshot.items(): print('The {0} dinosaur\'s score is {1}'.format(key, val))
Go
ref := client.NewRef("scores") results, err := ref.OrderByValue().GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var score int if err := r.Unmarshal(&score); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("The %s dinosaur's score is %d\n", r.Key(), score) }
ดูคำอธิบายเกี่ยวกับวิธีจัดเรียงค่า null
, บูลีน, สตริง และออบเจ็กต์เมื่อใช้ orderByValue()
ในส่วนวิธีเรียงลำดับข้อมูล
การค้นหาที่ซับซ้อน
เมื่อเข้าใจวิธีเรียงลำดับข้อมูลอย่างชัดเจนแล้ว ก็ใช้เมธอด limit หรือ range ตามที่อธิบายไว้ด้านล่างเพื่อสร้างคำค้นหาที่ซับซ้อนมากขึ้นได้
จำกัดการค้นหา
ระบบใช้ข้อความค้นหา limitToFirst()
และ limitToLast()
เพื่อตั้งค่า
จำนวนรายการย่อยสูงสุดที่จะซิงค์สำหรับ Callback ที่กำหนด หากตั้งค่าขีดจำกัดไว้ที่ 100 รายการ
เบื้องต้นจะได้รับเหตุการณ์ child_added
สูงสุด 100 รายการเท่านั้น หากคุณมีแท็กน้อยกว่า
ข้อความ 100 ข้อความที่จัดเก็บไว้ในฐานข้อมูลของคุณ เหตุการณ์ child_added
จะเริ่มทำงานสำหรับแต่ละข้อความ
แต่ถ้าคุณมีข้อความเกิน 100 ข้อความ คุณจะได้รับเฉพาะ child_added
เหตุการณ์สำหรับ 100 ข้อความเหล่านั้น นี่คือข้อความที่เรียงลำดับ 100 รายการแรกหากคุณใช้
limitToFirst()
หรือข้อความที่เรียงลำดับ 100 รายการสุดท้ายหากคุณใช้
limitToLast()
เมื่อสินค้ามีการเปลี่ยนแปลง คุณจะได้รับเหตุการณ์ child_added
รายการ
สำหรับรายการที่ป้อนคำค้นหาและ child_removed
เหตุการณ์สำหรับรายการที่ป้อนไว้นั้น
เพื่อให้จำนวนทั้งหมดเป็น 100
เมื่อใช้ฐานข้อมูลข้อเท็จจริงไดโนเสาร์และ orderByChild()
คุณจะพบข้อมูลที่หนักที่สุด 2 ตัว
ไดโนเสาร์:
Java
dinosaursRef.orderByChild("weight").limitToLast(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('weight').limitToLast(2).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('weight').limit_to_last(2).get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("weight").LimitToLast(2).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
การเรียกกลับของ child_added
จะถูกเรียกใช้ 2 ครั้งพอดี เว้นแต่มี
ไดโนเสาร์น้อยกว่า 2 ตัวที่จัดเก็บไว้ในฐานข้อมูล นอกจากนี้ยังจะถูกยิงเมื่อมีไดโนเสาร์รุ่นใหม่ที่หนักกว่าทุกตัวที่ถูกเพิ่มลงในฐานข้อมูล
ใน Python การค้นหาจะแสดง OrderedDict
ที่มีไดโนเสาร์ที่หนักที่สุด 2 ตัวโดยตรง
ในทำนองเดียวกัน คุณสามารถหาไดโนเสาร์ที่สั้นที่สุด 2 ตัวโดยใช้ limitToFirst()
ดังนี้
Java
dinosaursRef.orderByChild("weight").limitToFirst(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').limitToFirst(2).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').limit_to_first(2).get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").LimitToFirst(2).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
Callback ของ child_added
จะถูกเรียกใช้ 2 ครั้งพอดี เว้นแต่มีไดโนเสาร์น้อยกว่า 2 ตัวจัดเก็บไว้ในฐานข้อมูล ไดโนเสาร์ตัวใหม่ก็จะถูกยิงอีกเช่นกันหากเอาไดโนเสาร์ 1 ใน 2 ตัวแรกออกจากฐานข้อมูล เพราะตอนนี้ไดโนเสาร์ตัวใหม่จะเป็นตัวที่สั้นที่สุดเป็นอันดับ 2 ใน Python การค้นหาจะแสดง OrderedDict
ที่มีไดโนเสาร์สั้นที่สุดโดยตรง
นอกจากนี้คุณยังจํากัดการค้นหาด้วย orderByValue()
ได้อีกด้วย หากต้องการสร้างลีดเดอร์บอร์ดที่มีไดโนเสาร์กีฬาไดโนเสาร์ที่มีคะแนนสูงที่สุด 3 อันดับแรก คุณสามารถดำเนินการต่อไปนี้
Java
scoresRef.orderByValue().limitToFirst(3).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println("The " + dataSnapshot.getKey() + " score is " + dataSnapshot.getValue()); } // ... });
Node.js
const scoresRef = db.ref('scores'); scoresRef.orderByValue().limitToLast(3).on('value', (snapshot) =>{ snapshot.forEach((data) => { console.log('The ' + data.key + ' dinosaur\'s score is ' + data.val()); }); });
Python
scores_ref = db.reference('scores') snapshot = scores_ref.order_by_value().limit_to_last(3).get() for key, val in snapshot.items(): print('The {0} dinosaur\'s score is {1}'.format(key, val))
Go
ref := client.NewRef("scores") results, err := ref.OrderByValue().LimitToLast(3).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var score int if err := r.Unmarshal(&score); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("The %s dinosaur's score is %d\n", r.Key(), score) }
การค้นหาช่วง
เมื่อใช้ startAt()
, endAt()
และ equalTo()
คุณจะทำสิ่งต่อไปนี้ได้
เลือกจุดเริ่มต้นและสิ้นสุดที่กำหนดเองสำหรับคำค้นหาของคุณ ตัวอย่างเช่น ถ้าคุณต้องการ
ค้นหาไดโนเสาร์ทุกตัวที่สูงอย่างน้อย 3 เมตร คุณรวม orderByChild()
เข้าด้วยกันได้
และ startAt()
:
Java
dinosaursRef.orderByChild("height").startAt(3).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').startAt(3).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').start_at(3).get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").StartAt(3).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
คุณสามารถใช้ endAt()
เพื่อค้นหาไดโนเสาร์ทุกตัวที่มีชื่อก่อนเทอโรแดคทิล
แบบพจนานุกรม:
Java
dinosaursRef.orderByKey().endAt("pterodactyl").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByKey().endAt('pterodactyl').on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().end_at('pterodactyl').get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByKey().EndAt("pterodactyl").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
คุณสามารถรวม startAt()
และ endAt()
เพื่อจํากัดจุดสิ้นสุดทั้ง 2 ของ
คำถาม ตัวอย่างต่อไปนี้ค้นหาไดโนเสาร์ทุกตัวที่ชื่อขึ้นต้นด้วย "b"
Java
dinosaursRef.orderByKey().startAt("b").endAt("b\uf8ff").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
var ref = db.ref('dinosaurs'); ref.orderByKey().startAt('b').endAt('b\uf8ff').on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().start_at('b').end_at(u'b\uf8ff').get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByKey().StartAt("b").EndAt("b\uf8ff").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
เมธอด equalTo()
ช่วยให้คุณกรองตามผลลัพธ์ที่ตรงกันทั้งหมดได้ ตามที่เห็น
กับคำค้นหาช่วงอื่นๆ โหนดนี้จะเริ่มทำงานสำหรับโหนดย่อยที่ตรงกันแต่ละโหนด ตัวอย่างเช่น คุณสามารถ
ใช้ข้อความค้นหาต่อไปนี้เพื่อค้นหาไดโนเสาร์ทุกชนิดที่สูง 25 เมตร:
Java
dinosaursRef.orderByChild("height").equalTo(25).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').equalTo(25).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').equal_to(25).get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").EqualTo(25).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
การค้นหาแบบช่วงยังมีประโยชน์เมื่อคุณต้องใส่เลขหน้าให้กับข้อมูลด้วย
กำลังประกอบรูปภาพเข้าด้วยกัน
โดยคุณจะรวมเทคนิคทั้งหมดเหล่านี้เข้าด้วยกันเพื่อสร้างคำค้นหาที่ซับซ้อนได้ ตัวอย่างเช่น คุณจะค้นหา ชื่อไดโนเสาร์ที่สั้นกว่าสเตโกซอรัสตรงๆ
Java
dinosaursRef.child("stegosaurus").child("height").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot stegoHeightSnapshot) { Integer favoriteDinoHeight = stegoHeightSnapshot.getValue(Integer.class); Query query = dinosaursRef.orderByChild("height").endAt(favoriteDinoHeight).limitToLast(2); query.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // Data is ordered by increasing height, so we want the first entry DataSnapshot firstChild = dataSnapshot.getChildren().iterator().next(); System.out.println("The dinosaur just shorter than the stegosaurus is: " + firstChild.getKey()); } @Override public void onCancelled(DatabaseError databaseError) { // ... } }); } @Override public void onCancelled(DatabaseError databaseError) { // ... } });
Node.js
const ref = db.ref('dinosaurs'); ref.child('stegosaurus').child('height').on('value', (stegosaurusHeightSnapshot) => { const favoriteDinoHeight = stegosaurusHeightSnapshot.val(); const queryRef = ref.orderByChild('height').endAt(favoriteDinoHeight).limitToLast(2); queryRef.on('value', (querySnapshot) => { if (querySnapshot.numChildren() === 2) { // Data is ordered by increasing height, so we want the first entry querySnapshot.forEach((dinoSnapshot) => { console.log('The dinosaur just shorter than the stegasaurus is ' + dinoSnapshot.key); // Returning true means that we will only loop through the forEach() one time return true; }); } else { console.log('The stegosaurus is the shortest dino'); } }); });
Python
ref = db.reference('dinosaurs') favotire_dino_height = ref.child('stegosaurus').child('height').get() query = ref.order_by_child('height').end_at(favotire_dino_height).limit_to_last(2) snapshot = query.get() if len(snapshot) == 2: # Data is ordered by increasing height, so we want the first entry. # Second entry is stegosarus. for key in snapshot: print('The dinosaur just shorter than the stegosaurus is {0}'.format(key)) return else: print('The stegosaurus is the shortest dino')
Go
ref := client.NewRef("dinosaurs") var favDinoHeight int if err := ref.Child("stegosaurus").Child("height").Get(ctx, &favDinoHeight); err != nil { log.Fatalln("Error querying database:", err) } query := ref.OrderByChild("height").EndAt(favDinoHeight).LimitToLast(2) results, err := query.GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } if len(results) == 2 { // Data is ordered by increasing height, so we want the first entry. // Second entry is stegosarus. fmt.Printf("The dinosaur just shorter than the stegosaurus is %s\n", results[0].Key()) } else { fmt.Println("The stegosaurus is the shortest dino") }
วิธีเรียงลำดับข้อมูล
ส่วนนี้จะอธิบายวิธีเรียงลำดับข้อมูลเมื่อใช้ฟังก์ชันการเรียงลำดับ 4 อย่าง
สั่งซื้อByรายการย่อย
เมื่อใช้ orderByChild()
ข้อมูลที่มีคีย์ย่อยที่ระบุจะเรียงลำดับดังนี้
- เด็กที่มีค่า
null
สำหรับคีย์ย่อยที่ระบุจะต้องมาก่อน - แท็กย่อยที่มีค่าเป็น
false
สำหรับคีย์ย่อยที่ระบุจะเกิดขึ้นในลำดับถัดไป หากมีเด็กหลายคนมีค่าเป็นfalse
ระบบจะจัดเรียงเด็กเหล่านั้นแบบพจนานุกรมตามคีย์ - แท็กย่อยที่มีค่าเป็น
true
สำหรับคีย์ย่อยที่ระบุจะเกิดขึ้นในลำดับถัดไป หากมีเด็กหลายคนมีค่าtrue
ระบบจะจัดเรียงแบบพจนานุกรมตามคีย์ - เด็กที่มีค่าตัวเลขจะแสดงอยู่ถัดไปโดยเรียงลำดับจากน้อยไปหามาก หากโหนดย่อยหลายรายการมีค่าตัวเลขเหมือนกันสำหรับโหนดย่อยที่ระบุ ระบบจะจัดเรียงตามคีย์
- สตริงจะอยู่หลังตัวเลขและจัดเรียงแบบพจนานุกรมตามลำดับจากน้อยไปมาก หากโหนดย่อยหลายรายการมีค่าเหมือนกันสำหรับโหนดย่อยที่ระบุ ระบบจะเรียงลำดับแบบพจนานุกรมตามคีย์
- ออบเจ็กต์อยู่ท้ายสุดและจัดเรียงแบบพจนานุกรมตามคีย์ในลำดับจากน้อยไปมาก
คีย์ตามลำดับ
เมื่อใช้ orderByKey()
เพื่อจัดเรียงข้อมูล ระบบจะส่งข้อมูลคืนตามลำดับคีย์จากน้อยไปมากดังนี้ โปรดทราบว่าคีย์ต้องเป็นสตริงเท่านั้น
- เด็กที่มีคีย์ซึ่งแยกวิเคราะห์ได้เป็นจำนวนเต็ม 32 บิตจะมีอยู่ก่อนแล้วโดยจัดเรียงจากน้อยไปมาก
- เด็กที่มีค่าสตริงเป็นคีย์ถัดไป ซึ่งจัดเรียงแบบพจนานุกรมจากน้อยไปมาก
มูลค่าการสั่งซื้อ
เมื่อใช้ orderByValue()
ระบบจะเรียงลำดับรายการย่อยตามค่า เกณฑ์การจัดลำดับจะเหมือนกับใน orderByChild()
ยกเว้นจะใช้ค่าของโหนดแทนค่าของคีย์ย่อยที่ระบุ