Abrufen von Daten

Dieses Dokument behandelt die Grundlagen des Abrufens von Datenbankdaten, die Reihenfolge der Daten und die Durchführung einfacher Datenabfragen. Der Datenabruf im Admin SDK wird in verschiedenen Programmiersprachen leicht unterschiedlich implementiert.

  1. Asynchrone Listener: In einer Firebase-Echtzeitdatenbank gespeicherte Daten werden durch Anhängen eines asynchronen Listeners an eine Datenbankreferenz abgerufen. Der Listener wird einmal für den Anfangszustand der Daten und jedes Mal, wenn sich die Daten ändern, erneut ausgelöst. Ein Ereignis-Listener kann verschiedene Arten von Ereignissen empfangen. Dieser Modus des Datenabrufs wird in Java-, Node.js- und Python-Admin-SDKs unterstützt.
  2. Blockierende Lesevorgänge: In einer Firebase-Echtzeitdatenbank gespeicherte Daten werden durch Aufrufen einer Blockierungsmethode für eine Datenbankreferenz abgerufen, die die an der Referenz gespeicherten Daten zurückgibt. Jeder Methodenaufruf ist ein einmaliger Vorgang. Das bedeutet, dass das SDK keine Rückrufe registriert, die auf nachfolgende Datenaktualisierungen warten. Dieses Modell des Datenabrufs wird in Python- und Go Admin-SDKs unterstützt.

Erste Schritte

Schauen wir uns noch einmal das Blogging-Beispiel aus dem vorherigen Artikel an, um zu verstehen, wie man Daten aus einer Firebase-Datenbank liest. Denken Sie daran, dass die Blogbeiträge in der Beispiel-App unter der Datenbank-URL https://docs-examples.firebaseio.com/server/ saving-data/fireblog/posts.json gespeichert sind. Um Ihre Beitragsdaten zu lesen, können Sie Folgendes tun:

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

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

Wenn Sie den obigen Code ausführen, sehen Sie ein Objekt, das alle Ihre in der Konsole protokollierten Beiträge enthält. Im Fall von Node.js und Java wird die Listener-Funktion jedes Mal aufgerufen, wenn neue Daten zu Ihrer Datenbankreferenz hinzugefügt werden, und Sie müssen dafür keinen zusätzlichen Code schreiben.

In Java und Node.js empfängt die Callback-Funktion einen DataSnapshot , bei dem es sich um einen Snapshot der Daten handelt. Ein Snapshot ist ein Bild der Daten einer bestimmten Datenbankreferenz zu einem bestimmten Zeitpunkt. Der Aufruf von val() / getValue() für einen Snapshot gibt eine sprachspezifische Objektdarstellung der Daten zurück. Wenn am Speicherort der Referenz keine Daten vorhanden sind, ist der Wert des Snapshots null . Die Methode get() in Python gibt direkt eine Python-Darstellung der Daten zurück. Die Get() -Funktion in Go entmarshmiert die Daten in eine bestimmte Datenstruktur.

Beachten Sie, dass wir im obigen Beispiel den Ereignistyp value verwendet haben, der den gesamten Inhalt einer Firebase-Datenbankreferenz liest, auch wenn sich nur ein Datenelement geändert hat. value ist einer der fünf unten aufgeführten verschiedenen Ereignistypen, die Sie zum Lesen von Daten aus der Datenbank verwenden können.

Lesen Sie Ereignistypen in Java und Node.js

Wert

Das value wird verwendet, um eine statische Momentaufnahme des Inhalts in einem bestimmten Datenbankpfad zu lesen, so wie er zum Zeitpunkt des Leseereignisses vorhanden war. Es wird einmal mit den Ausgangsdaten und jedes Mal, wenn sich die Daten ändern, erneut ausgelöst. Dem Ereignisrückruf wird ein Snapshot übergeben, der alle Daten an diesem Speicherort enthält, einschließlich untergeordneter Daten. Im obigen Codebeispiel hat value alle Blogbeiträge in Ihrer App zurückgegeben. Jedes Mal, wenn ein neuer Blog-Beitrag hinzugefügt wird, gibt die Rückruffunktion alle Beiträge zurück.

Kind hinzugefügt

Das Ereignis child_added wird normalerweise beim Abrufen einer Liste von Elementen aus der Datenbank verwendet. Im Gegensatz zu value , der den gesamten Inhalt des Speicherorts zurückgibt, wird child_added einmal für jedes vorhandene untergeordnete Element und dann jedes Mal erneut ausgelöst, wenn dem angegebenen Pfad ein neues untergeordnetes Element hinzugefügt wird. Dem Ereignisrückruf wird ein Snapshot übergeben, der die Daten des neuen untergeordneten Elements enthält. Zu Ordnungszwecken wird ihm außerdem ein zweites Argument übergeben, das den Schlüssel des vorherigen untergeordneten Elements enthält.

