Mengambil Data

Dokumen ini membahas dasar-dasar pengambilan data database, bagaimana data diurutkan, dan cara melakukan kueri sederhana pada data. Pengambilan data di Admin SDK diterapkan dengan cara yang sedikit berbeda di bahasa pemrograman yang berbeda.

  1. Pemroses asinkron: Data yang disimpan di Firebase Realtime Database diambil dengan melampirkan pemroses asinkron ke referensi database. Pemroses ini dipicu sekali untuk status awal data dan dipicu kembali setiap kali data berubah. Pemroses peristiwa dapat menerima jenis peristiwa yang berbeda. Cara pengambilan data ini didukung di Admin SDK Java, Node.js, dan Python.
  2. Pemblokiran pembacaan: Data yang tersimpan dalam Firebase Realtime Database diambil dengan meminta metode pemblokiran pada referensi database yang menampilkan data yang tersimpan pada referensi. Masing-masing pemanggilan metode adalah operasi sekali pakai. Itu berarti SDK tidak mendaftarkan callback yang mendeteksi update data berikutnya. Model pengambilan data ini didukung di Python dan Go Admin SDK.

Memulai

Perhatikan kembali contoh blogging dari artikel sebelumnya untuk memahami cara membaca data dari database Firebase. Harap diingat bahwa postingan blog dalam contoh aplikasi disimpan di URL database https://docs-examples.firebaseio.com/server/saving-data/fireblog/posts.json. Untuk membaca data postingan, Anda dapat melakukan hal berikut:

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)
}

Jika Anda menjalankan kode di atas, Anda akan melihat objek yang berisi semua postingan Anda yang dibuat lognya ke konsol. Pada kasus Node.js dan Java, fungsi pemroses ini akan dipanggil setiap kali data baru ditambahkan ke referensi database dan Anda tidak perlu menulis kode tambahan untuk menjalankannya.

Di Java dan Node.js, fungsi callback menerima DataSnapshot, yang merupakan snapshot data. Snapshot adalah foto dari data pada referensi database tertentu pada suatu titik waktu. Memanggil val() / getValue() pada snapshot akan menampilkan representasi objek spesifik bahasa dari data tersebut. Jika tidak ada data di lokasi referensi, nilai snapshot akan menjadi null. Metode get() di Python menampilkan representasi Python dari data secara langsung. Fungsi Get() dalam Go memecah susunan data ke dalam struktur data tertentu.

Perlu diperhatikan bahwa kita menggunakan jenis peristiwa value pada contoh di atas, yang akan membaca seluruh isi referensi database Firebase, meskipun hanya ada satu bagian data yang berubah. value adalah salah satu dari lima jenis peristiwa berbeda yang tercantum di bawah ini yang dapat Anda gunakan untuk membaca data dari database.

Jenis Peristiwa Baca di Java dan Node.js

Nilai

Peristiwa value digunakan untuk membaca snapshot statis konten pada jalur database tertentu ketika peristiwa baca terjadi. Hal ini akan terpicu sekali saat data berada di kondisi awal data dan terpicu lagi setiap kali data berubah. Callback peristiwa diberikan snapshot yang berisi semua data di lokasi tersebut, termasuk data turunan. Dalam contoh kode di atas, value menampilkan semua postingan blog di aplikasi Anda. Setiap kali postingan blog baru ditambahkan, fungsi callback akan menampilkan semua postingan.

Child Added (Turunan Ditambahkan)

Peristiwa child_added biasanya digunakan saat mengambil daftar item dari database. Tidak seperti value yang menampilkan seluruh konten lokasi, child_added dipicu satu kali untuk setiap turunan yang ada, dan akan dipicu lagi setiap kali ada turunan baru yang ditambahkan ke jalur yang ditetapkan. Callback peristiwa diberikan snapshot yang berisi data turunan baru. Demi kemudahan pengurutan, callback peristiwa juga akan diberikan argumen kedua yang berisi kunci dari turunan sebelumnya.

Jika Anda hanya ingin mengambil data di setiap postingan baru yang ditambahkan ke aplikasi blogging, Anda dapat menggunakan 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);
});

Dalam contoh ini, snapshot akan berisi sebuah objek dengan postingan blog individu. Karena SDK mengonversi postingan menjadi objek dengan mengambil nilainya, Anda akan memiliki akses ke penulis dan properti judul postingan dengan memanggil author dan title. Anda juga memiliki akses ke ID postingan sebelumnya dari argumen prevChildKey kedua.

