使用 C++ 適用的 Firebase 即時資料庫擷取資料

本文將說明擷取資料的基本概念,以及如何排序和篩選 Firebase 資料。

事前準備

請確認您已設定應用程式,且可以存取資料庫,如 Get Started 指南所述。

正在擷取資料

您可以呼叫 GetValue() 一次,或附加至 FirebaseDatabase 參考資料的 ValueListener,即可擷取 Firebase 資料。值監聽器會針對資料的初始狀態呼叫一次,並且在資料變更時會再次呼叫。

取得 DatabaseReference

如要將資料寫入資料庫,您需要 DatabaseReference 的執行個體:

    // Get the root reference location of the database.
    firebase::database::DatabaseReference dbref = database->GetReference();

讀取資料一次

您可以使用 GetValue() 方法,讀取指定路徑內容的靜態快照一次。工作結果會包含快照,其中含有該位置的所有資料,包括子項資料。如果沒有資料,傳回的快照會是 null

  firebase::Future&ltfirebase::database::DataSnapshot&gt 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 擷取項目清單或聆聽項目清單的新增內容。 建議搭配 OnChildChangedOnChildRemoved 使用,監控清單的變更。
OnChildChanged 監聽清單中項目的變更。搭配 OnChildAddedOnChildRemoved 使用,即可監控清單的變更。
OnChildRemoved 監聽從清單中移除的項目。搭配 OnChildAddedOnChildChanged 使用,即可監控清單的變更。
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&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("Leaders").AddValueListener(listener);

Future&ltDataSnapshot&gt 結果包含事件發生時資料庫中指定位置的資料。對快照呼叫 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&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("GameSessionComments").AddChildListener(listener);

OnChildAdded 回呼通常用於擷取 Firebase 資料庫中的項目清單。系統會為每個現有子項呼叫一次 OnChildAdded 回呼,然後每當有新子項新增至指定路徑時,再次呼叫該回呼。系統會將含有新子項資料的快照傳遞給監聽器。

每當修改子節點時,系統就會呼叫 OnChildChanged 回呼。 包括對子節點後代的任何修改。通常會與 OnChildAddedOnChildRemoved 呼叫搭配使用,以回應項目清單的變更。傳遞至接聽程式的快照包含子項的更新資料。

移除直接子項時,系統會觸發 OnChildRemoved 回呼。 這通常會與 OnChildAddedOnChildChanged 回呼搭配使用。傳遞至回呼的快照包含已移除子項的資料。

每當更新導致子項重新排序時,系統就會觸發 OnChildMoved 回呼。OnChildChanged這項功能適用於以 OrderByChildOrderByValue 排序的資料。

排序及篩選資料

您可以使用 Realtime Database Query 類別,依鍵、值或子項的值擷取排序後的資料。您也可以將排序結果篩選為特定結果數,或是特定範圍的鍵或值。

排序資料

如要擷取排序後的資料,請先指定其中一個排序依據方法,決定結果的排序方式:

方法 用量
OrderByChild() 依指定子項鍵的值排序結果。
OrderByKey() 依子項鍵排序結果。
OrderByValue() 依子項值排序結果。

一次只能使用一種排序依據方法。在同一項查詢中多次呼叫 order-by 方法會擲回錯誤。

以下範例說明如何訂閱依分數排序的分數排行榜。

  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() 時,包含指定子項鍵的資料會依下列順序排序:

  1. 指定子項鍵的 null 值會優先顯示。
  2. 接著是指定子項鍵的值為 false 的子項。如果多個子項的值為 false,系統會依鍵依字母順序排序。
  3. 接著是指定子項鍵的值為 true 的子項。如果多個子項的值為 true,系統會依鍵的字典順序排序。
  4. 接著是數值,並以遞增順序排序。如果多個子項的指定子項節點具有相同的數值,系統會依鍵排序。
  5. 字串會排在數字後面,並依字典順序遞增排序。如果多個子項在指定的子項節點中具有相同的值,系統會依鍵的字典順序排序。
  6. 物件會排在最後,並依鍵以遞增順序按字母排序。

OrderByKey

使用 OrderByKey() 排序資料時,系統會依鍵值以遞增順序傳回資料。

  1. 如果子項的鍵可剖析為 32 位元整數,則會先顯示這些子項,並依遞增順序排序。
  2. 接著是金鑰為字串值的子項,並依字典順序遞增排序。

OrderByValue

使用 OrderByValue() 時,子項會依值排序。排序條件與 OrderByChild() 相同,但會使用節點的值,而不是指定子項鍵的值。

後續步驟