Wenn Sie nur die Daten zu jedem neuen Beitrag abrufen möchten, der Ihrer Blogging-App hinzugefügt wird, können Sie child_added verwenden:

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

In diesem Beispiel enthält der Snapshot ein Objekt mit einem einzelnen Blog-Beitrag. Da das SDK Beiträge durch Abrufen des Werts in Objekte umwandelt, haben Sie Zugriff auf die Eigenschaften „Autor“ und „Titel“ des Beitrags, indem Sie author “ bzw. title aufrufen. Sie haben auch über das zweite prevChildKey Argument Zugriff auf die vorherige Beitrags-ID.

Kind verändert

Das Ereignis child_changed wird jedes Mal ausgelöst, wenn ein untergeordneter Knoten geändert wird. Dazu gehören alle Änderungen an Nachkommen des untergeordneten Knotens. Es wird normalerweise in Verbindung mit child_added und child_removed verwendet, um auf Änderungen an einer Liste von Elementen zu reagieren. Der an den Ereignisrückruf übergebene Snapshot enthält die aktualisierten Daten für das untergeordnete Element.

Sie können child_changed verwenden, um aktualisierte Daten zu Blogbeiträgen zu lesen, wenn diese bearbeitet werden:

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

Kind entfernt

Das Ereignis child_removed wird ausgelöst, wenn ein unmittelbar untergeordnetes Element entfernt wird. Es wird normalerweise in Verbindung mit child_added und child_changed verwendet. Der an den Ereignisrückruf übergebene Snapshot enthält die Daten für das entfernte untergeordnete Element.

Im Blog-Beispiel können Sie child_removed verwenden, um eine Benachrichtigung über den gelöschten Beitrag in der Konsole zu protokollieren:

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

Kind ist umgezogen

Das Ereignis child_moved wird beim Arbeiten mit geordneten Daten verwendet, was im nächsten Abschnitt behandelt wird.

Veranstaltungsgarantien

Die Firebase-Datenbank bietet mehrere wichtige Garantien für Ereignisse:

Garantien für Datenbankereignisse
Ereignisse werden immer dann ausgelöst, wenn sich der lokale Zustand ändert.
Ereignisse spiegeln letztendlich immer den korrekten Zustand der Daten wider, selbst in Fällen, in denen lokale Vorgänge oder Zeitvorgaben zu vorübergehenden Unterschieden führen, beispielsweise bei einem vorübergehenden Verlust der Netzwerkverbindung.
Schreibvorgänge von einem einzelnen Client werden immer auf den Server geschrieben und der Reihe nach an andere Benutzer gesendet.
Wertereignisse werden immer zuletzt ausgelöst und enthalten garantiert Aktualisierungen aller anderen Ereignisse, die vor der Erstellung dieses Snapshots aufgetreten sind.

Da Wertereignisse immer zuletzt ausgelöst werden, funktioniert das folgende Beispiel immer:

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

Rückrufe trennen

Rückrufe werden entfernt, indem der Ereignistyp und die zu entfernende Rückruffunktion wie folgt angegeben werden:

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

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

Wenn Sie einen Bereichskontext an on() übergeben haben, muss dieser beim Trennen des Rückrufs übergeben werden:

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

Wenn Sie alle Rückrufe an einem Standort entfernen möchten, können Sie Folgendes tun:

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

Daten einmal lesen

In manchen Fällen kann es sinnvoll sein, dass ein Rückruf einmal aufgerufen und dann sofort entfernt wird. Um dies zu vereinfachen, haben wir eine Hilfsfunktion erstellt:

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

Daten abfragen

Mit Firebase-Datenbankabfragen können Sie Daten basierend auf verschiedenen Faktoren selektiv abrufen. Um eine Abfrage in Ihrer Datenbank zu erstellen, geben Sie zunächst an, wie Ihre Daten geordnet werden sollen, indem Sie eine der Ordnungsfunktionen verwenden: orderByChild() , orderByKey() oder orderByValue() . Sie können diese dann mit fünf anderen Methoden kombinieren, um komplexe Abfragen durchzuführen: limitToFirst() , limitToLast() , startAt() , endAt() und equalTo() .

Da wir alle bei Firebase Dinosaurier für ziemlich cool halten, verwenden wir einen Ausschnitt aus einer Beispieldatenbank mit Dinosaurier-Fakten, um zu demonstrieren, wie Sie Daten in Ihrer Firebase-Datenbank abfragen können:

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

