本文將說明擷取資料的基本概念,以及如何排序和篩選 Firebase 資料。
事前準備
請確認您已設定應用程式,並可按照 Get Started 指南所述存取資料庫。
擷取資料
如要擷取 Firebase 資料,可以對 GetValue() 進行一次性呼叫,或將 ValueListener 附加至 FirebaseDatabase 參照。系統會針對資料的初始狀態呼叫一次值事件監聽器,並在資料變更時再次呼叫。
取得 DatabaseReference
如要將資料寫入資料庫,您需要 DatabaseReference 的執行個體:
// Get the root reference location of the database. firebase::database::DatabaseReference dbref = database->GetReference();
讀取資料一次
您可以使用 GetValue() 方法,讀取指定路徑內容的靜態快照一次。工作結果會包含快照,其中含有該位置的所有資料,包括子項資料。如果沒有資料,傳回的快照會是 null。
firebase::Future<firebase::database::DataSnapshot> result = dbRef.GetReference("Leaders").GetValue();
此時,要求已提出,但我們必須等待 Future 完成,才能讀取值。由於遊戲通常會循環執行,且回呼驅動程度低於其他應用程式,因此您通常會輪詢完成。
// In the game loop that polls for the result... if (result.status() != firebase::kFutureStatusPending) { if (result.status() != firebase::kFutureStatusComplete) { LogMessage("ERROR: GetValue() returned an invalid result."); // Handle the error... } else if (result.error() != firebase::database::kErrorNone) { LogMessage("ERROR: GetValue() returned error %d: %s", result.error(), result.error_message()); // Handle the error... } else { firebase::database::DataSnapshot snapshot = result.result(); // Do something with the snapshot... } }
這會顯示一些基本錯誤檢查,請參閱 firebase::Future 參考資料,進一步瞭解錯誤檢查,以及如何判斷結果何時就緒。
接聽事件
您可以新增事件監聽器,訂閱資料變更:
ValueListener 基礎類別
| 回撥電話 | 一般用途 |
|---|---|
OnValueChanged |
讀取及監聽路徑中所有內容的變更。 |
OnChildListener 基礎類別
OnChildAdded
| 擷取項目清單,或監聽項目清單的新增內容。
建議與 OnChildChanged 和 OnChildRemoved 搭配使用,監控清單變更。 |
OnChildChanged |
監聽清單中項目的變更。與 OnChildAdded 和 OnChildRemoved 搭配使用,監控清單變更。 |
OnChildRemoved |
監聽從清單中移除的項目。與 OnChildAdded 和 OnChildChanged 搭配使用,監控清單變更。 |
OnChildMoved |
監聽已排序的清單中項目順序的變更。OnChildMoved 回呼一律會接在 OnChildChanged 回呼之後,因為項目順序會變更 (根據目前的排序方法)。 |
ValueListener 類別
您可以使用 OnValueChanged 回呼,訂閱特定路徑內容的變更。附加事件監聽器時,系統會觸發這個回呼一次,之後每當資料 (包括子項) 變更時,也會再次觸發。回呼會收到快照,其中包含該位置的所有資料,包括子項資料。如果沒有資料,傳回的快照會是 null。
以下範例說明遊戲如何從資料庫擷取排行榜分數:
class LeadersValueListener : public firebase::database::ValueListener { public: void OnValueChanged( const firebase::database::DataSnapshot& snapshot) override { // Do something with the data in snapshot... } void OnCancelled(const firebase::database::Error& error_code, const char* error_message) override { LogMessage("ERROR: LeadersValueListener canceled: %d: %s", error_code, error_message); } }; // Elsewhere in the code... LeadersValueListener* listener = new LeadersValueListener(); firebase::Future<firebase::database::DataSnapshot> result = dbRef.GetReference("Leaders").AddValueListener(listener);
Future<DataSnapshot> 結果包含事件發生時,資料庫中指定位置的資料。對快照呼叫 value() 會傳回代表資料的 Variant。
在這個範例中,OnCancelled 方法也會遭到覆寫,以查看讀取作業是否取消。舉例來說,如果用戶端沒有從 Firebase 資料庫位置讀取的權限,系統可能會取消讀取。database::Error 會指出失敗原因。
ChildListener 類別
子事件會因應節點子項發生的特定作業而觸發,例如透過 PushChild() 方法新增子項,或透過 UpdateChildren() 方法更新子項。這些函式搭配使用,可用於監聽資料庫中特定節點的變更。舉例來說,遊戲可能會同時使用這些方法,監控遊戲工作階段留言中的活動,如下所示:
class SessionCommentsChildListener : public firebase::database::ChildListener { public: void OnChildAdded(const firebase::database::DataSnapshot& snapshot, const char* previous_sibling) override { // Do something with the data in snapshot ... } void OnChildChanged(const firebase::database::DataSnapshot& snapshot, const char* previous_sibling) override { // Do something with the data in snapshot ... } void OnChildRemoved( const firebase::database::DataSnapshot& snapshot) override { // Do something with the data in snapshot ... } void OnChildMoved(const firebase::database::DataSnapshot& snapshot, const char* previous_sibling) override { // Do something with the data in snapshot ... } void OnCancelled(const firebase::database::Error& error_code, const char* error_message) override { LogMessage("ERROR: SessionCommentsChildListener canceled: %d: %s", error_code, error_message); } }; // elsewhere .... SessionCommentsChildListener* listener = new SessionCommentsChildListener(); firebase::Future<firebase::database::DataSnapshot> result = dbRef.GetReference("GameSessionComments").AddChildListener(listener);
OnChildAdded 回呼通常用於擷取 Firebase 資料庫中的項目清單。系統會為每個現有子項呼叫一次 OnChildAdded 回呼,然後在每次有新子項新增至指定路徑時再次呼叫。事件監聽器會收到包含新子項資料的快照。
每當子節點遭到修改,系統就會呼叫 OnChildChanged 回呼。包括對子節點後代所做的任何修改。通常會與 OnChildAdded 和 OnChildRemoved 呼叫搭配使用,以回應項目清單的變更。傳遞至事件監聽器的快照包含子項的更新資料。
移除直接子項時,系統會觸發 OnChildRemoved 回呼。通常會與 OnChildAdded 和 OnChildChanged 回呼搭配使用。傳遞至回呼的快照包含已移除子項的資料。
每當更新導致子項重新排序,而觸發 OnChildChanged 呼叫時,系統就會觸發 OnChildMoved 回呼。適用於以 OrderByChild 或 OrderByValue 排序的資料。
排序及篩選資料
您可以使用 Realtime Database Query 類別,擷取依鍵、值或子項值排序的資料。您也可以將排序結果篩選為特定數量的結果,或是一組鍵或值。
排序資料
如要擷取排序後的資料,請先指定其中一種排序方法,決定結果的排序方式:
| 方法 | 用量 |
|---|---|
OrderByChild() |
依指定子項索引鍵的值排序結果。 |
OrderByKey()
| 依子項索引鍵排序結果。 |
OrderByValue() |
依子項值排序結果。 |
一次只能使用一種排序方法。在同一查詢中多次呼叫排序方法會擲回錯誤。
以下範例說明如何訂閱依分數排序的分數排行榜。
firebase::database::Query query = dbRef.GetReference("Leaders").OrderByChild("score"); // To get the resulting DataSnapshot either use query.GetValue() and poll the // future, or use query.AddValueListener() and register to handle the // OnValueChanged callback.
這會定義 firebase::Query,與 ValueListener 結合時,會將用戶端與資料庫中的排行榜同步,並依每個項目的分數排序。如要進一步瞭解如何有效率地建構資料,請參閱「建構資料庫」。
呼叫 OrderByChild() 方法時,會指定要用來排序結果的子項鍵。在這種情況下,系統會依據每個子項的 "score" 值排序結果。如要進一步瞭解其他資料類型的排序方式,請參閱「查詢資料的排序方式」。
篩選資料
如要篩選資料,您可以在建構查詢時,將任何限制或範圍方法與排序方法結合。
| 方法 | 用量 |
|---|---|
LimitToFirst() |
設定從已排序的清單結果開頭傳回的項目數量上限。 |
LimitToLast() |
設定從已排序結果清單結尾傳回的項目數量上限。 |
StartAt() |
根據所選排序方法,傳回大於或等於指定鍵或值的項目。 |
EndAt() |
根據所選排序方法,傳回小於或等於指定鍵或值的項目。 |
EqualTo() |
根據所選排序方法,傳回與指定鍵或值相等的項目。 |
與排序方法不同,您可以合併多個限制或範圍函式。舉例來說,您可以結合 StartAt() 和 EndAt() 方法,將結果限制在指定的值範圍內。
即使查詢只有一個相符項目,快照仍會是清單,只是其中只有一個項目。
限制結果數量
您可以使用 LimitToFirst() 和 LimitToLast() 方法,設定特定回呼要同步處理的子項數量上限。舉例來說,如果您使用 LimitToFirst() 將限制設為 100,一開始最多只會收到 100 個 OnChildAdded 回呼。如果 Firebase 資料庫中儲存的項目少於 100 個,系統會為每個項目觸發 OnChildAdded 回呼。
當項目變更時,您會收到進入查詢項目的 OnChildAdded 回呼,以及從查詢中刪除項目的 OnChildRemoved 回呼,因此總數會維持在 100。
舉例來說,下列程式碼會傳回排行榜的最高分數:
firebase::database::Query query = dbRef.GetReference("Leaders").OrderByChild("score").LimitToLast(1); // To get the resulting DataSnapshot either use query.GetValue() and poll the // future, or use query.AddValueListener() and register to handle the // OnValueChanged callback.
依鍵或值篩選
您可以使用 StartAt()、EndAt() 和 EqualTo(),為查詢選擇任意的起點、終點和等值點。這項功能可用於將資料分頁,或尋找子項具有特定值的項目。
查詢資料的排序方式
本節說明 Query 類別中各個排序方法的資料排序方式。
OrderByChild
使用 OrderByChild() 時,包含指定子項索引鍵的資料會依下列方式排序:
- 指定子項索引鍵的值為
null的子項會排在最前面。 - 接著是指定子鍵值為
false的子項。如果多個子項的值為false,系統會依鍵按字母順序排序。 - 接著是指定子鍵值為
true的子項。如果多個子項的值為true,則會依鍵的字母順序排序。 - 接著是具有數值的子項目,按照遞增順序排序。如果多個子項的指定子節點具有相同的數值,則會依鍵排序。
- 字串會排在數字後面,並依字母順序遞增排序。如果多個子項在指定子節點的值相同,則會依鍵的字典順序排列。
- 物件排在最後,並依鍵的字母順序遞增排序。
OrderByKey
使用 OrderByKey() 排序資料時,系統會依鍵值遞增傳回資料。
- 如果子項的鍵可剖析為 32 位元整數,則會優先顯示,並依遞增順序排序。
- 接著是鍵值為字串值的子項,按照字母順序遞增排序。
OrderByValue
使用 OrderByValue() 時,子項會依其值排序。排序條件與 OrderByChild() 相同,但使用的是節點的值,而非指定子項索引鍵的值。