Child Changed (Turunan Diubah)

Peristiwa child_changed dipicu setiap kali node turunan diubah. Hal ini juga termasuk setiap perubahan pada turunan node turunan. Peristiwa ini biasanya digunakan bersamaan dengan child_added dan child_removed untuk menanggapi perubahan daftar item. Snapshot yang diteruskan ke callback peristiwa berisi data yang telah diupdate untuk turunan tersebut.

Anda bisa menggunakan child_changed untuk membaca data yang telah diupdate pada postingan blog ketika postingan tersebut diedit:

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 (Turunan Dihapus)

Peristiwa child_removed dipicu ketika turunan langsung dihapus. Peristiwa ini biasanya digunakan bersamaan dengan child_added dan child_changed. Snapshot yang diteruskan ke callback peristiwa berisi data untuk turunan yang dihapus.

Dalam contoh blog, Anda dapat menggunakan child_removed untuk mencatat notifikasi postingan yang dihapus ke konsol ke dalam log:

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 (Turunan Dipindahkan)

Peristiwa child_moved digunakan saat menangani data yang diurutkan, dan akan dibahas di bagian berikutnya.

Jaminan Peristiwa

Database Firebase membuat beberapa jaminan penting mengenai peristiwa:

Jaminan Peristiwa Database
Peristiwa akan selalu dipicu ketika kondisi lokal berubah.
Peristiwa akan selalu mencerminkan keadaan yang benar dari data, bahkan ketika operasi atau waktu lokal menyebabkan perbedaan sementara, misalnya hilangnya koneksi jaringan untuk sementara.
Operasi tulis dari klien tunggal akan selalu ditulis ke server dan disiarkan ke pengguna lain secara berurutan.
Peristiwa nilai selalu dipicu terakhir dan dijamin berisi update dari setiap peristiwa lainnya yang terjadi sebelum snapshot diambil.

Karena peristiwa nilai selalu dipicu terakhir, contoh berikut akan selalu bekerja:

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);
});

Melepaskan Callback

Callback dihapus dengan menetapkan tipe peristiwa dan fungsi callback yang akan dihapus, seperti berikut ini:

Java
// Create and attach listener
ValueEventListener listener = new ValueEventListener() {
    // ...
};
ref.addValueEventListener(listener);

// Remove listener
ref.removeEventListener(listener);
Node.js
ref.off('value', originalCallback);

Jika Anda meneruskan konteks cakupan ke on(), konteks tersebut harus diteruskan saat melepaskan callback:

Java
// Not applicable for Java
Node.js
ref.off('value', originalCallback, ctx);

Jika ingin menghapus semua callback di suatu lokasi, Anda bisa melakukan hal berikut:

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();

Membaca Data Sekali

Dalam beberapa kasus, mungkin akan lebih baik jika callback dipanggil sekali lalu segera dihapus. Kami telah membuat fungsi bantuan untuk memudahkan hal ini:

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)
}

Kueri Data

Dengan kueri database Firebase, Anda bisa mengambil data secara selektif berdasarkan berbagai macam faktor. Untuk membuat kueri dalam database, mulailah dengan menentukan metode pengurutan data yang Anda inginkan menggunakan salah satu fungsi pengurutan: orderByChild(), orderByKey(), atau orderByValue(). Selanjutnya, Anda dapat menggabungkan metode ini dengan lima metode lainnya untuk melakukan kueri yang kompleks: limitToFirst(), limitToLast(), startAt(), endAt(), dan equalTo().

Karena kami semua di Firebase suka dinosaurus, kami akan menggunakan cuplikan dari contoh database fakta dinosaurus untuk menunjukkan bagaimana Anda bisa melakukan kueri data di database Firebase:

{
  "lambeosaurus": {
    "height" : 2.1,
    "length" : 12.5,
    "weight": 5000
  },
  "stegosaurus": {
    "height" : 4,
    "length" : 9,
    "weight" : 2500
  }
}

Anda dapat mengurutkan data dengan tiga cara: berdasarkan kunci turunan, berdasarkan kunci, atau berdasarkan nilai. Kueri database dasar dimulai dengan salah satu fungsi pengurutan yang masing-masing akan dijelaskan di bawah ini.