Sie können Daten auf drei Arten ordnen: nach untergeordnetem Schlüssel , nach Schlüssel oder nach Wert . Eine einfache Datenbankabfrage beginnt mit einer dieser Ordnungsfunktionen, die im Folgenden erläutert werden.

Sortieren nach einem angegebenen untergeordneten Schlüssel

Sie können Knoten nach einem gemeinsamen untergeordneten Schlüssel ordnen, indem Sie diesen Schlüssel an orderByChild() übergeben. Um beispielsweise alle nach Größe sortierten Dinosaurier zu lesen, können Sie Folgendes tun:

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

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

Jeder Knoten, der nicht über den untergeordneten Schlüssel verfügt, den wir abfragen, wird mit dem Wert null sortiert, was bedeutet, dass er in der Reihenfolge an erster Stelle steht. Einzelheiten zur Reihenfolge der Daten finden Sie im Abschnitt „Wie Daten geordnet werden“ .

Abfragen können auch nach tief verschachtelten untergeordneten Elementen und nicht nur nach untergeordneten Elementen einer Ebene sortiert werden. Dies ist nützlich, wenn Sie tief verschachtelte Daten wie diese haben:

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

Um jetzt die Höhe abzufragen, können Sie statt eines einzelnen Schlüssels den vollständigen Pfad zum Objekt verwenden:

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

Abfragen können jeweils nur nach einem Schlüssel sortiert werden. Der mehrmalige Aufruf von orderByChild() für dieselbe Abfrage führt zu einem Fehler.

Bestellung nach Schlüssel

Sie können Knoten auch nach ihren Schlüsseln ordnen, indem Sie die Methode orderByKey() verwenden. Das folgende Beispiel liest alle Dinosaurier in alphabetischer Reihenfolge:

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

Sortierung nach Wert

Mit der Methode orderByValue() können Sie Knoten nach dem Wert ihrer untergeordneten Schlüssel ordnen. Nehmen wir an, die Dinosaurier veranstalten einen Dino-Sportwettbewerb und Sie verfolgen ihre Ergebnisse im folgenden Format:

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

Um die Dinosaurier nach ihrer Punktzahl zu sortieren, könnten Sie die folgende Abfrage erstellen:

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

Im Abschnitt „Wie Daten geordnet werden“ finden Sie eine Erklärung dazu, wie null , Boolesche-, Zeichenfolgen- und Objektwerte bei Verwendung von orderByValue() sortiert werden.

Komplexe Abfragen

Da nun klar ist, wie Ihre Daten geordnet sind, können Sie die unten beschriebenen Grenzwert- oder Bereichsmethoden verwenden, um komplexere Abfragen zu erstellen.

Begrenzen Sie Abfragen

Die Abfragen limitToFirst() und limitToLast() werden verwendet, um eine maximale Anzahl von untergeordneten Elementen festzulegen, die für einen bestimmten Rückruf synchronisiert werden sollen. Wenn Sie ein Limit von 100 festlegen, erhalten Sie zunächst nur bis zu 100 child_added Ereignisse. Wenn in Ihrer Datenbank weniger als 100 Nachrichten gespeichert sind, wird für jede Nachricht ein child_added Ereignis ausgelöst. Wenn Sie jedoch mehr als 100 Nachrichten haben, erhalten Sie nur für 100 dieser Nachrichten ein child_added -Ereignis. Dies sind die ersten 100 geordneten Nachrichten, wenn Sie limitToFirst() verwenden, oder die letzten 100 geordneten Nachrichten, wenn Sie limitToLast() verwenden. Wenn sich Elemente ändern, erhalten Sie child_added “-Ereignisse für Elemente, die in die Abfrage eingegeben werden, und child_removed -Ereignisse für Elemente, die sie verlassen, sodass die Gesamtzahl bei 100 bleibt.

Mithilfe der Dinosaurier-Faktendatenbank und orderByChild() können Sie die beiden schwersten Dinosaurier finden:

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

Der Rückruf child_added wird genau zweimal ausgelöst, es sei denn, in der Datenbank sind weniger als zwei Dinosaurier gespeichert. Es wird auch für jeden neuen, schwereren Dinosaurier ausgelöst, der zur Datenbank hinzugefügt wird. In Python gibt die Abfrage direkt ein OrderedDict zurück, das die beiden schwersten Dinosaurier enthält.

Ebenso können Sie die beiden kürzesten Dinosaurier finden, indem Sie limitToFirst() verwenden:

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

