Pobieranie danych

W tym dokumencie omówiono podstawy pobierania danych z bazy danych, uporządkowania danych i wykonywania prostych zapytań dotyczących danych. Pobieranie danych w pakiecie Admin SDK jest wdrażane nieco inaczej w różnych językach programowania.

  1. Detektory asynchroniczne: dane przechowywane w bazie danych czasu rzeczywistego Firebase są pobierane przez dołączenie detektora asynchronicznego do odwołania do bazy danych. Odbiornik jest wyzwalany raz dla początkowego stanu danych i ponownie za każdym razem, gdy dane się zmieniają. Detektor zdarzeń może odbierać kilka różnych typów zdarzeń . Ten tryb pobierania danych jest obsługiwany w pakietach SDK Java, Node.js i Python Admin SDK.
  2. Blokowanie odczytów: dane przechowywane w bazie danych czasu rzeczywistego Firebase są pobierane przez wywołanie metody blokowania w odniesieniu do bazy danych, która zwraca dane przechowywane w tym odwołaniu. Każde wywołanie metody jest operacją jednorazową. Oznacza to, że SDK nie rejestruje żadnych wywołań zwrotnych, które nasłuchują kolejnych aktualizacji danych. Ten model pobierania danych jest obsługiwany w pakietach SDK Python i Go Admin.

Pierwsze kroki

Wróćmy do przykładu blogowania z poprzedniego artykułu, aby zrozumieć, jak odczytywać dane z bazy danych Firebase. Przypomnij sobie, że wpisy w blogu w przykładowej aplikacji są przechowywane pod adresem URL bazy danych https://docs-examples.firebaseio.com/server/saving-data/fireblog/posts.json . Aby odczytać dane swojego posta, możesz wykonać następujące czynności:

Jawa
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);
}); 
Pyton
# 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())
Iść

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

Jeśli uruchomisz powyższy kod, zobaczysz obiekt zawierający wszystkie Twoje posty zalogowane do konsoli. W przypadku Node.js i Javy funkcja listener jest wywoływana za każdym razem, gdy nowe dane są dodawane do Twojej bazy danych i nie musisz pisać żadnego dodatkowego kodu, aby to się stało.

W Javie i Node.js funkcja wywołania zwrotnego otrzymuje DataSnapshot , który jest migawką danych. Migawka to obraz danych w określonym odwołaniu do bazy danych w jednym punkcie w czasie. Wywołanie val() / getValue() na migawce zwraca obiektową reprezentację danych specyficzną dla języka. Jeśli w lokalizacji odniesienia nie ma żadnych danych, wartość migawki to null . Metoda get() w Pythonie zwraca bezpośrednio reprezentację danych w Pythonie. Funkcja Get() w Go przenosi dane do określonej struktury danych.

Zwróć uwagę, że w powyższym przykładzie użyliśmy typu zdarzenia value , który odczytuje całą zawartość odwołania do bazy danych Firebase, nawet jeśli zmienił się tylko jeden element danych. value to jeden z pięciu różnych typów zdarzeń wymienionych poniżej, których można używać do odczytywania danych z bazy danych.

Odczytywanie typów zdarzeń w Javie i Node.js

Wartość

Zdarzenie value służy do odczytywania statycznej migawki zawartości w danej ścieżce bazy danych, tak jak istniała ona w momencie zdarzenia odczytu. Jest wyzwalany raz z danymi początkowymi i ponownie za każdym razem, gdy dane się zmieniają. Do wywołania zwrotnego zdarzenia przekazuje się migawkę zawierającą wszystkie dane w tej lokalizacji, w tym dane podrzędne. W powyższym przykładzie kodu value zwróciła wszystkie posty na blogu w Twojej aplikacji. Za każdym razem, gdy zostanie dodany nowy post na blogu, funkcja wywołania zwrotnego zwróci wszystkie posty.

Dodano dziecko

Zdarzenie child_added jest zwykle używane podczas pobierania listy elementów z bazy danych. W przeciwieństwie do value , która zwraca całą zawartość lokalizacji, child_added jest wyzwalane raz dla każdego istniejącego dziecka, a następnie ponownie za każdym razem, gdy nowe dziecko jest dodawane do określonej ścieżki. Do wywołania zwrotnego zdarzenia przekazuje się migawkę zawierającą dane nowego dziecka. Dla celów porządkowania przekazywany jest również drugi argument zawierający klucz poprzedniego dziecka.

Jeśli chcesz pobrać tylko dane o każdym nowym poście dodanym do Twojej aplikacji do blogowania, możesz użyć child_added :

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

