กำลังดึงข้อมูล

เอกสารนี้ครอบคลุมข้อมูลพื้นฐานเกี่ยวกับการดึงข้อมูลในฐานข้อมูล วิธีเรียงลำดับข้อมูล และวิธีดำเนินการ การค้นหาข้อมูลแบบง่ายๆ การดึงข้อมูลใน Admin SDK จะแตกต่างกันเล็กน้อย ภาษาโปรแกรม

  1. ผู้ฟังแบบไม่พร้อมกัน: ระบบจะดึงข้อมูลที่จัดเก็บในฐานข้อมูลเรียลไทม์ของ Firebase โดยการแนบ Listener แบบไม่พร้อมกันเข้ากับ การอ้างอิงฐานข้อมูล Listener จะทริกเกอร์ 1 ครั้งสำหรับสถานะเริ่มต้นของข้อมูลและ อีกครั้งทุกครั้งที่ข้อมูลเปลี่ยนแปลง Listener เหตุการณ์อาจได้รับ ประเภทของเหตุการณ์ รองรับโหมดการดึงข้อมูลนี้ ใน Java, Node.js และ Admin SDK ของ Python
  2. การบล็อกการอ่าน ข้อมูลที่จัดเก็บในฐานข้อมูลเรียลไทม์ของ Firebase จะดึงขึ้นมาโดยการเรียกใช้วิธีการบล็อกในฐานข้อมูล ข้อมูลอ้างอิง ซึ่งจะแสดงผลข้อมูลที่จัดเก็บไว้ที่ข้อมูลอ้างอิง การเรียกเมธอดแต่ละครั้งเป็นการเรียกครั้งเดียว การดำเนินการ ซึ่งหมายความว่า 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:"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 ฟังก์ชัน 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:"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 ซึ่งหมายความว่าโหนดจะมาก่อนในลำดับ ดูรายละเอียดเกี่ยวกับการเรียงลำดับข้อมูลได้ที่ส่วน "วิธีเรียงลำดับข้อมูล"

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

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

คีย์ตามลำดับ

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

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

ค่าคำสั่งซื้อ

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