Der Rückruf child_added wird genau zweimal ausgelöst, es sei denn, in der Datenbank sind weniger als zwei Dinosaurier gespeichert. Es wird auch erneut ausgelöst, wenn einer der ersten beiden Dinosaurier aus der Datenbank entfernt wird, da ein neuer Dinosaurier nun der zweitkürzeste ist. In Python gibt die Abfrage direkt ein OrderedDict zurück, das die kürzesten Dinosaurier enthält.

Sie können Limit-Abfragen auch mit orderByValue() durchführen. Wenn Sie eine Rangliste mit den drei Dino-Sportdinosauriern mit der höchsten Punktzahl erstellen möchten, können Sie Folgendes tun:

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

Bereichsabfragen

Mit startAt() , endAt() und equalTo() können Sie beliebige Start- und Endpunkte für Ihre Abfragen auswählen. Wenn Sie beispielsweise alle Dinosaurier finden möchten, die mindestens drei Meter groß sind, können Sie orderByChild() und startAt() kombinieren:

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

Sie können endAt() verwenden, um alle Dinosaurier zu finden, deren Namen lexikographisch vor Pterodaktylus stehen:

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

Sie können startAt() und endAt() kombinieren, um beide Enden Ihrer Abfrage einzuschränken. Das folgende Beispiel findet alle Dinosaurier, deren Name mit dem Buchstaben „b“ beginnt:

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

Mit der Methode equalTo() können Sie nach genauen Übereinstimmungen filtern. Wie bei den anderen Bereichsabfragen wird sie für jeden passenden untergeordneten Knoten ausgelöst. Mit der folgenden Abfrage können Sie beispielsweise alle Dinosaurier finden, die 25 Meter groß sind:

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

Bereichsabfragen sind auch nützlich, wenn Sie Ihre Daten paginieren müssen.

Alles zusammenfügen

Sie können alle diese Techniken kombinieren, um komplexe Abfragen zu erstellen. Sie können beispielsweise den Namen des Dinosauriers finden, der nur kürzer als Stegosaurus ist:

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

So werden Daten geordnet

In diesem Abschnitt wird erläutert, wie Ihre Daten geordnet werden, wenn Sie jede der vier Bestellfunktionen verwenden.

orderByChild

Bei Verwendung von orderByChild() werden Daten, die den angegebenen untergeordneten Schlüssel enthalten, wie folgt sortiert:

  1. Kinder mit einem null für den angegebenen Kinderschlüssel stehen an erster Stelle.
  2. Als nächstes folgen Kinder mit dem Wert false für den angegebenen Kinderschlüssel. Wenn mehrere untergeordnete Elemente den Wert false haben, werden sie lexikografisch nach Schlüssel sortiert.
  3. Als nächstes folgen Kinder mit dem Wert true für den angegebenen Kinderschlüssel. Wenn mehrere untergeordnete Elemente den Wert true haben, werden sie lexikografisch nach Schlüssel sortiert.
  4. Als nächstes folgen Kinder mit einem numerischen Wert, sortiert in aufsteigender Reihenfolge. Wenn mehrere untergeordnete Knoten denselben numerischen Wert für den angegebenen untergeordneten Knoten haben, werden sie nach Schlüssel sortiert.
  5. Zeichenfolgen folgen nach Zahlen und werden lexikografisch in aufsteigender Reihenfolge sortiert. Wenn mehrere untergeordnete Knoten denselben Wert für den angegebenen untergeordneten Knoten haben, werden sie lexikografisch nach Schlüssel sortiert.
  6. Die Objekte stehen an letzter Stelle und werden lexikografisch nach Schlüssel in aufsteigender Reihenfolge sortiert.

orderByKey

Wenn Sie orderByKey() zum Sortieren Ihrer Daten verwenden, werden die Daten wie folgt in aufsteigender Reihenfolge nach Schlüssel zurückgegeben. Beachten Sie, dass Schlüssel nur Zeichenfolgen sein können.

  1. Kinder mit einem Schlüssel, der als 32-Bit-Ganzzahl geparst werden kann, stehen an erster Stelle und werden in aufsteigender Reihenfolge sortiert.
  2. Als nächstes folgen Kinder mit einem Zeichenfolgenwert als Schlüssel, lexikografisch in aufsteigender Reihenfolge sortiert.

orderByValue

Bei Verwendung von orderByValue() werden untergeordnete Elemente nach ihrem Wert sortiert. Die Sortierkriterien sind die gleichen wie bei orderByChild() , außer dass der Wert des Knotens anstelle des Werts eines angegebenen untergeordneten Schlüssels verwendet wird.