W tym przykładzie migawka będzie zawierać obiekt z indywidualnym wpisem na blogu. Ponieważ SDK konwertuje posty na obiekty, pobierając wartość, masz dostęp do właściwości autora i tytułu wpisu, wywołując odpowiednio author i title . Masz również dostęp do poprzedniego identyfikatora posta z drugiego argumentu prevChildKey .

Zmieniono dziecko

Zdarzenie child_changed jest wyzwalane za każdym razem, gdy węzeł podrzędny jest modyfikowany. Obejmuje to wszelkie modyfikacje potomków węzła podrzędnego. Jest zwykle używany w połączeniu z child_added i child_removed , aby odpowiadać na zmiany na liście elementów. Migawka przekazana do wywołania zwrotnego zdarzenia zawiera zaktualizowane dane dziecka.

Możesz użyć child_changed , aby przeczytać zaktualizowane dane w postach na blogu, gdy są one edytowane:

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

Dziecko usunięte

Zdarzenie child_removed jest wywoływane po usunięciu bezpośredniego dziecka. Jest zwykle używany w połączeniu z child_added i child_changed . Migawka przekazana do wywołania zwrotnego zdarzenia zawiera dane usuniętego elementu podrzędnego.

W przykładzie z blogiem możesz użyć child_removed , aby zarejestrować powiadomienie o usuniętym poście w konsoli:

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

Dziecko przeniesione

Zdarzenie child_moved jest używane podczas pracy z uporządkowanymi danymi, co zostało omówione w następnej sekcji .

Gwarancje na imprezy

Baza danych Firebase daje kilka ważnych gwarancji dotyczących zdarzeń:

Gwarancje na zdarzenia bazy danych
Zdarzenia będą zawsze wyzwalane, gdy zmieni się stan lokalny.
Zdarzenia zawsze będą ostatecznie odzwierciedlać poprawny stan danych, nawet w przypadkach, gdy lokalne operacje lub czasy powodują tymczasowe różnice, takie jak chwilowa utrata połączenia sieciowego.
Zapisy z pojedynczego klienta będą zawsze zapisywane na serwerze i rozsyłane do innych użytkowników w odpowiedniej kolejności.
Zdarzenia wartości są zawsze wyzwalane jako ostatnie i gwarantują, że zawierają aktualizacje z wszelkich innych zdarzeń, które wystąpiły przed wykonaniem tej migawki.

Ponieważ zdarzenia wartości są zawsze wyzwalane jako ostatnie, poniższy przykład zawsze będzie działał:

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

Odłączanie wywołań zwrotnych

Wywołania zwrotne są usuwane przez określenie typu zdarzenia i funkcji wywołania zwrotnego, które mają zostać usunięte, na przykład:

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

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

Jeśli przekazałeś kontekst zasięgu do on() , musi on zostać przekazany podczas odłączania wywołania zwrotnego:

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

Jeśli chcesz usunąć wszystkie wywołania zwrotne w lokalizacji, możesz wykonać następujące czynności:

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

Czytanie danych raz

W niektórych przypadkach może być przydatne jednokrotne wywołanie wywołania zwrotnego, a następnie natychmiastowe usunięcie. Stworzyliśmy funkcję pomocniczą, aby to ułatwić:

Jawa
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
});
Pyton
# 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())
Iść
// 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)
}

Odpytywanie danych

Za pomocą zapytań do bazy danych Firebase możesz selektywnie pobierać dane na podstawie różnych czynników. Aby skonstruować zapytanie w bazie danych, zacznij od określenia, jak chcesz uporządkować dane za pomocą jednej z funkcji porządkujących: orderByChild() , orderByKey() lub orderByValue() . Następnie możesz połączyć je z pięcioma innymi metodami w celu przeprowadzenia złożonych zapytań: limitToFirst() , limitToLast() , startAt() , endAt() i equalTo() .

Ponieważ wszyscy w Firebase uważamy, że dinozaury są całkiem fajne, użyjemy fragmentu z przykładowej bazy danych faktów o dinozaurach, aby zademonstrować, jak można wyszukiwać dane w bazie danych Firebase.:

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

Dane można uporządkować na trzy sposoby: według klucza podrzędnego , według klucza lub według wartości . Podstawowe zapytanie do bazy danych rozpoczyna się od jednej z tych funkcji porządkowania, z których każda została wyjaśniona poniżej.

Zamawianie według określonego klucza podrzędnego

Możesz uporządkować węzły według wspólnego klucza podrzędnego, przekazując ten klucz do orderByChild() . Na przykład, aby odczytać wszystkie dinozaury uporządkowane według wzrostu, możesz wykonać następujące czynności:

Jawa
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');
});
Pyton
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))
Iść

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

