เอกสารนี้ครอบคลุมถึงพื้นฐานของการดึงข้อมูลฐานข้อมูล วิธีการเรียงลำดับข้อมูล และวิธีการดำเนินการสืบค้นข้อมูลแบบง่ายๆ การดึงข้อมูลใน Admin SDK มีการใช้งานแตกต่างกันเล็กน้อยในภาษาการเขียนโปรแกรมต่างๆ
- ผู้ฟังแบบอะซิงโครนัส: ข้อมูลที่จัดเก็บไว้ในฐานข้อมูล Firebase Realtime จะถูกดึงออกมาโดยการแนบตัวฟังแบบอะซิงโครนัสเข้ากับการอ้างอิงฐานข้อมูล Listener จะถูกทริกเกอร์หนึ่งครั้งสำหรับสถานะเริ่มต้นของข้อมูล และอีกครั้งทุกครั้งที่ข้อมูลมีการเปลี่ยนแปลง Listener เหตุการณ์อาจได้รับ เหตุการณ์หลายประเภท โหมดการดึงข้อมูลนี้รองรับใน Java, Node.js และ Python Admin SDK
- การบล็อกการอ่าน: ข้อมูลที่จัดเก็บไว้ในฐานข้อมูล Firebase Realtime จะถูกดึงออกมาโดยการเรียกใช้วิธีการบล็อกในการอ้างอิงฐานข้อมูล ซึ่งจะส่งคืนข้อมูลที่จัดเก็บไว้ในการอ้างอิง การเรียกเมธอดแต่ละครั้งเป็นการดำเนินการครั้งเดียว นั่นหมายความว่า SDK จะไม่ลงทะเบียนการเรียกกลับใดๆ ที่รับฟังการอัปเดตข้อมูลที่ตามมา การดึงข้อมูลโมเดลนี้รองรับ Python และ Go Admin SDK
เริ่มต้นใช้งาน
เรามาทบทวนตัวอย่างการเขียนบล็อกจากบทความที่แล้วเพื่อทำความเข้าใจวิธีอ่านข้อมูลจากฐานข้อมูล Firebase โปรดจำไว้ว่าโพสต์บล็อกในแอปตัวอย่างถูกเก็บไว้ที่ URL ฐานข้อมูล https://docs-examples.firebaseio.com/server/saving-data/fireblog/posts.json หากต้องการอ่านข้อมูลโพสต์ของคุณ คุณสามารถทำสิ่งต่อไปนี้:
ชวา
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()); } });
โหนด 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); });
หลาม
# 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())
ไป
// Post is a json-serializable type. type Post struct { Author string `json:"author,omitempty"` Title string `json:"title,omitempty"` } // 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) }
หากคุณเรียกใช้โค้ดข้างต้น คุณจะเห็นออบเจ็กต์ที่มีโพสต์ทั้งหมดของคุณบันทึกไว้ในคอนโซล ในกรณีของ Node.js และ Java ฟังก์ชัน Listener จะถูกเรียกใช้ทุกครั้งที่มีการเพิ่มข้อมูลใหม่ลงในการอ้างอิงฐานข้อมูลของคุณ และคุณไม่จำเป็นต้องเขียนโค้ดเพิ่มเติมใดๆ เพื่อให้สิ่งนี้เกิดขึ้น
ใน Java และ Node.js ฟังก์ชันการโทรกลับจะได้รับ DataSnapshot
ซึ่งเป็นสแน็ปช็อตของข้อมูล สแน็ปช็อตคือรูปภาพของข้อมูลที่อ้างอิงฐานข้อมูลเฉพาะ ณ จุดเวลาเดียว การเรียก val()
/ getValue()
บนสแน็ปช็อตจะส่งคืนการแสดงออบเจ็กต์เฉพาะภาษาของข้อมูล หากไม่มีข้อมูลอยู่ที่ตำแหน่งของข้อมูลอ้างอิง ค่าของสแนปชอตจะเป็น null
เมธอด get()
ใน Python ส่งคืนการแสดงข้อมูล Python โดยตรง ฟังก์ชัน Get()
ใน Go จะยกเลิกการจัดเรียงข้อมูลลงในโครงสร้างข้อมูลที่กำหนด
โปรดสังเกตว่าเราใช้ประเภทเหตุการณ์ value
ในตัวอย่างด้านบน ซึ่งจะอ่านเนื้อหาทั้งหมดของการอ้างอิงฐานข้อมูล Firebase แม้ว่าข้อมูลจะมีการเปลี่ยนแปลงเพียงชิ้นเดียวก็ตาม value
เป็นหนึ่งในห้าประเภทเหตุการณ์ที่แตกต่างกันตามรายการด้านล่างที่คุณสามารถใช้เพื่ออ่านข้อมูลจากฐานข้อมูล
อ่านประเภทเหตุการณ์ใน Java และ Node.js
ค่า
เหตุการณ์ value
ใช้เพื่ออ่านสแน็ปช็อตแบบคงที่ของเนื้อหาในพาธฐานข้อมูลที่กำหนด ตามที่มีอยู่ ณ เวลาที่เหตุการณ์อ่าน โดยจะถูกทริกเกอร์หนึ่งครั้งด้วยข้อมูลเริ่มต้นและอีกครั้งทุกครั้งที่ข้อมูลเปลี่ยนแปลง การเรียกกลับเหตุการณ์จะถูกส่งผ่านสแน็ปช็อตที่มีข้อมูลทั้งหมด ณ ตำแหน่งนั้น รวมถึงข้อมูลลูกด้วย ในตัวอย่างโค้ดด้านบน value
ส่งคืนโพสต์บล็อกทั้งหมดในแอปของคุณ ทุกครั้งที่มีการเพิ่มโพสต์ในบล็อกใหม่ ฟังก์ชันโทรกลับจะส่งคืนโพสต์ทั้งหมด
เพิ่มเด็กแล้ว
โดยทั่วไปแล้วเหตุการณ์ child_added
จะใช้เมื่อดึงรายการของรายการจากฐานข้อมูล ต่างจาก value
ที่ส่งคืนเนื้อหาทั้งหมดของตำแหน่งนั้น child_added
จะถูกทริกเกอร์หนึ่งครั้งสำหรับรายการย่อยที่มีอยู่แต่ละรายการ และอีกครั้งทุกครั้งที่มีการเพิ่มรายการย่อยใหม่ลงในเส้นทางที่ระบุ การเรียกกลับเหตุการณ์จะถูกส่งผ่านสแน็ปช็อตที่มีข้อมูลของเด็กใหม่ เพื่อวัตถุประสงค์ในการสั่งซื้อ อาร์กิวเมนต์ที่สองที่มีคีย์ย่อยก่อนหน้าจะถูกส่งผ่านด้วย
หากคุณต้องการดึงเฉพาะข้อมูลในแต่ละโพสต์ใหม่ที่เพิ่มลงในแอปบล็อกของคุณ คุณสามารถใช้ child_added
:
ชวา
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) {} });
โหนด 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
ตามลำดับ คุณยังสามารถเข้าถึง ID โพสต์ก่อนหน้าได้จากอาร์กิวเมนต์ prevChildKey
ที่สอง
เด็กเปลี่ยนไป
เหตุการณ์ child_changed
จะถูกทริกเกอร์ทุกครั้งที่มีการแก้ไขโหนดลูก ซึ่งรวมถึงการปรับเปลี่ยนใด ๆ กับการสืบทอดของโหนดลูก โดยทั่วไปจะใช้ร่วมกับ child_added
และ child_removed
เพื่อตอบสนองต่อการเปลี่ยนแปลงรายการต่างๆ สแน็ปช็อตที่ส่งไปยังการเรียกกลับเหตุการณ์ประกอบด้วยข้อมูลที่อัปเดตสำหรับเด็ก
คุณสามารถใช้ child_changed
เพื่ออ่านข้อมูลที่อัปเดตในโพสต์บล็อกเมื่อได้รับการแก้ไข:
ชวา
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) {} });
โหนด 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
สแน็ปช็อตที่ส่งไปยังการเรียกกลับเหตุการณ์ประกอบด้วยข้อมูลสำหรับเด็กที่ถูกลบออก
ในตัวอย่างบล็อก คุณสามารถใช้ child_removed
เพื่อบันทึกการแจ้งเตือนเกี่ยวกับโพสต์ที่ถูกลบไปยังคอนโซล:
ชวา
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) {} });
โหนด 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 ให้การรับประกันที่สำคัญหลายประการเกี่ยวกับเหตุการณ์:
การรับประกันเหตุการณ์ฐานข้อมูล |
---|
เหตุการณ์จะถูกทริกเกอร์เสมอเมื่อสถานะท้องถิ่นเปลี่ยนแปลง |
ในที่สุด เหตุการณ์ต่างๆ จะสะท้อนถึงสถานะที่ถูกต้องของข้อมูลเสมอ แม้ว่าในกรณีที่การดำเนินงานหรือเวลาในพื้นที่ทำให้เกิดความแตกต่างชั่วคราว เช่น การเชื่อมต่อเครือข่ายขาดหายชั่วคราว |
การเขียนจากไคลเอนต์เดียวจะถูกเขียนไปยังเซิร์ฟเวอร์เสมอและเผยแพร่ไปยังผู้ใช้รายอื่นตามลำดับ |
เหตุการณ์ค่าจะถูกทริกเกอร์เป็นครั้งสุดท้ายเสมอและรับประกันว่าจะมีการอัปเดตจากเหตุการณ์อื่นๆ ที่เกิดขึ้นก่อนที่จะบันทึกสแนปชอตนั้น |
เนื่องจากเหตุการณ์ค่าจะถูกทริกเกอร์เป็นลำดับสุดท้ายเสมอ ตัวอย่างต่อไปนี้จึงใช้ได้เสมอ:
ชวา
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) {} });
โหนด 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); });
การแยกการโทรกลับ
การเรียกกลับจะถูกลบออกโดยการระบุประเภทเหตุการณ์และฟังก์ชันการเรียกกลับที่จะลบออก ดังต่อไปนี้:
ชวา
// Create and attach listener ValueEventListener listener = new ValueEventListener() { // ... }; ref.addValueEventListener(listener); // Remove listener ref.removeEventListener(listener);
โหนด js
ref.off('value', originalCallback);
หากคุณส่งบริบทของขอบเขตไปที่ on()
จะต้องส่งผ่านเมื่อแยกการโทรกลับ:
ชวา
// Not applicable for Java
โหนด js
ref.off('value', originalCallback, ctx);
หากคุณต้องการลบการติดต่อกลับทั้งหมดในสถานที่ใดสถานที่หนึ่ง คุณสามารถทำสิ่งต่อไปนี้:
ชวา
// No Java equivalent, listeners must be removed individually.
โหนด js
// Remove all value callbacks ref.off('value'); // Remove all callbacks of any type ref.off();
อ่านข้อมูลครั้งเดียว
ในบางกรณี อาจมีประโยชน์สำหรับการเรียกกลับครั้งเดียวแล้วจึงลบออกทันที เราได้สร้างฟังก์ชันตัวช่วยเพื่อทำให้สิ่งนี้ง่ายขึ้น:
ชวา
ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // ... } @Override public void onCancelled(DatabaseError databaseError) { // ... } });
โหนด js
ref.once('value', (data) => { // do some stuff once });
หลาม
# 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())
ไป
// 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()
จากนั้น คุณสามารถรวมสิ่งเหล่านี้เข้ากับวิธีอื่นอีกห้าวิธีเพื่อทำการสืบค้นที่ซับซ้อน: limitToFirst()
, limitToLast()
, startAt()
, endAt()
และ equalTo()
เนื่องจากพวกเราทุกคนที่ Firebase คิดว่าไดโนเสาร์ค่อนข้างเจ๋ง เราจะใช้ตัวอย่างจากฐานข้อมูลตัวอย่างข้อเท็จจริงเกี่ยวกับไดโนเสาร์เพื่อสาธิตวิธีที่คุณสามารถสืบค้นข้อมูลในฐานข้อมูล Firebase ของคุณ:
{ "lambeosaurus": { "height" : 2.1, "length" : 12.5, "weight": 5000 }, "stegosaurus": { "height" : 4, "length" : 9, "weight" : 2500 } }
คุณสามารถเรียงลำดับข้อมูลได้สามวิธี: ตาม คีย์ลูก ตาม คีย์ หรือตาม ค่า การสืบค้นฐานข้อมูลพื้นฐานเริ่มต้นด้วยฟังก์ชันการเรียงลำดับอย่างใดอย่างหนึ่ง ซึ่งแต่ละฟังก์ชันจะอธิบายไว้ด้านล่าง
การเรียงลำดับด้วยคีย์ลูกที่ระบุ
คุณสามารถเรียงลำดับโหนดด้วยคีย์ลูกทั่วไปโดยส่งคีย์นั้นไปที่ orderByChild()
ตัวอย่างเช่น หากต้องการอ่านไดโนเสาร์ทั้งหมดโดยเรียงตามความสูง คุณสามารถทำสิ่งต่อไปนี้:
ชวา
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."); } // ... });
โหนด js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').on('child_added', (snapshot) => { console.log(snapshot.key + ' was ' + snapshot.val().height + ' meters tall'); });
หลาม
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))
ไป
// Dinosaur is a json-serializable type. type Dinosaur struct { Height int `json:"height"` Width int `json:"width"` } ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("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) }
โหนดใดๆ ที่ไม่มีคีย์ลูกที่เรากำลังสอบถามจะถูกจัดเรียงด้วยค่า null
ซึ่งหมายความว่าโหนดนั้นจะมาก่อนในลำดับ สำหรับรายละเอียดเกี่ยวกับวิธีการเรียงลำดับข้อมูล โปรดดู ส่วนวิธีการเรียงลำดับข้อมูล
การสืบค้นยังสามารถเรียงลำดับโดยรายการย่อยที่ซ้อนกันลึก แทนที่จะเรียงลำดับเพียงระดับเดียวเท่านั้น สิ่งนี้มีประโยชน์หากคุณมีข้อมูลที่ซ้อนกันลึกเช่นนี้:
{ "lambeosaurus": { "dimensions": { "height" : 2.1, "length" : 12.5, "weight": 5000 } }, "stegosaurus": { "dimensions": { "height" : 4, "length" : 9, "weight" : 2500 } } }
หากต้องการสอบถามความสูงตอนนี้ คุณสามารถใช้เส้นทางแบบเต็มไปยังออบเจ็กต์แทนที่จะใช้คีย์เดียว:
ชวา
dinosaursRef.orderByChild("dimensions/height").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { // ... } // ... });
โหนด js
const ref = db.ref('dinosaurs'); ref.orderByChild('dimensions/height').on('child_added', (snapshot) => { console.log(snapshot.key + ' was ' + snapshot.val().height + ' meters tall'); });
หลาม
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))
ไป
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) }
แบบสอบถามสามารถสั่งซื้อได้ครั้งละหนึ่งคีย์เท่านั้น การเรียก orderByChild()
หลายครั้งในแบบสอบถามเดียวกันทำให้เกิดข้อผิดพลาด
การสั่งซื้อโดยคีย์
คุณยังสามารถเรียงลำดับโหนดโดยใช้คีย์โดยใช้เมธอด orderByKey()
ตัวอย่างต่อไปนี้อ่านไดโนเสาร์ทั้งหมดตามลำดับตัวอักษร:
ชวา
dinosaursRef.orderByKey().addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
โหนด js
var ref = db.ref('dinosaurs'); ref.orderByKey().on('child_added', (snapshot) => { console.log(snapshot.key); });
หลาม
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().get() print(snapshot)
ไป
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 } }
หากต้องการจัดเรียงไดโนเสาร์ตามคะแนน คุณสามารถสร้างแบบสอบถามต่อไปนี้:
ชวา
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()); } // ... });
โหนด 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()); }); });
หลาม
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))
ไป
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()
แบบสอบถามที่ซับซ้อน
ตอนนี้เป็นที่ชัดเจนว่าข้อมูลของคุณถูกจัดลำดับอย่างไร คุณสามารถใช้วิธี จำกัด หรือ ช่วง ที่อธิบายไว้ด้านล่างเพื่อสร้างการสืบค้นที่ซับซ้อนมากขึ้นได้
จำกัดการสืบค้น
แบบสอบถาม limitToFirst()
และ limitToLast()
ใช้เพื่อตั้งค่าจำนวนลูกสูงสุดที่จะซิงค์สำหรับการโทรกลับที่กำหนด หากคุณกำหนดขีดจำกัดไว้ที่ 100 รายการ ในตอนแรกคุณจะได้รับกิจกรรม child_added
สูงสุด 100 รายการเท่านั้น หากคุณมีข้อความที่เก็บไว้ในฐานข้อมูลน้อยกว่า 100 ข้อความ เหตุการณ์ child_added
จะเริ่มทำงานสำหรับแต่ละข้อความ อย่างไรก็ตาม หากคุณมีข้อความมากกว่า 100 ข้อความ คุณจะได้รับกิจกรรม child_added
เพียง 100 ข้อความจากข้อความเหล่านั้น นี่คือข้อความที่เรียงลำดับ 100 ข้อความแรก หากคุณใช้ limitToFirst()
หรือข้อความที่สั่งซื้อ 100 ข้อความสุดท้าย หากคุณใช้ limitToLast()
เมื่อรายการเปลี่ยนแปลง คุณจะได้รับเหตุการณ์ child_added
สำหรับรายการที่ป้อนแบบสอบถามและกิจกรรม child_removed
สำหรับรายการที่ปล่อยไว้ เพื่อให้จำนวนทั้งหมดยังคงอยู่ที่ 100
การใช้ฐานข้อมูลไดโนเสาร์และ orderByChild()
คุณสามารถค้นหาไดโนเสาร์ที่หนักที่สุดสองตัวได้:
ชวา
dinosaursRef.orderByChild("weight").limitToLast(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
โหนด js
const ref = db.ref('dinosaurs'); ref.orderByChild('weight').limitToLast(2).on('child_added', (snapshot) => { console.log(snapshot.key); });
หลาม
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('weight').limit_to_last(2).get() for key in snapshot: print(key)
ไป
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
จะถูกทริกเกอร์สองครั้งพอดี เว้นแต่จะมีไดโนเสาร์น้อยกว่าสองตัวเก็บไว้ในฐานข้อมูล มันจะถูกไล่ออกสำหรับไดโนเสาร์ตัวใหม่ที่หนักกว่าทุกตัวที่ถูกเพิ่มเข้าไปในฐานข้อมูล ใน Python แบบสอบถามจะส่งคืน OrderedDict
ที่มีไดโนเสาร์ที่หนักที่สุดสองตัวโดยตรง
ในทำนองเดียวกัน คุณสามารถค้นหาไดโนเสาร์ที่สั้นที่สุดสองตัวได้โดยใช้ limitToFirst()
:
ชวา
dinosaursRef.orderByChild("weight").limitToFirst(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
โหนด js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').limitToFirst(2).on('child_added', (snapshot) => { console.log(snapshot.key); });
หลาม
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').limit_to_first(2).get() for key in snapshot: print(key)
ไป
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()) }
การเรียกกลับ child_added
จะถูกทริกเกอร์สองครั้งพอดี เว้นแต่จะมีไดโนเสาร์น้อยกว่าสองตัวเก็บไว้ในฐานข้อมูล มันจะถูกยิงอีกครั้งหากไดโนเสาร์ตัวใดตัวหนึ่งในสองตัวแรกถูกลบออกจากฐานข้อมูล เนื่องจากไดโนเสาร์ตัวใหม่จะสั้นที่สุดเป็นอันดับสอง ใน Python แบบสอบถามจะส่งคืน OrderedDict
ที่มีไดโนเสาร์ที่สั้นที่สุดโดยตรง
คุณยังสามารถดำเนินการค้นหาแบบจำกัดด้วย orderByValue()
หากคุณต้องการสร้างกระดานผู้นำที่มีไดโนเสาร์กีฬาไดโนที่มีคะแนนสูงสุด 3 อันดับแรก คุณสามารถทำสิ่งต่อไปนี้:
ชวา
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()); } // ... });
โหนด 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()); }); });
หลาม
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))
ไป
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()
:
ชวา
dinosaursRef.orderByChild("height").startAt(3).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
โหนด js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').startAt(3).on('child_added', (snapshot) => { console.log(snapshot.key); });
หลาม
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').start_at(3).get() for key in snapshot: print(key)
ไป
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()
เพื่อค้นหาไดโนเสาร์ทั้งหมดที่มีชื่ออยู่ข้างหน้า Pterodactyl ตามพจนานุกรม:
ชวา
dinosaursRef.orderByKey().endAt("pterodactyl").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
โหนด js
const ref = db.ref('dinosaurs'); ref.orderByKey().endAt('pterodactyl').on('child_added', (snapshot) => { console.log(snapshot.key); });
หลาม
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().end_at('pterodactyl').get() for key in snapshot: print(key)
ไป
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()
เพื่อจำกัดการสืบค้นทั้งสองด้าน ตัวอย่างต่อไปนี้ค้นหาไดโนเสาร์ทุกตัวที่ชื่อขึ้นต้นด้วยตัวอักษร "b":
ชวา
dinosaursRef.orderByKey().startAt("b").endAt("b\uf8ff").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
โหนด js
var ref = db.ref('dinosaurs'); ref.orderByKey().startAt('b').endAt('b\uf8ff').on('child_added', (snapshot) => { console.log(snapshot.key); });
หลาม
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().start_at('b').end_at(u'b\uf8ff').get() for key in snapshot: print(key)
ไป
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 เมตร:
ชวา
dinosaursRef.orderByChild("height").equalTo(25).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
โหนด js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').equalTo(25).on('child_added', (snapshot) => { console.log(snapshot.key); });
หลาม
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').equal_to(25).get() for key in snapshot: print(key)
ไป
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()) }
การสืบค้นแบบช่วงยังมีประโยชน์เมื่อคุณต้องการแบ่งหน้าข้อมูลของคุณ
วางมันทั้งหมดเข้าด้วยกัน
คุณสามารถรวมเทคนิคเหล่านี้ทั้งหมดเพื่อสร้างแบบสอบถามที่ซับซ้อนได้ ตัวอย่างเช่น คุณสามารถค้นหาชื่อของไดโนเสาร์ที่สั้นกว่าสเตโกซอรัส:
ชวา
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) { // ... } });
โหนด 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'); } }); });
หลาม
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')
ไป
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") }
วิธีเรียงลำดับข้อมูล
ส่วนนี้จะอธิบายวิธีการเรียงลำดับข้อมูลของคุณเมื่อใช้ฟังก์ชันการจัดลำดับทั้งสี่ฟังก์ชัน
สั่งซื้อ ByChild
เมื่อใช้ orderByChild()
ข้อมูลที่มีคีย์ลูกที่ระบุจะถูกเรียงลำดับดังนี้:
- รายการย่อยที่มีค่า
null
สำหรับคีย์ลูกที่ระบุจะต้องมาก่อน - รายการย่อยที่มีค่า
false
สำหรับคีย์ลูกที่ระบุจะอยู่ลำดับถัดไป หากลูกหลายคนมีค่าเป็นfalse
พวกเขาจะถูกจัดเรียงตาม พจนานุกรม ตามคีย์ - รายการย่อยที่มีค่า
true
สำหรับรหัสลูกที่ระบุจะอยู่ลำดับถัดไป หากรายการย่อยหลายรายการมีค่าเป็นtrue
รายการเหล่านั้นจะถูกจัดเรียงตามพจนานุกรมตามคีย์ - ลูกที่มีค่าตัวเลขจะมาถัดไป เรียงลำดับจากน้อยไปหามาก ถ้าลูกหลายคนมีค่าตัวเลขเหมือนกันสำหรับโหนดลูกที่ระบุ พวกเขาจะถูกจัดเรียงตามคีย์
- สตริงจะอยู่หลังตัวเลข และจัดเรียงตามพจนานุกรมจากน้อยไปหามาก หากลูกหลายคนมีค่าเดียวกันสำหรับโหนดลูกที่ระบุ พวกเขาจะถูกเรียงลำดับตามพจนานุกรมตามคีย์
- วัตถุจะอยู่ลำดับสุดท้าย และจัดเรียงพจนานุกรมตามคีย์ตามลำดับจากน้อยไปหามาก
สั่งซื้อ ByKey
เมื่อใช้ orderByKey()
เพื่อจัดเรียงข้อมูล ข้อมูลจะถูกส่งกลับโดยเรียงจากน้อยไปมากตามคีย์ดังนี้ โปรดทราบว่าคีย์ต้องเป็นสตริงเท่านั้น
- รายการย่อยที่มีคีย์ที่สามารถแยกวิเคราะห์เป็นจำนวนเต็ม 32 บิตมาก่อน โดยเรียงลำดับจากน้อยไปหามาก
- รายการย่อยที่มีค่าสตริงเป็นคีย์จะอยู่ลำดับถัดไป โดยเรียงลำดับตามพจนานุกรมจากน้อยไปหามาก
สั่งซื้อตามมูลค่า
เมื่อใช้ orderByValue()
ลูกจะถูกเรียงลำดับตามค่าของพวกเขา เกณฑ์การเรียงลำดับจะเหมือนกับใน orderByChild()
ยกเว้นว่าจะใช้ค่าของโหนดแทนค่าของคีย์ลูกที่ระบุ