W tym dokumencie omówiono podstawy pobierania danych z bazy danych, sposób porządkowania danych oraz wykonywanie prostych zapytań dotyczących danych. Pobieranie danych w pakiecie Admin SDK jest realizowane nieco inaczej w różnych językach programowania.
- Odbiorniki asynchroniczne: dane przechowywane w bazie danych czasu rzeczywistego Firebase są pobierane przez dołączenie odbiornika asynchronicznego do odwołania do bazy danych. Odbiornik jest uruchamiany raz dla początkowego stanu danych i ponownie za każdym razem, gdy dane się zmieniają. Odbiornik zdarzeń może odbierać kilka różnych typów zdarzeń . Ten tryb pobierania danych jest obsługiwany w pakietach Java, Node.js i Python Admin SDK.
- Blokowanie odczytów: dane przechowywane w bazie danych czasu rzeczywistego Firebase są pobierane przez wywołanie metody blokowania w odwołaniu do bazy danych, która zwraca dane przechowywane w 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 zestawach SDK Python i Go Admin.
Rozpoczęcie pracy
Wróćmy do przykładu blogowania z poprzedniego artykułu, aby zrozumieć, jak odczytywać dane z bazy danych Firebase. Przypomnij sobie, że posty na 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 postów, 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 wpisy zarejestrowane w konsoli. W przypadku Node.js i Javy funkcja nasłuchiwania jest wywoływana za każdym razem, gdy do odniesienia do bazy danych dodawane są nowe dane i nie trzeba pisać żadnego dodatkowego kodu, aby tak się stało.
W Javie i Node.js funkcja wywołania zwrotnego otrzymuje DataSnapshot
, która 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 specyficzną dla języka reprezentację obiektową danych. Jeśli w lokalizacji odwołania nie istnieją żadne dane, wartość migawki jest null
. Metoda get()
w Pythonie zwraca bezpośrednio reprezentację danych w języku Python. 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
jest jednym z pięciu różnych typów zdarzeń wymienionych poniżej, których można użyć do odczytania danych z bazy danych.
Przeczytaj Typy 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 read. Jest uruchamiany raz z danymi początkowymi i ponownie za każdym razem, gdy dane się zmieniają. Wywołanie zwrotne zdarzenia przekazuje 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 dodawany jest 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 elementu podrzędnego, a następnie ponownie za każdym razem, gdy do określonej ścieżki zostanie dodany nowy element podrzędny. Wywołanie zwrotne zdarzenia przekazuje migawkę zawierającą dane nowego dziecka. W celu uporządkowania przekazywany jest również drugi argument zawierający klucz poprzedniego elementu potomnego.
Jeśli chcesz pobrać tylko dane dotyczące każdego nowego posta dodanego do 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 postem na blogu. Ponieważ zestaw SDK konwertuje posty na obiekty, pobierając wartość, masz dostęp do właściwości autora i tytułu posta, wywołując odpowiednio author
i title
. Masz również dostęp do poprzedniego identyfikatora posta z drugiego argumentu prevChildKey
.
Dziecko zmienione
Zdarzenie child_changed
jest wyzwalane za każdym razem, gdy modyfikowany jest węzeł podrzędny. Obejmuje to wszelkie modyfikacje potomków węzła podrzędnego. Zwykle jest używany w połączeniu z child_added
i child_removed
w celu reagowania na zmiany na liście elementów. Migawka przekazana do wywołania zwrotnego zdarzenia zawiera zaktualizowane dane elementu podrzędnego.
Możesz użyć child_changed
aby odczytać zaktualizowane dane w postach na blogu, gdy są 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 wyzwalane po usunięciu bezpośredniego elementu podrzędnego. Zwykle jest 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 wydarzeń
Baza danych Firebase zapewnia kilka ważnych gwarancji dotyczących wydarzeń:
Gwarancje zdarzeń bazy danych |
---|
Zdarzenia będą zawsze wyzwalane, gdy zmieni się stan lokalny. |
Zdarzenia zawsze ostatecznie odzwierciedlają prawidłowy stan danych, nawet w przypadkach, gdy lokalne operacje lub synchronizacja powodują tymczasowe różnice, takie jak tymczasowa utrata połączenia sieciowego. |
Zapisy z pojedynczego klienta będą zawsze zapisywane na serwerze i rozgłaszane do innych użytkowników w kolejności. |
Zdarzenia związane z wartościami są zawsze wyzwalane jako ostatnie i gwarantują, że będą zawierały aktualizacje z wszelkich innych zdarzeń, które miały miejsce przed wykonaniem migawki. |
Ponieważ zdarzenia wartości są zawsze wyzwalane jako ostatnie, poniższy przykład zawsze zadział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óra ma zostać usunięta, 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 zakresu 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();
Odczyt danych raz
W niektórych przypadkach przydatne może być wywołanie wywołania zwrotnego raz, 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) }
Wyszukiwanie danych
Dzięki zapytaniom bazy danych Firebase możesz selektywnie pobierać dane na podstawie różnych czynników. Aby skonstruować zapytanie w bazie danych, należy rozpocząć od określenia sposobu uporządkowania danych za pomocą jednej z funkcji porządkujących: orderByChild()
, orderByKey()
lub orderByValue()
. Następnie można połączyć je z pięcioma innymi metodami w celu przeprowadzania 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 przykładowej bazy danych faktów o dinozaurach, aby zademonstrować, w jaki sposób 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 potomnego, 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 potomnego, o który pytamy, jest sortowany z wartością null
, co oznacza, że zajmie pierwsze miejsce w kolejności. Aby uzyskać szczegółowe informacje na temat porządkowania danych, zobacz sekcję Jak uporządkowane są dane .
Zapytania można również uporządkować według głęboko zagnieżdżonych elementów podrzędnych, a nie tylko podrzędnych o jeden poziom niżej. Jest to przydatne, jeśli masz głęboko zagnieżdżone dane, takie jak te:
{ "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 mogą porządkować tylko według jednego klucza naraz. Wielokrotne wywołanie orderByChild()
dla tego samego zapytania spowoduje zgłoszenie błędu.
Zamawianie według klucza
Możesz także uporządkować węzły według ich kluczy, używając 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)
Porządkowanie według wartości
Możesz uporządkować węzły według wartości ich kluczy potomnych, używając 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 wartości null
, boolean, string i object są sortowane podczas korzystania orderByValue()
.
Złożone zapytania
Teraz, gdy jest już jasne, w jaki sposób uporządkowane są Twoje dane, możesz użyć opisanych poniżej metod ograniczania lub zakresu , aby konstruować bardziej złożone zapytania.
Ogranicz zapytania
Zapytania limitToFirst()
i limitToLast()
służą do ustawiania maksymalnej liczby dzieci do zsynchronizowania dla danego wywołania zwrotnego. Jeśli ustawisz limit 100, początkowo otrzymasz tylko do 100 zdarzeń child_added
. Jeśli masz mniej niż 100 wiadomości przechowywanych w bazie danych, zdarzenie child_added
zostanie uruchomione dla każdej wiadomości. 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ą, będziesz otrzymywać zdarzenia child_added
dla elementów, które wchodzą w zapytanie, i zdarzenia child_removed
dla elementów, które je opuszczają, dzięki czemu łączna liczba pozostanie na poziomie 100.
Korzystając z bazy 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()) }
Wywołanie zwrotne child_added
jest uruchamiane dokładnie dwa razy, chyba że w bazie danych są przechowywane 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 zwraca bezpośrednio OrderedDict
zawierający dwa najcięższe dinozaury.
Podobnie możesz znaleźć dwa najkrótsze dinozaury, używając 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()) }
Wywołanie zwrotne child_added
jest uruchamiane dokładnie dwa razy, chyba że w bazie danych są przechowywane mniej niż dwa dinozaury. Zostanie również ponownie wystrzelony, jeśli jeden z dwóch pierwszych dinozaurów zostanie usunięty z bazy danych, ponieważ nowy dinozaur będzie teraz drugim najkrótszym dinozaurem. W Pythonie zapytanie zwraca bezpośrednio OrderedDict
zawierający najkrótsze dinozaury.
Zapytania o limity można również przeprowadzać za pomocą orderByValue()
. Jeśli chcesz stworzyć tabelę liderów z trzema najwyżej punktowanymi sportowymi dinozaurami dino, 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
Korzystanie z funkcji startAt()
, endAt()
i equalTo()
umożliwia wybranie dowolnego punktu początkowego i końcowego 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 nazwy leksykograficznie występują przed Pterodaktylem:
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 znajduje 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, uruchomi się 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
Możesz łączyć wszystkie te techniki, aby tworzyć złożone zapytania. Na przykład możesz znaleźć nazwę dinozaura, która jest nieco krótsza 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, w jaki sposób uporządkowane są Twoje dane podczas korzystania z każdej z czterech funkcji porządkowania.
zamów przez dziecko
Podczas korzystania z orderByChild()
dane zawierające określony klucz podrzędny są uporządkowane w następujący sposób:
- Dzieci z wartością
null
dla określonego klucza podrzędnego są na pierwszym miejscu. - Dzieci z wartością
false
dla określonego klucza potomnego są następne. Jeśli wiele elementów podrzędnych ma wartośćfalse
, są one sortowane leksykograficznie według klucza. - Dzieci z wartością
true
dla określonego klucza podrzędnego są następne. Jeśli wiele elementów podrzędnych ma wartośćtrue
, są one sortowane leksykograficznie według klucza. - Następne są dzieci z wartością liczbową, posortowane rosnąco. 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.
- Ciągi 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.
- Obiekty są na końcu i są sortowane leksykograficznie według klucza w porządku rosnącym.
zamów według klucza
Gdy używasz orderByKey()
do sortowania danych, dane są zwracane w porządku rosnącym według klucza w następujący sposób. Pamiętaj, że klucze mogą być tylko łańcuchami.
- Dzieci z kluczem, który można przeanalizować jako 32-bitową liczbę całkowitą, są pierwsze, posortowane w porządku rosnącym.
- Dzieci z wartością ciągu jako kluczem są następne, posortowane leksykograficznie w porządku rosnącym.
zamówienieWedługWartości
Podczas korzystania z orderByValue()
elementy podrzędne są sortowane według ich wartości. Kryteria porządkowania są takie same jak w przypadku orderByChild()
, z wyjątkiem tego, że zamiast wartości określonego klucza podrzędnego używana jest wartość węzła.