Każdy węzeł, który nie ma klucza podrzędnego, o który pytamy, jest sortowany z wartością null , co oznacza, że ​​znajdzie się na pierwszym miejscu w kolejności. Aby uzyskać szczegółowe informacje na temat porządkowania danych, zobacz sekcję Jak uporządkowane są dane .

Zapytania mogą być również porządkowane według głęboko zagnieżdżonych elementów potomnych, a nie tylko dzieci o jeden poziom niżej. Jest to przydatne, jeśli masz głęboko zagnieżdżone dane, takie jak:

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

Aby teraz zapytać o wysokość, możesz użyć pełnej ścieżki do obiektu zamiast pojedynczego klucza:

Jawa
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');
});
Pyton
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))
Iść
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)
}

Zapytania można zamawiać tylko według jednego klucza na raz. Wielokrotne wywołanie orderByChild() w tym samym zapytaniu powoduje błąd.

Zamawianie według klucza

Możesz również uporządkować węzły według ich kluczy za pomocą metody orderByKey() . Poniższy przykład odczytuje wszystkie dinozaury w kolejności alfabetycznej:

Jawa
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);
});
Pyton
ref = db.reference('dinosaurs')
snapshot = ref.order_by_key().get()
print(snapshot)
Iść
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)

Zamawianie według wartości

Możesz uporządkować węzły według wartości ich kluczy podrzędnych za pomocą metody orderByValue() . Załóżmy, że dinozaury organizują zawody sportowe dinozaurów, a ty śledzisz ich wyniki w następującym formacie:

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

Aby posortować dinozaury według ich wyniku, możesz skonstruować następujące zapytanie:

Jawa
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());
  });
});
Pyton
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))
Iść
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)
}

Zobacz sekcję Jak dane są uporządkowane , aby uzyskać wyjaśnienie, w jaki sposób null , boolean, string i object są sortowane podczas korzystania z orderByValue() .

Złożone zapytania

Teraz, gdy jest już jasne, jak uporządkowane są Twoje dane, możesz użyć opisanych poniżej metod limitu lub zakresu , aby skonstruować bardziej złożone zapytania.

Ogranicz zapytania

limitToFirst() i limitToLast() służą do ustawienia maksymalnej liczby dzieci, które mają być synchronizowane dla danego wywołania zwrotnego. Jeśli ustawisz limit 100, początkowo otrzymasz tylko do 100 zdarzeń child_added . Jeśli w bazie danych jest zapisanych mniej niż 100 wiadomości, dla każdej wiadomości zostanie wywołane zdarzenie child_added . Jeśli jednak masz ponad 100 wiadomości, otrzymasz zdarzenie child_added tylko dla 100 z tych wiadomości. Są to pierwsze 100 uporządkowanych wiadomości, jeśli używasz limitToFirst() lub ostatnie 100 uporządkowanych wiadomości, jeśli używasz limitToLast() . Gdy elementy się zmienią, otrzymasz zdarzenia child_added dla elementów, które wprowadzają zapytanie i zdarzenia child_removed dla elementów, które je opuszczają, tak aby całkowita liczba pozostała na poziomie 100.

Korzystając z bazy danych faktów o dinozaurach i orderByChild() , możesz znaleźć dwa najcięższe dinozaury:

Jawa
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);
});
Pyton
ref = db.reference('dinosaurs')
snapshot = ref.order_by_child('weight').limit_to_last(2).get()
for key in snapshot:
    print(key)
Iść
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 jest wywoływany dokładnie dwa razy, chyba że w bazie danych przechowywane są mniej niż dwa dinozaury. Zostanie również zwolniony za każdego nowego, cięższego dinozaura, który zostanie dodany do bazy danych. W Pythonie zapytanie bezpośrednio zwraca OrderedDict zawierający dwa najcięższe dinozaury.

Podobnie możesz znaleźć dwa najkrótsze dinozaury za pomocą limitToFirst() :

Jawa
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);
});
Pyton
ref = db.reference('dinosaurs')
snapshot = ref.order_by_child('height').limit_to_first(2).get()
for key in snapshot:
    print(key)
Iść
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 jest wywoływany dokładnie dwa razy, chyba że w bazie danych przechowywane są mniej niż dwa dinozaury. Zostanie również zwolniony ponownie, jeśli jeden z pierwszych dwóch dinozaurów zostanie usunięty z bazy danych, ponieważ nowy dinozaur będzie teraz drugim najkrótszym. W Pythonie zapytanie bezpośrednio zwraca OrderedDict zawierający najkrótsze dinozaury.