Mengurutkan berdasarkan kunci turunan yang telah ditentukan

Anda dapat mengurutkan node berdasarkan kunci turunan umum dengan meneruskan kunci tersebut ke orderByChild(). Misalnya, untuk membaca semua dinosaurus yang diurutkan berdasarkan tinggi, Anda bisa melakukan hal berikut:

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)
}

Setiap node yang tidak memiliki kunci turunan yang sesuai dengan kueri akan diurutkan dengan nilai null, sehingga akan muncul di urutan pertama. Untuk mengetahui detail tentang cara data diurutkan, baca bagian Metode Pengurutan Data.

Kueri juga bisa diurutkan dengan turunan bertingkat yang dalam, bukan oleh turunan yang hanya satu level ke bawah. Hal ini berguna jika Anda memiliki data bertingkat yang dalam seperti ini:

{
  "lambeosaurus": {
    "dimensions": {
      "height" : 2.1,
      "length" : 12.5,
      "weight": 5000
    }
  },
  "stegosaurus": {
    "dimensions": {
      "height" : 4,
      "length" : 9,
      "weight" : 2500
    }
  }
}

Untuk menerapkan kueri terkait tinggi, kita dapat menggunakan jalur lengkap ke objek alih-alih kunci tunggal:

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)
}

Kueri hanya bisa menerapkan pengurutan dengan satu kunci pada satu waktu. Memanggil orderByChild() beberapa kali pada kueri yang sama akan memunculkan error.

Mengurutkan berdasarkan kunci

Anda juga dapat mengurutkan node berdasarkan kuncinya menggunakan metode orderByKey(). Contoh berikut membaca semua dinosaurus sesuai urutan abjad:

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)

Mengurutkan berdasarkan nilai

Anda dapat mengurutkan node berdasarkan nilai kunci turunannya menggunakan metode orderByValue(). Anggap dinosaurus sedang mengadakan kompetisi olahraga dino dan Anda mengikuti perkembangan skornya dalam format berikut:

{
  "scores": {
    "bruhathkayosaurus" : 55,
    "lambeosaurus" : 21,
    "linhenykus" : 80,
    "pterodactyl" : 93,
    "stegosaurus" : 5,
    "triceratops" : 22
  }
}

Untuk mengurutkan dinosaurus berdasarkan skor yang diraihnya, Anda bisa membuat kueri berikut:

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)
}

Baca bagian Metode Pengurutan Data untuk mendapatkan penjelasan mengenai pengurutan nilai null, boolean, string, dan objek jika orderByValue() digunakan.

Kueri Kompleks

Setelah memahami pengurutan data, Anda dapat menggunakan metode batas atau rentang yang dijelaskan di bawah ini untuk membuat kueri yang lebih kompleks.

Kueri Batas

Kueri limitToFirst() dan limitToLast() digunakan untuk menetapkan jumlah turunan maksimum yang akan disinkronkan untuk callback tertentu. Jika Anda menetapkan batas 100, pada awalnya Anda hanya akan menerima hingga 100 peristiwa child_added. Jika Anda memiliki kurang dari 100 pesan yang tersimpan dalam database, peristiwa child_added akan diaktifkan untuk setiap pesan. Namun, jika ada lebih dari 100 pesan, Anda hanya akan menerima peristiwa child_added untuk 100 pesan tersebut. Ini adalah 100 pesan urutan pertama jika Anda menggunakan limitToFirst() atau 100 pesan urutan terakhir jika Anda menggunakan limitToLast(). Saat item berubah, Anda akan menerima peristiwa child_added untuk item yang memasukkan kueri dan peristiwa child_removed untuk item yang keluar dari kueri, sehingga jumlah totalnya tetap 100.

Dengan menggunakan database fakta dinosaurus dan orderByChild(), Anda dapat menemukan dua dinosaurus terberat:

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())
}

Callback child_added akan terpicu tepat dua kali, kecuali jika jumlah dinosaurus di database kurang dari dua. Callback ini juga akan terpicu dengan setiap dinosaurus baru yang lebih berat yang ditambahkan ke database. Dalam Python, kueri secara langsung menampilkan OrderedDict yang berisi dua dinosaurus terberat.

