Questo documento illustra le nozioni di base per il recupero dei dati del database, la loro organizzazione e come eseguire query semplici sui dati. Il recupero dei dati nell'SDK Admin è implementato in modo leggermente diverso nei diversi linguaggi di programmazione.
- Listener asincroni:I dati archiviati in un Firebase Realtime Database vengono recuperati collegando un listener asincrono a un riferimento di database. L'ascoltatore viene attivato una volta per lo stato iniziale dei dati e nuovamente ogni volta che i dati cambiano. Un gestore di eventi può ricevere diversi tipi di eventi. Questa modalità di recupero dei dati è supportata negli SDK di amministrazione Java, Node.js e Python.
- Letture bloccanti: I dati archiviati in un Firebase Realtime Database vengono recuperati richiamando un metodo di blocco su un riferimento al database, che restituisce i dati archiviati nel riferimento. Ogni chiamata al metodo è un'operazione singola. Ciò significa che l'SDK non registra alcun callback che ascolta gli aggiornamenti dei dati successivi. Questo modello di recupero dei dati è supportato negli SDK di amministrazione Python e Go.
Per iniziare
Esaminiamo di nuovo l'esempio di blogging dell'articolo precedente per capire come leggere i dati da un database Firebase. Ricorda che i post del blog nell'app di esempio sono archiviati nell'URL del database https://docs-examples.firebaseio.com/server/saving-data/fireblog/posts.json. Per leggere i dati dei post, puoi:
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())
Vai
// 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) }
Se esegui il codice riportato sopra, vedrai un oggetto contenente tutti i post registrati nella console. Nel caso di Node.js e Java, la funzione di listener viene chiamata ogni volta che vengono aggiunti nuovi dati al riferimento del database e non è necessario scrivere codice aggiuntivo per farlo.
In Java e Node.js, la funzione di callback riceve un DataSnapshot
, ovvero uno snapshot dei dati. Uno snapshot è un'immagine dei dati di un determinato riferimento del database in un singolo punto nel tempo. La chiamata a val()
/ getValue()
su uno snapshot restituisce una rappresentazione oggetto specifica per lingua dei dati. Se non esistono dati nella posizione del riferimento, il valore dell'istantanea è null
. Il metodo get()
in Python restituisce direttamente una rappresentazione Python dei dati. La funzione Get()
in Go esegue il unmarshaling dei dati in una determinata struttura di dati.
Tieni presente che nell'esempio riportato sopra abbiamo utilizzato il tipo di evento value
, che legge l'intero contenuto di un riferimento a un database Firebase, anche se è stato modificato un solo dato. value
è uno dei cinque diversi tipi di eventi elencati di seguito che puoi utilizzare per leggere i dati dal database.
Leggere i tipi di eventi in Java e Node.js
Valore
L'evento value
viene utilizzato per leggere uno snapshot statico dei contenuti in un determinato percorso del database, così come esistevano al momento dell'evento di lettura. Viene attivata una volta con i dati iniziali e di nuovo ogni volta che i dati cambiano. Al callback dell'evento viene passato uno snapshot contenente tutti i dati in quella posizione, inclusi i dati secondari. Nell'esempio di codice riportato sopra, value
ha restituito tutti i post del blog nella tua app. Ogni volta che viene aggiunto un nuovo post del blog, la funzione di callback restituirà tutti i post.
Elemento secondario aggiunto
L'evento child_added
viene in genere utilizzato per recuperare un elenco di elementi dal database. A differenza di value
, che restituisce l'intero contenuto della posizione, child_added
viene attivato una volta per ogni elemento secondario esistente e poi di nuovo ogni volta che viene aggiunto un nuovo elemento secondario al percorso specificato. Al callback dell'evento viene passato uno snapshot contenente i dati del nuovo bambino. Ai fini dell'ordinamento, viene passato anche un secondo argomento contenente la chiave del figlio precedente.
Se vuoi recuperare solo i dati di ogni nuovo post aggiunto alla tua app di blogging, puoi utilizzare child_added
:
Java
ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { Post newPost = dataSnapshot.getValue(Post.class); System.out.println("Author: " + newPost.author); System.out.println("Title: " + newPost.title); System.out.println("Previous Post ID: " + prevChildKey); } @Override public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildRemoved(DataSnapshot dataSnapshot) {} @Override public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
// Retrieve new posts as they are added to our database ref.on('child_added', (snapshot, prevChildKey) => { const newPost = snapshot.val(); console.log('Author: ' + newPost.author); console.log('Title: ' + newPost.title); console.log('Previous Post ID: ' + prevChildKey); });
In questo esempio, l'istantanea conterrà un oggetto con un singolo post del blog. Poiché l'SDK converte i post in oggetti recuperando il valore, hai accesso alle proprietà autore e titolo del post chiamando rispettivamente author
e title
. Hai anche accesso all'ID post precedente dal secondo argomento prevChildKey
.
Elemento secondario modificato
L'evento child_changed
viene attivato ogni volta che un nodo figlio viene modificato. Sono incluse eventuali modifiche ai discendenti del nodo figlio. Viene in genere utilizzato in combinazione con child_added
e child_removed
per rispondere alle modifiche a un elenco di elementi. Lo snapshot passato al callback dell'evento contiene i dati aggiornati per l'elemento secondario.
Puoi utilizzare child_changed
per leggere i dati aggiornati sui post del blog quando vengono modificati:
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); });
Bambino rimosso
L'evento child_removed
viene attivato quando viene rimosso un elemento figlio immediato. Viene in genere utilizzata in combinazione con child_added
e child_changed
. Lo snapshot passato al callback dell'evento contiene i dati dell'elemento secondario rimosso.
Nell'esempio del blog, puoi utilizzare child_removed
per registrare una notifica relativa al post eliminato nella console:
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'); });
Bambino trasferito
L'evento child_moved
viene utilizzato quando si lavora con dati ordinati, descritti nella sezione successiva.
Garanzie per gli eventi
Il database Firebase offre diverse garanzie importanti in merito agli eventi:
Garanzie per gli eventi del database |
---|
Gli eventi verranno sempre attivati quando lo stato locale cambia. |
Gli eventi rifletteranno sempre lo stato corretto dei dati, anche nei casi in cui le operazioni locali o la temporizzazione causino differenze temporanee, ad esempio in caso di perdita temporanea della connessione di rete. |
Le scritture di un singolo client verranno sempre scritte sul server e trasmesse agli altri utenti in ordine. |
Gli eventi Value vengono sempre attivati per ultimi e contengono aggiornamenti di tutti gli altri eventi che si sono verificati prima dell'acquisizione dello snapshot. |
Poiché gli eventi relativi al valore vengono sempre attivati per ultimi, il seguente esempio funzionerà sempre:
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); });
Scollegare i callback
I callback vengono rimossi specificando il tipo di evento e la funzione di callback da rimuovere, ad esempio:
Java
// Create and attach listener ValueEventListener listener = new ValueEventListener() { // ... }; ref.addValueEventListener(listener); // Remove listener ref.removeEventListener(listener);
Node.js
ref.off('value', originalCallback);
Se hai passato un contesto ambito a on()
, devi passarlo anche quando scolleghi il callback:
Java
// Not applicable for Java
Node.js
ref.off('value', originalCallback, ctx);
Se vuoi rimuovere tutti i callback in una località, puoi procedere nel seguente modo:
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();
Lettura dei dati una volta
In alcuni casi può essere utile chiamare un callback una volta e poi rimuoverlo immediatamente. Abbiamo creato una funzione di supporto per semplificare la procedura:
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())
Vai
// 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) }
Eseguire query sui dati
Con le query del database Firebase, puoi recuperare i dati in modo selettivo in base a vari fattori. Per creare una query nel database, inizia specificando come vuoi ordinare i dati utilizzando una delle funzioni di ordinamento: orderByChild()
, orderByKey()
o orderByValue()
. Puoi poi combinarli con altri cinque metodi per eseguire query complesse: limitToFirst()
,
limitToLast()
, startAt()
, endAt()
e equalTo()
.
Dato che tutti noi di Firebase pensiamo che i dinosauri siano fantastici, utilizzeremo uno snippet di un database di esempio di curiosità sui dinosauri per dimostrare come puoi eseguire query sui dati nel tuo database Firebase.:
{ "lambeosaurus": { "height" : 2.1, "length" : 12.5, "weight": 5000 }, "stegosaurus": { "height" : 4, "length" : 9, "weight" : 2500 } }
Puoi ordinare i dati in tre modi: per chiave secondaria, per chiave o per valore. Una query di database di base inizia con una di queste funzioni di ordinamento, ciascuna delle quali è spiegata di seguito.
Ordinamento in base a una chiave secondaria specificata
Puoi ordinare i nodi in base a una chiave secondaria comune passandola a orderByChild()
. Ad esempio, per leggere tutti i dinosauri ordinati in base all'altezza, puoi eseguire quanto segue:
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))
Vai
// 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) }
Qualsiasi nodo che non abbia la chiave secondaria su cui stiamo eseguendo la query viene ordinato con un valore di null
, il che significa che verrà visualizzato per primo nell'ordinamento. Per informazioni dettagliate sull'ordinamento dei dati, consulta la sezione Ordine dei dati.
Le query possono essere ordinate anche in base a elementi secondari nidificati in modo approfondito, anziché solo in base a elementi secondari di un livello inferiore. Questo è utile se hai dati nidificati in modo complesso come questo:
{ "lambeosaurus": { "dimensions": { "height" : 2.1, "length" : 12.5, "weight": 5000 } }, "stegosaurus": { "dimensions": { "height" : 4, "length" : 9, "weight" : 2500 } } }
Ora, per eseguire query sull'altezza, puoi utilizzare il percorso completo dell'oggetto anziché una singola chiave:
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))
Vai
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) }
Le query possono essere ordinate in base a una sola chiave alla volta. Se chiami orderByChild()
più volte nella stessa query, viene generato un errore.
Ordinamento per chiave
Puoi anche ordinare i nodi in base alle relative chiavi utilizzando il metodo orderByKey()
. L'esempio seguente legge tutti i dinosauri in ordine alfabetico:
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)
Vai
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)
Ordinamento per valore
Puoi ordinare i nodi in base al valore delle relative chiavi secondarie utilizzando il metodo orderByValue()
. Supponiamo che i dinosauri stiano partecipando a una competizione sportiva e tu stia tenendo traccia dei loro punteggi nel seguente formato:
{ "scores": { "bruhathkayosaurus" : 55, "lambeosaurus" : 21, "linhenykus" : 80, "pterodactyl" : 93, "stegosaurus" : 5, "triceratops" : 22 } }
Per ordinare i dinosauri in base al punteggio, puoi creare la seguente query:
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))
Vai
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) }
Consulta la sezione Come vengono ordinati i dati per una spiegazione su come vengono ordinati i valori null
, booleani, di stringa e di oggetto quando utilizzi orderByValue()
.
Query complesse
Ora che è chiaro come sono ordinati i dati, puoi utilizzare i metodi limit o range descritti di seguito per creare query più complesse.
Limita query
Le query limitToFirst()
e limitToLast()
vengono utilizzate per impostare un
numero massimo di elementi secondari da sincronizzare per un determinato callback. Se imposti un limite di 100, inizialmente riceverai solo fino a 100 eventi child_added
. Se nel tuo database sono archiviati meno di 100 messaggi, verrà attivato un evento child_added
per ogni messaggio. Tuttavia, se hai più di 100 messaggi, riceverai un evento child_added
solo per 100 di questi messaggi. Si tratta dei primi 100 messaggi ordinati se utilizzi
limitToFirst()
o degli ultimi 100 messaggi ordinati se utilizzi
limitToLast()
. Quando gli articoli cambiano, riceverai eventi child_added
per gli articoli che entrano nella query ed eventi child_removed
per quelli che la escono, in modo che il numero totale rimanga 100.
Utilizzando il database di fatti sui dinosauri e orderByChild()
, puoi trovare i due dinosauri più pesanti:
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)
Vai
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()) }
Il callback child_added
viene attivato esattamente due volte, a meno che nel database non siano memorizzati meno di due dinosauri. Verrà attivato anche per ogni nuovo dinosauro più pesante aggiunto al database.
In Python, la query restituisce direttamente un OrderedDict
contenente i due dinosauri più pesanti.
Allo stesso modo, puoi trovare i due dinosauri più piccoli utilizzando limitToFirst()
:
Java
dinosaursRef.orderByChild("weight").limitToFirst(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').limitToFirst(2).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').limit_to_first(2).get() for key in snapshot: print(key)
Vai
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()) }
Il callback child_added
viene attivato esattamente due volte, a meno che non siano presenti meno di due dinosauri nel database. Verrà attivato di nuovo anche se uno dei primi due dinosauri viene rimosso dal database, poiché un nuovo dinosauro sarà ora il secondo più corto. In Python, la query restituisce direttamente un OrderedDict
contenente i dinosauri più piccoli.
Puoi anche eseguire query con limiti con orderByValue()
. Se vuoi creare una classifica con i tre dinosauri sportivi con il punteggio più alto, puoi procedere nel seguente modo:
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))
Vai
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) }
Query sull'intervallo
L'utilizzo di startAt()
, endAt()
e equalTo()
ti consente di scegliere punti di inizio e di fine arbitrari per le query. Ad esempio, se vuoi trovare tutti i dinosauri alti almeno tre metri, puoi combinare orderByChild()
e startAt()
:
Java
dinosaursRef.orderByChild("height").startAt(3).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').startAt(3).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').start_at(3).get() for key in snapshot: print(key)
Vai
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()) }
Puoi utilizzare endAt()
per trovare tutti i dinosauri i cui nomi precedono Pterodattilo alfabeticamente:
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)
Vai
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()) }
Puoi combinare startAt()
e endAt()
per limitare entrambe le estremità della query. Il seguente esempio trova tutti i dinosauri il cui nome inizia con la lettera "b":
Java
dinosaursRef.orderByKey().startAt("b").endAt("b\uf8ff").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
var ref = db.ref('dinosaurs'); ref.orderByKey().startAt('b').endAt('b\uf8ff').on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().start_at('b').end_at(u'b\uf8ff').get() for key in snapshot: print(key)
Vai
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()) }
Il metodo equalTo()
consente di filtrare in base alle corrispondenze esatte. Come accade per le altre query sull'intervallo, viene attivata per ogni nodo secondario corrispondente. Ad esempio, puoi
utilizzare la seguente query per trovare tutti i dinosauri alti 25 metri:
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)
Vai
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()) }
Le query sull'intervallo sono utili anche quando devi paginare i dati.
In sintesi
Puoi combinare tutte queste tecniche per creare query complesse. Ad esempio, puoi trovare il nome del dinosauro che è solo più corto di Stegosaurus:
Java
dinosaursRef.child("stegosaurus").child("height").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot stegoHeightSnapshot) { Integer favoriteDinoHeight = stegoHeightSnapshot.getValue(Integer.class); Query query = dinosaursRef.orderByChild("height").endAt(favoriteDinoHeight).limitToLast(2); query.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // Data is ordered by increasing height, so we want the first entry DataSnapshot firstChild = dataSnapshot.getChildren().iterator().next(); System.out.println("The dinosaur just shorter than the stegosaurus is: " + firstChild.getKey()); } @Override public void onCancelled(DatabaseError databaseError) { // ... } }); } @Override public void onCancelled(DatabaseError databaseError) { // ... } });
Node.js
const ref = db.ref('dinosaurs'); ref.child('stegosaurus').child('height').on('value', (stegosaurusHeightSnapshot) => { const favoriteDinoHeight = stegosaurusHeightSnapshot.val(); const queryRef = ref.orderByChild('height').endAt(favoriteDinoHeight).limitToLast(2); queryRef.on('value', (querySnapshot) => { if (querySnapshot.numChildren() === 2) { // Data is ordered by increasing height, so we want the first entry querySnapshot.forEach((dinoSnapshot) => { console.log('The dinosaur just shorter than the stegasaurus is ' + dinoSnapshot.key); // Returning true means that we will only loop through the forEach() one time return true; }); } else { console.log('The stegosaurus is the shortest dino'); } }); });
Python
ref = db.reference('dinosaurs') favotire_dino_height = ref.child('stegosaurus').child('height').get() query = ref.order_by_child('height').end_at(favotire_dino_height).limit_to_last(2) snapshot = query.get() if len(snapshot) == 2: # Data is ordered by increasing height, so we want the first entry. # Second entry is stegosarus. for key in snapshot: print('The dinosaur just shorter than the stegosaurus is {0}'.format(key)) return else: print('The stegosaurus is the shortest dino')
Vai
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") }
Come vengono ordinati i dati
Questa sezione spiega come vengono ordinati i dati quando utilizzi ciascuna delle quattro funzioni di ordinamento.
orderByChild
Quando utilizzi orderByChild()
, i dati che contengono la chiave secondaria specificata sono ordinati come segue:
- I figli con un valore
null
per la chiave secondaria specificata vengono visualizzati per primi. - Seguono gli elementi secondari con un valore di
false
per la chiave secondaria specificata. Se più elementi secondari hanno un valorefalse
, vengono ordinati in ordine alfabetico in base alla chiave. - Seguono gli elementi secondari con un valore di
true
per la chiave secondaria specificata. Se più elementi secondari hanno un valoretrue
, vengono ordinati in ordine alfabetico per chiave. - Seguono gli elementi secondari con un valore numerico, ordinati in ordine crescente. Se più elementi secondari hanno lo stesso valore numerico per il nodo secondario specificato, vengono ordinati in base alla chiave.
- Le stringhe vengono visualizzate dopo i numeri e sono ordinate in ordine crescente in base al codice. Se più elementi figlio hanno lo stesso valore per il nodo figlio specificato, vengono ordinati in ordine alfabetico per chiave.
- Gli oggetti vengono visualizzati per ultimi e ordinati in ordine lessicografico per chiave in ordine crescente.
orderByKey
Quando utilizzi orderByKey()
per ordinare i dati, questi vengono restituiti in ordine crescente per chiave come segue. Tieni presente che le chiavi possono essere solo stringhe.
- I figli con una chiave che può essere analizzata come numero intero a 32 bit vengono visualizzati per primi, in ordine crescente.
- Seguono gli elementi secondari con una stringa come chiave, ordinati in ordine lessicografico crescente.
orderByValue
Quando utilizzi orderByValue()
, gli elementi secondari vengono ordinati in base al loro valore. I criteri di ordinamento sono gli stessi di orderByChild()
, tranne per il fatto che viene utilizzato il valore del nodo anziché il valore di una chiave secondaria specificata.