Możesz również przeprowadzać zapytania limitujące za pomocą orderByValue() . Jeśli chcesz stworzyć tabelę liderów z 3 najwyżej punktowanymi dinozaurami sportowymi, możesz wykonać następujące czynności:

Jawa
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());
  });
});
Pyton
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))
Iść
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)
}

Zapytania o zakres

Użycie startAt() , endAt() i equalTo() pozwala wybrać dowolny punkt początkowy i końcowy dla zapytań. Na przykład, jeśli chcesz znaleźć wszystkie dinozaury, które mają co najmniej trzy metry wysokości, możesz połączyć orderByChild() i startAt() :

Jawa
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);
});
Pyton
ref = db.reference('dinosaurs')
snapshot = ref.order_by_child('height').start_at(3).get()
for key in snapshot:
    print(key)
Iść
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())
}

Możesz użyć endAt() , aby znaleźć wszystkie dinozaury, których imiona są leksykograficzne przed Pterodactyl:

Jawa
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);
});
Pyton
ref = db.reference('dinosaurs')
snapshot = ref.order_by_key().end_at('pterodactyl').get()
for key in snapshot:
    print(key)
Iść
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())
}

Możesz połączyć startAt() i endAt() , aby ograniczyć oba końce zapytania. Poniższy przykład wyszukuje wszystkie dinozaury, których nazwa zaczyna się na literę „b”:

Jawa
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);
});
Pyton
ref = db.reference('dinosaurs')
snapshot = ref.order_by_key().start_at('b').end_at(u'b\uf8ff').get()
for key in snapshot:
    print(key)
Iść
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())
}

Metoda equalTo() umożliwia filtrowanie na podstawie dokładnych dopasowań. Podobnie jak w przypadku innych zapytań o zakres, zostanie on uruchomiony dla każdego pasującego węzła podrzędnego. Na przykład możesz użyć następującego zapytania, aby znaleźć wszystkie dinozaury, które mają 25 metrów wysokości:

Jawa
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);
});
Pyton
ref = db.reference('dinosaurs')
snapshot = ref.order_by_child('height').equal_to(25).get()
for key in snapshot:
    print(key)
Iść
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())
}

Zapytania o zakres są również przydatne, gdy trzeba podzielić dane na strony.

Kładąc wszystko razem

Wszystkie te techniki można łączyć, aby tworzyć złożone zapytania. Na przykład możesz znaleźć imię dinozaura, które jest tylko krótsze niż stegozaur:

Jawa
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');
      }
    });
});
Pyton
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')
Iść
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")
}

Jak uporządkowane są dane

W tej sekcji wyjaśniono, jak uporządkowane są Twoje dane podczas korzystania z każdej z czterech funkcji porządkowania.

orderByChild

Podczas korzystania z orderByChild() , dane zawierające określony klucz podrzędny są uporządkowane w następujący sposób:

  1. Dzieci z wartością null dla określonego klucza podrzędnego są na pierwszym miejscu.
  2. Dzieci z wartością false dla określonego klucza podrzędnego są następne. Jeśli wiele elementów potomnych ma wartość false , są one sortowane leksykograficznie według klucza.
  3. Dzieci z wartością true dla określonego klucza podrzędnego są następne. Jeśli wiele elementów potomnych ma wartość true , są one sortowane leksykograficznie według klucza.
  4. Następne są dzieci z wartością numeryczną, posortowane w porządku rosnącym. Jeśli wiele elementów podrzędnych ma tę samą wartość liczbową dla określonego węzła podrzędnego, są one sortowane według klucza.
  5. Łańcuchy występują po liczbach i są sortowane leksykograficznie w porządku rosnącym. Jeśli wiele elementów podrzędnych ma tę samą wartość dla określonego węzła podrzędnego, są one uporządkowane leksykograficznie według klucza.
  6. Obiekty znajdują się na końcu i są posortowane leksykograficznie według klucza w porządku rosnącym.

orderByKey

Gdy używasz orderByKey() do sortowania danych, dane są zwracane w kolejności rosnącej według klucza w następujący sposób. Pamiętaj, że klucze mogą być tylko ciągami.

  1. Dzieci z kluczem, który można przeanalizować jako 32-bitową liczbę całkowitą, są na pierwszym miejscu, posortowane w kolejności rosnącej.
  2. Dzieci z wartością ciągu jako kluczem są następne, posortowane leksykograficznie w porządku rosnącym.

zamów według wartości

Podczas korzystania z orderByValue() , dzieci są uporządkowane według ich wartości. Kryteria porządkowania są takie same jak w orderByChild() , z tym wyjątkiem, że zamiast wartości określonego klucza podrzędnego używana jest wartość węzła.