Demikian pula, Anda bisa menemukan dua dinosaurus terpendek dengan menggunakan 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 akan terpicu tepat dua kali, kecuali jika jumlah dinosaurus di database kurang dari dua. Callback ini juga akan terpicu lagi jika salah satu dari kedua dinosaurus pertama dihapus dari database, sehingga menyebabkan dinosaurus baru menjadi terpendek kedua. Dalam Python, kueri secara langsung menampilkan OrderedDict yang berisi dinosaurus terpendek.

Anda juga dapat melakukan kueri batas dengan orderByValue(). Jika Anda ingin membuat papan peringkat dinosaurus yang masuk 3 besar dengan skor tertinggi di olahraga dino, Anda bisa melakukan hal berikut:

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)
}

Kueri Rentang

Anda dapat menggunakan startAt(), endAt(), dan equalTo() untuk memilih titik awal dan akhir arbitrer untuk kueri Anda. Misalnya, jika Anda ingin menemukan semua dinosaurus dengan tinggi minimal tiga meter, Anda dapat menggabungkan orderByChild() dan 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())
}

Anda dapat menggunakan endAt() untuk menemukan semua dinosaurus yang namanya muncul sebelum Pterodactyl secara leksikografis:

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())
}

Anda dapat menggabungkan startAt() dan endAt() untuk membatasi kedua ujung kueri Anda. Contoh berikut menemukan semua dinosaurus yang namanya dimulai dengan huruf "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())
}

Metode equalTo() dapat Anda gunakan untuk melakukan filter berdasarkan pencocokan persis. Seperti halnya dengan kueri rentang lainnya, pemicuan akan terjadi untuk setiap node turunan yang cocok. Misalnya, Anda bisa menggunakan kueri berikut untuk menemukan semua dinosaurus yang tingginya 25 meter:

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())
}

Kueri rentang juga berguna ketika Anda perlu memberi nomor pada data.

Menggabungkan semuanya

Anda bisa menggabungkan semua teknik ini untuk membuat kueri yang kompleks. Misalnya, Anda bisa menemukan nama dinosaurus yang lebih pendek dari Stegosaurus:

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")
}

Metode Pengurutan Data

Bagian ini menjelaskan bagaimana data Anda diurutkan ketika menggunakan empat fungsi pengurutan yang berbeda.

orderByChild

Jika Anda menggunakan orderByChild(), data yang berisi kunci turunan yang ditentukan akan diurutkan sebagai berikut:

  1. Turunan yang memiliki nilai null untuk kunci turunan yang ditentukan akan muncul terlebih dahulu.
  2. Turunan yang memiliki nilai false untuk kunci turunan yang ditentukan akan muncul berikutnya. Jika beberapa turunan memiliki nilai false, turunan tersebut akan diurutkan secara leksikografis berdasarkan kunci.
  3. Turunan yang memiliki nilai true untuk kunci turunan yang ditentukan akan muncul berikutnya. Jika beberapa turunan memiliki nilai true, turunan tersebut akan diurutkan secara leksikografis berdasarkan kunci.
  4. Turunan dengan nilai numerik akan muncul berikutnya, dan diurutkan dalam urutan menaik. Jika beberapa turunan memiliki nilai numerik yang sama untuk node turunan yang ditentukan, turunan tersebut akan diurutkan berdasarkan kunci.
  5. String muncul setelah angka, dan diurutkan secara leksikografis dalam urutan menaik. Jika beberapa turunan memiliki nilai yang sama untuk node turunan yang ditentukan, turunan tersebut akan diurutkan secara leksikografis menurut kunci.
  6. Objek muncul terakhir, dan diurutkan secara leksikografis berdasarkan kunci dalam urutan menaik.

orderByKey

Data yang diurutkan menggunakan orderByKey() akan ditampilkan dalam urutan menaik menurut kunci sebagai berikut. Perlu diingat bahwa kunci hanya bisa berupa string.

  1. Turunan dengan kunci yang bisa diurai sebagai bilangan bulat 32-bit berada di urutan atas, dan diurutkan menaik.
  2. Turunan dengan nilai string sebagai kuncinya berada di urutan berikutnya, diurutkan secara leksikografis dalam urutan menaik.

orderByValue

Ketika menggunakan orderByValue(), turunan akan diurutkan berdasarkan nilainya. Kriteria urutan sama seperti di orderByChild(), tetapi yang digunakan adalah nilai node, bukan nilai kunci turunan yang ditentukan.