本文說明擷取資料庫資料的基本概念、資料排序方式和執行方式 簡單的資料查詢方法Admin SDK 中的資料擷取作業導入方式略有不同 程式設計語言
- 非同步事件監聽器: 如要擷取儲存在 Firebase Realtime Database 中的資料,請將非同步事件監聽器附加至 資料庫參照監聽器會針對資料的初始狀態觸發一次 因為資料有所變動。事件監聽器可能會收到幾種不同的 。支援這種資料擷取模式 Java、Node.js 和 Python Admin SDK
- 封鎖讀取作業: 對資料庫叫用封鎖方法,即可擷取 Firebase Realtime Database 中儲存的資料 參照,傳回儲存在參照中的資料。每個方法呼叫都是 作業。這表示 SDK 不會註冊任何監聽後續資料更新的回呼。 Python 和 Go Admin SDK 支援這種資料擷取模型。
開始使用
讓我們再次回到上一篇文章的網誌範例,瞭解如何從 Firebase 資料庫讀取資料。喚回度 範例應用程式中的網誌文章儲存在資料庫網址 https://docs-examples.firebaseio.com/server/saving-data/fireblog/posts.json。 如要讀取貼文資料,您可以執行下列操作:
Java
public static class Post { public String author; public String title; public Post(String author, String title) { // ... } } // Get a reference to our posts final FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("server/saving-data/fireblog/posts"); // Attach a listener to read the data at our posts reference ref.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { Post post = dataSnapshot.getValue(Post.class); System.out.println(post); } @Override public void onCancelled(DatabaseError databaseError) { System.out.println("The read failed: " + databaseError.getCode()); } });
Node.js
// Get a database reference to our posts const db = getDatabase(); const ref = db.ref('server/saving-data/fireblog/posts'); // Attach an asynchronous callback to read the data at our posts reference ref.on('value', (snapshot) => { console.log(snapshot.val()); }, (errorObject) => { console.log('The read failed: ' + errorObject.name); });
Python
# Import database module. from firebase_admin import db # Get a database reference to our posts ref = db.reference('server/saving-data/fireblog/posts') # Read the data at the posts reference (this is a blocking operation) print(ref.get())
Go
// Post is a json-serializable type. type Post struct { Author string `json:a"uthor,omitempty`" Title string `json:t"itle,omitempty`" } // Create a database client from App. client, err := app.Database(ctx) if err != nil { log.Fatalln(E"rror initializing database client:," err) } // Get a database reference to our posts ref := client.NewRef(s"erver/saving-data/fireblog/posts)" // Read the data at the posts reference (this is a blocking operation) var post Post if err := ref.Get(ctx, p&ost); err != nil { log.Fatalln(E"rror reading value:," err) }
如果執行上述程式碼,就會看到一個物件,其中包含您記錄在控制台中的所有貼文。以 Node.js 和 Java 為例,在資料庫參照加入新資料時,系統就會呼叫事件監聽器函式,您不需要編寫任何額外的程式碼即可這麼做。
在 Java 和 Node.js 中,回呼函式會接收 DataSnapshot
,此為資料快照。快照是指在某個時間點上,特定資料庫參照的資料圖片。在快照上呼叫 val()
/ getValue()
,會傳回特定語言的資料物件表示法。如果參照的位置沒有任何資料,則快照的值為 null
。Python 中的 get()
方法會直接傳回資料的 Python 表示法。Go 中的 Get()
函式會將資料拆解為特定的資料結構。
請注意,我們在上述範例中使用了 value
事件類型,該類型會讀取 Firebase 資料庫參照的所有內容,即使只有一項資料變更也一樣。value
是下列五個不同事件類型之一,可用來從資料庫讀取資料。
讀取 Java 和 Node.js 中的事件類型
值
value
事件可用來讀取指定資料庫路徑的內容靜態快照,因為這些快照在讀取事件時就已存在。觸發條件與初始資料觸發一次,並在資料變更時再次觸發。事件回呼會傳遞一個快照,其中包含該位置的所有資料,包括子項資料。在上述程式碼範例中,value
傳回應用程式中的所有網誌文章。每次新增網誌文章時,回呼函式都會傳回所有文章。
已新增孩童
從資料庫擷取商品清單時,通常會使用 child_added
事件。有別於 value
會傳回位置全部的內容,child_added
會針對每個現有子項觸發一次,然後每當將新子項新增至指定路徑時,就會再次觸發。事件回呼會傳遞含有新子項資料的快照。為方便排序,系統也會傳遞包含前一個子項金鑰的第二個引數。
如果只想擷取加入網誌應用程式的每篇新文章資料,可以使用 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); });
在本例中,快照包含的個別網誌文章含有個別網誌文章。由於 SDK 會以擷取值的方式將文章轉換為物件,因此您可以分別呼叫 author
和 title
來存取文章的作者和標題屬性。您也可以存取第二個 prevChildKey
引數中的先前貼文 ID。
子發布商已變更
每當修改子節點時,就會觸發 child_changed
事件。這包括所有
子節點的子系的變更通常會搭配 child_added
使用
和 child_removed
來回應項目清單的變更。傳遞至事件回呼的快照包含子項的更新資料。
您可以在編輯網誌文章時,使用 child_changed
讀取網誌文章的更新資料:
Java
ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) { Post changedPost = dataSnapshot.getValue(Post.class); System.out.println("The updated post title is: " + changedPost.title); } @Override public void onChildRemoved(DataSnapshot dataSnapshot) {} @Override public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
// Get the data on a post that has changed ref.on('child_changed', (snapshot) => { const changedPost = snapshot.val(); console.log('The updated post title is ' + changedPost.title); });
已移除孩童
移除直接子項時,會觸發 child_removed
事件。通常會搭配 child_added
和 child_changed
使用。傳遞至事件回呼的快照包含已移除的子項資料。
在網誌範例中,您可以使用 child_removed
記錄已刪除貼文的通知到控制台:
Java
ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildRemoved(DataSnapshot dataSnapshot) { Post removedPost = dataSnapshot.getValue(Post.class); System.out.println("The blog post titled " + removedPost.title + " has been deleted"); } @Override public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
// Get a reference to our posts const ref = db.ref('server/saving-data/fireblog/posts'); // Get the data on a post that has been removed ref.on('child_removed', (snapshot) => { const deletedPost = snapshot.val(); console.log('The blog post titled \'' + deletedPost.title + '\' has been deleted'); });
孩子已移動
處理已排序資料時,系統會使用 child_moved
事件,詳情請參閱下一節。
活動保證
Firebase 資料庫為事件提供幾項重要保證:
資料庫事件保證 |
---|
當本機狀態變更時,一律都會觸發事件。 |
即使發生本機營運或本機作業 時間不會造成暫時性的差異,例如網路連線暫時中斷。 |
單一用戶端的寫入資料一律會寫入伺服器,並按順序向其他使用者廣播。 |
價值事件一律會在最後觸發,並保證會包含其他已發生事件的更新 但在建立快照之前 |
由於值事件一律會在最後觸發,因此以下範例一律有效:
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); });
卸離回呼
如要移除回呼,請指定事件類型和要移除的回呼函式,如下所示:
Java
// Create and attach listener ValueEventListener listener = new ValueEventListener() { // ... }; ref.addValueEventListener(listener); // Remove listener ref.removeEventListener(listener);
Node.js
ref.off('value', originalCallback);
如果您將範圍內容傳遞至 on()
,則必須在卸離回呼時傳遞此內容:
Java
// Not applicable for Java
Node.js
ref.off('value', originalCallback, ctx);
如要移除某個位置的所有回呼,可以執行以下步驟:
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();
讀取資料一次
在某些情況下,您可以呼叫一次回呼,然後立即移除。我們建立了輔助程式 功能來簡化這項作業:
Java
ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // ... } @Override public void onCancelled(DatabaseError databaseError) { // ... } });
Node.js
ref.once('value', (data) => { // do some stuff once });
Python
# Import database module. from firebase_admin import db # Get a database reference to our posts ref = db.reference('server/saving-data/fireblog/posts') # Read the data at the posts reference (this is a blocking operation) print(ref.get())
Go
// Create a database client from App. client, err := app.Database(ctx) if err != nil { log.Fatalln("Error initializing database client:", err) } // Get a database reference to our posts ref := client.NewRef("server/saving-data/fireblog/posts") // Read the data at the posts reference (this is a blocking operation) var post Post if err := ref.Get(ctx, &post); err != nil { log.Fatalln("Error reading value:", err) }
查詢資料
您可以運用 Firebase 資料庫查詢,根據各種因素選擇性地擷取資料。如要在資料庫中建構查詢,首先請使用下列其中一個排序函式指定資料排序方式:orderByChild()
、orderByKey()
或 orderByValue()
。然後,您可以將這些函式與另外五種方法結合,執行複雜的查詢:limitToFirst()
、
limitToLast()
、startAt()
、endAt()
和equalTo()
。
由於 Firebase 全體人員都認為恐龍很酷,因此我們會使用內含恐龍事實範例資料庫的程式碼片段,示範如何查詢 Firebase 資料庫中的資料。
{ "lambeosaurus": { "height" : 2.1, "length" : 12.5, "weight": 5000 }, "stegosaurus": { "height" : 4, "length" : 9, "weight" : 2500 } }
你可以透過三種方式排序資料:依子項鍵、鍵或值排序。基本的資料庫查詢會從以下其中一種排序函式開始,每個函式的說明如下。
按照指定的子項鍵排序
您可以按照通用子項鍵來排序節點,方法是將該鍵傳遞至 orderByChild()
。例如,如要閱讀依身高排序的所有恐龍,你可以
包括:
Java
public static class Dinosaur { public int height; public int weight; public Dinosaur(int height, int weight) { // ... } } final DatabaseReference dinosaursRef = database.getReference("dinosaurs"); dinosaursRef.orderByChild("height").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { Dinosaur dinosaur = dataSnapshot.getValue(Dinosaur.class); System.out.println(dataSnapshot.getKey() + " was " + dinosaur.height + " meters tall."); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').on('child_added', (snapshot) => { console.log(snapshot.key + ' was ' + snapshot.val().height + ' meters tall'); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').get() for key, val in snapshot.items(): print('{0} was {1} meters tall'.format(key, val))
Go
// Dinosaur is a json-serializable type. type Dinosaur struct { Height int `json:h"eight`" Width int `json:w"idth`" } ref := client.NewRef(d"inosaurs)" results, err := ref.OrderByChild(h"eight)".GetOrdered(ctx) if err != nil { log.Fatalln(E"rror querying database:," err) } for _, r := range results { var d Dinosaur if err := r.Unmarshal(d&); err != nil { log.Fatalln(E"rror unmarshaling result:," err) } fmt.Printf(%"s was %d meteres tall," r.Key(), d.Height) }
如果節點沒有我們查詢的子項鍵,則會以 null
值排序,也就是說,該節點會優先排序。如要進一步瞭解資料的排序方式,請參閱資料的排序方式一節。
查詢也可以由深層巢狀子項排序,而不只是子項一個層級的子項。如果您有如下的深層巢狀資料,這種做法就非常實用:
{ "lambeosaurus": { "dimensions": { "height" : 2.1, "length" : 12.5, "weight": 5000 } }, "stegosaurus": { "dimensions": { "height" : 4, "length" : 9, "weight" : 2500 } } }
如要立即查詢高度,您可以使用物件的完整路徑,而不只是單一鍵:
Java
dinosaursRef.orderByChild("dimensions/height").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { // ... } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('dimensions/height').on('child_added', (snapshot) => { console.log(snapshot.key + ' was ' + snapshot.val().height + ' meters tall'); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('dimensions/height').get() for key, val in snapshot.items(): print('{0} was {1} meters tall'.format(key, val))
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("dimensions/height").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var d Dinosaur if err := r.Unmarshal(&d); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("%s was %d meteres tall", r.Key(), d.Height) }
在查詢中,一次只能依一個鍵排序查詢。正在撥打 orderByChild()
多次重複執行相同查詢就會擲回錯誤。
依索引鍵排序
您也可以使用 orderByKey()
方法,依節點排序節點。
以下範例會按照字母順序讀取所有恐龍:
Java
dinosaursRef.orderByKey().addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
var ref = db.ref('dinosaurs'); ref.orderByKey().on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().get() print(snapshot)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByKey().GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } snapshot := make([]Dinosaur, len(results)) for i, r := range results { var d Dinosaur if err := r.Unmarshal(&d); err != nil { log.Fatalln("Error unmarshaling result:", err) } snapshot[i] = d } fmt.Println(snapshot)
依值排序
您可以使用 orderByValue()
方法,依照節點的子項鍵值排序節點。假設恐龍正在進行恐龍運動競賽,而您以下列格式追蹤他們的分數:
{ "scores": { "bruhathkayosaurus" : 55, "lambeosaurus" : 21, "linhenykus" : 80, "pterodactyl" : 93, "stegosaurus" : 5, "triceratops" : 22 } }
若要按照恐龍得分排序,可以建立下列查詢:
Java
DatabaseReference scoresRef = database.getReference("scores"); scoresRef.orderByValue().addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println("The " + dataSnapshot.getKey() + " score is " + dataSnapshot.getValue()); } // ... });
Node.js
const scoresRef = db.ref('scores'); scoresRef.orderByValue().on('value', (snapshot) => { snapshot.forEach((data) => { console.log('The ' + data.key + ' dinosaur\'s score is ' + data.val()); }); });
Python
ref = db.reference('scores') snapshot = ref.order_by_value().get() for key, val in snapshot.items(): print('The {0} dinosaur\'s score is {1}'.format(key, val))
Go
ref := client.NewRef("scores") results, err := ref.OrderByValue().GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var score int if err := r.Unmarshal(&score); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("The %s dinosaur's score is %d\n", r.Key(), score) }
請參閱資料的排序方式一節,瞭解使用 orderByValue()
時 null
、布林值、字串和物件值如何排序。
複雜查詢
現在,您已清楚瞭解如何排序資料,您可以使用下文所述的限制或範圍方法,建立更複雜的查詢。
限制查詢
limitToFirst()
和 limitToLast()
查詢可用來設定
要為特定回呼同步處理的子項數量上限。如果設定的上限是 100 個,
一開始最多只能接收 100 個 child_added
事件。如果少於
資料庫中儲存了 100 則訊息,則每則訊息都會觸發 child_added
事件
撰寫新的電子郵件訊息不過,如果您有超過 100 則訊息,則只會收到 child_added
此事件會有 100 則訊息。如果您使用
limitToFirst()
,或是最近 100 則已排序訊息 (如有)
limitToLast()
。當商品有異動時,您將會收到 child_added
個事件
針對輸入查詢的項目加上 child_removed
事件 (針對離開該查詢的項目),
因此總數會維持在 100
根據恐龍事實資料庫和 orderByChild()
,你可以找出
恐龍:
Java
dinosaursRef.orderByChild("weight").limitToLast(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('weight').limitToLast(2).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('weight').limit_to_last(2).get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("weight").LimitToLast(2).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
child_added
回呼會完全觸發兩次,除非
儲存在資料庫中的恐龍少於兩台。此外,每當新的恐龍新增到資料庫時,也會觸發那個嚴重的恐龍。
在 Python 中,查詢會直接傳回 OrderedDict
,其中包含兩個最重的恐龍。
同樣地,您可以使用 limitToFirst()
找出兩隻最短的恐龍:
Java
dinosaursRef.orderByChild("weight").limitToFirst(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').limitToFirst(2).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').limit_to_first(2).get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").LimitToFirst(2).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
除非資料庫中儲存的恐龍數量少於兩個,否則 child_added
回呼會完全觸發兩次。此外,如果將前兩隻恐龍從資料庫中移除,此現象也會再次觸發,因為新的恐龍現在會是第二短的恐龍。在 Python 中,查詢會直接傳回含有最短恐龍的 OrderedDict
。
您也可以使用 orderByValue()
對查詢執行限制查詢。如果想建立排行榜前 3 名的恐龍得分最高的恐龍,請按照下列步驟操作:
Java
scoresRef.orderByValue().limitToFirst(3).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println("The " + dataSnapshot.getKey() + " score is " + dataSnapshot.getValue()); } // ... });
Node.js
const scoresRef = db.ref('scores'); scoresRef.orderByValue().limitToLast(3).on('value', (snapshot) =>{ snapshot.forEach((data) => { console.log('The ' + data.key + ' dinosaur\'s score is ' + data.val()); }); });
Python
scores_ref = db.reference('scores') snapshot = scores_ref.order_by_value().limit_to_last(3).get() for key, val in snapshot.items(): print('The {0} dinosaur\'s score is {1}'.format(key, val))
Go
ref := client.NewRef("scores") results, err := ref.OrderByValue().LimitToLast(3).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var score int if err := r.Unmarshal(&score); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("The %s dinosaur's score is %d\n", r.Key(), score) }
範圍查詢
使用 startAt()
、endAt()
和 equalTo()
可讓您:
為查詢選擇任意的起點和終點。舉例來說
找出高度至少為 3 公尺的所有恐龍,您可以合併 orderByChild()
和 startAt()
:
Java
dinosaursRef.orderByChild("height").startAt(3).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').startAt(3).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').start_at(3).get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").StartAt(3).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
你可以使用 endAt()
找出所有姓名在《Pterodactyl》之前的恐龍
字母順序:
Java
dinosaursRef.orderByKey().endAt("pterodactyl").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByKey().endAt('pterodactyl').on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().end_at('pterodactyl').get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByKey().EndAt("pterodactyl").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
您可以結合 startAt()
和 endAt()
,限制
。以下範例可找出名稱開頭為「b」的所有恐龍:
Java
dinosaursRef.orderByKey().startAt("b").endAt("b\uf8ff").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
var ref = db.ref('dinosaurs'); ref.orderByKey().startAt('b').endAt('b\uf8ff').on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().start_at('b').end_at(u'b\uf8ff').get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByKey().StartAt("b").EndAt("b\uf8ff").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
equalTo()
方法可讓您根據完全符合進行篩選。如同
在其他範圍查詢中,每個相符的子節點都會觸發函式。舉例來說:
請使用下列查詢找出高度為 25 公尺的所有恐龍:
Java
dinosaursRef.orderByChild("height").equalTo(25).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').equalTo(25).on('child_added', (snapshot) => { console.log(snapshot.key); });
Python
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').equal_to(25).get() for key in snapshot: print(key)
Go
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").EqualTo(25).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
需要為資料分頁時,範圍查詢也相當實用。
全面整合使用
您可以結合上述所有技術來建立複雜的查詢。比如,您可以找到 用比 Stegosaurus 更短的恐龍名稱:
Java
dinosaursRef.child("stegosaurus").child("height").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot stegoHeightSnapshot) { Integer favoriteDinoHeight = stegoHeightSnapshot.getValue(Integer.class); Query query = dinosaursRef.orderByChild("height").endAt(favoriteDinoHeight).limitToLast(2); query.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // Data is ordered by increasing height, so we want the first entry DataSnapshot firstChild = dataSnapshot.getChildren().iterator().next(); System.out.println("The dinosaur just shorter than the stegosaurus is: " + firstChild.getKey()); } @Override public void onCancelled(DatabaseError databaseError) { // ... } }); } @Override public void onCancelled(DatabaseError databaseError) { // ... } });
Node.js
const ref = db.ref('dinosaurs'); ref.child('stegosaurus').child('height').on('value', (stegosaurusHeightSnapshot) => { const favoriteDinoHeight = stegosaurusHeightSnapshot.val(); const queryRef = ref.orderByChild('height').endAt(favoriteDinoHeight).limitToLast(2); queryRef.on('value', (querySnapshot) => { if (querySnapshot.numChildren() === 2) { // Data is ordered by increasing height, so we want the first entry querySnapshot.forEach((dinoSnapshot) => { console.log('The dinosaur just shorter than the stegasaurus is ' + dinoSnapshot.key); // Returning true means that we will only loop through the forEach() one time return true; }); } else { console.log('The stegosaurus is the shortest dino'); } }); });
Python
ref = db.reference('dinosaurs') favotire_dino_height = ref.child('stegosaurus').child('height').get() query = ref.order_by_child('height').end_at(favotire_dino_height).limit_to_last(2) snapshot = query.get() if len(snapshot) == 2: # Data is ordered by increasing height, so we want the first entry. # Second entry is stegosarus. for key in snapshot: print('The dinosaur just shorter than the stegosaurus is {0}'.format(key)) return else: print('The stegosaurus is the shortest dino')
Go
ref := client.NewRef("dinosaurs") var favDinoHeight int if err := ref.Child("stegosaurus").Child("height").Get(ctx, &favDinoHeight); err != nil { log.Fatalln("Error querying database:", err) } query := ref.OrderByChild("height").EndAt(favDinoHeight).LimitToLast(2) results, err := query.GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } if len(results) == 2 { // Data is ordered by increasing height, so we want the first entry. // Second entry is stegosarus. fmt.Printf("The dinosaur just shorter than the stegosaurus is %s\n", results[0].Key()) } else { fmt.Println("The stegosaurus is the shortest dino") }
資料的排序方式
本節將說明使用這四種排序函式時的資料排序方式。
orderByChild
使用 orderByChild()
時,包含指定子項鍵的資料會依以下順序排序:
- 針對指定子項金鑰,具有
null
值的子項會先列出。 - 指定子項金鑰值為
false
的子項接著會顯示。如果多個子項的值為false
,就會按照鍵的字母順序排序。 - 指定子項金鑰值為
true
的子項接著會顯示。如果多個子項的值為true
,就會按照鍵的字母順序排序。 - 含有數值的子項接著會以遞增順序排序。如果指定的子節點有多個子項具有相同的數值,則這些子項會按照鍵排序。
- 字串是由數字後方,並按字母順序排列,但以遞增順序排列。如果指定的子節點有多個子項的值相同,則會依照鍵的字母順序排列。
- 物件會在最後出現,並按照索引鍵順序排列,以遞增順序排列。
orderByKey
使用 orderByKey()
排序資料時,系統會根據索引鍵以遞增順序傳回資料,如下所示。請注意,金鑰只能包含字串。
- 如果子項的索引鍵可剖析為 32 位元整數,其內容會先以遞增順序排序。
- 具有字串值做為索引鍵的下一個子項,並依字母順序遞增排序。
orderByValue
使用 orderByValue()
時,子項會按照值的順序排列。排序條件與 orderByChild()
相同,但會使用節點的值取代指定子鍵的值。