擷取資料

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

事前準備

使用即時資料庫前,您必須先完成以下事項:

  • 註冊 Unity 專案,並將其設定為使用 Firebase。

    • 如果您的 Unity 專案已使用 Firebase,表示該專案已完成註冊並設定 Firebase。

    • 如果您沒有 Unity 專案,可以下載範例應用程式

  • 在 Unity 專案中新增 Firebase Unity SDK (尤其是 FirebaseDatabase.unitypackage)。

請注意,將 Firebase 新增至 Unity 專案涉及到 Firebase 主控台和開放式 Unity 專案中的工作 (例如從主控台下載 Firebase 設定檔,再移至 Unity 專案)。

正在擷取資料

系統會擷取 Firebase 資料,方法有兩種:一次呼叫 GetValueAsync(),或是附加至 FirebaseDatabase 參照的事件。系統會針對資料的初始狀態呼叫一次事件監聽器,並在資料變更時再次呼叫。

取得 DatabaseReference

如要從資料庫讀取資料,您需要 DatabaseReference 的執行個體:

using Firebase;
using Firebase.Database;
using Firebase.Extensions.TaskExtension; // for ContinueWithOnMainThread

public class MyScript: MonoBehaviour {
  void Start() {
    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

讀取資料一次

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

    FirebaseDatabase.DefaultInstance
      .GetReference("Leaders")
      .GetValueAsync().ContinueWithOnMainThread(task => {
        if (task.IsFaulted) {
          // Handle the error...
        }
        else if (task.IsCompleted) {
          DataSnapshot snapshot = task.Result;
          // Do something with snapshot...
        }
      });

接聽事件

您可以新增事件監聽器來訂閱資料變更:

活動 一般用量
ValueChanged 讀取及監聽路徑完整內容的異動。
ChildAdded 擷取項目清單,或監聽附加項目清單。 建議搭配 ChildChangedChildRemoved 使用,監控清單變更。
ChildChanged 監聽清單中項目的變更。使用 ChildAddedChildRemoved 即可監控清單變更。
ChildRemoved 監聽已從清單中移除的項目。使用 ChildAddedChildChanged 即可監控清單變更。
ChildMoved 監聽已排序清單中項目順序的變更。 ChildMoved 事件一律會遵循導致項目順序變更的 ChildChanged 事件 (以目前的排序方式為準)。

ValueChanged 事件

您可以使用 ValueChanged 事件訂閱指定路徑的內容變更。您附加監聽器時,這個事件會觸發一次,且每當資料 (包括子項) 變更時,就會觸發這個事件。事件回呼會傳遞含有該位置所有資料的快照,包括子項資料。如果沒有資料,則傳回的快照為 null

以下範例是一個遊戲,示範如何從資料庫擷取排行榜的分數:

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

ValueChangedEventArgs 包含 DataSnapshot,其中包含事件發生時資料庫中指定的位置資料。對快照呼叫 Value 會傳回代表資料的 Dictionary<string, object>。如果位置沒有資料,呼叫 Value 會傳回 null

在這個範例中,也會檢查 args.DatabaseError,看看讀取作業是否已取消。舉例來說,如果用戶端權限不足,無法讀取 Firebase 資料庫位置,系統就會取消讀取作業。DatabaseError 會指出失敗的原因。

您之後可使用任何具有相同路徑的 DatabaseReference 取消訂閱事件。DatabaseReference 執行個體是暫時的,可視為存取任何路徑和查詢的方法。

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged -= HandleValueChanged; // unsubscribe from ValueChanged.
    }

子活動

如果作業發生在節點子項所發生的特定作業 (例如透過 Push() 方法新增的子項,或透過 UpdateChildrenAsync() 方法更新子項),就會觸發子項事件。這兩個組合都有助於監聽資料庫中特定節點的變更。舉例來說,遊戲可能同時使用下列方法,監控遊戲工作階段留言中的活動,如下所示:

      var ref = FirebaseDatabase.DefaultInstance
      .GetReference("GameSessionComments");

      ref.ChildAdded += HandleChildAdded;
      ref.ChildChanged += HandleChildChanged;
      ref.ChildRemoved += HandleChildRemoved;
      ref.ChildMoved += HandleChildMoved;
    }

    void HandleChildAdded(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildChanged(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildRemoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildMoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

ChildAdded 事件通常用於擷取 Firebase 資料庫中的項目清單。每個現有子項都會引發一次 ChildAdded 事件,之後每次將新子項新增至指定路徑時,就會再次觸發。事件監聽器傳遞了含有新子項資料的快照。

每當修改子節點時,就會引發 ChildChanged 事件。這也包括對子節點子系所做的任何修改。它通常會與 ChildAddedChildRemoved 事件搭配使用,以回應項目清單的變更。傳遞至事件監聽器的快照會包含子項的更新資料。

移除即時子項時,會觸發 ChildRemoved 事件。通常與 ChildAddedChildChanged 回呼搭配使用。傳遞至事件回呼的快照會包含已移除的子項資料。

每當更新引發 ChildChanged 事件,進而重新排序子項時,就會觸發 ChildMoved 事件。可與以 OrderByChildOrderByValue 排序的資料搭配使用。

排序及篩選資料

您可以使用即時資料庫 Query 類別,擷取依鍵、值或子項值排序的資料。您也可以篩選排序結果,以達到特定結果數量、鍵/值範圍。

排序資料

如要擷取經過排序的資料,請先指定一種依順序排序的方法來決定結果的排序方式:

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

一次只能使用「一個」排序方法。在同一查詢中多次呼叫依順序的方法呼叫會擲回錯誤。

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

這會定義一項查詢,與值變更事件監聽器搭配使用時,系統會依每個項目的分數排序用戶端與資料庫中的排行榜。如要進一步瞭解如何有效率地建構資料,請參閱建立資料庫結構

OrderByChild() 方法的呼叫會指定子項鍵,依結果排序結果。在這種情況下,結果會按照每個子項中的 "score" 值排序。如要進一步瞭解其他資料類型的排序方式,請參閱查詢資料的排序方式

篩選資料

如要篩選資料,您可以在建構查詢時,將任何限製或範圍方法與排序方法結合。

方式 用量
LimitToFirst() 設定要從已排序結果清單開頭傳回的項目數量上限。
LimitToLast() 設定從已排序結果清單結尾傳回的項目數量上限。
StartAt() 依據所選的順序,傳回大於或等於指定鍵或值的項目。
EndAt() 依據所選的順序,傳回小於或等於指定鍵或值的項目。
EqualTo() 根據所選順序,傳回與指定鍵或值相等的項目。

有別於依序執行排序的方式,您可以合併多個限製或範圍函式。舉例來說,您可以結合 StartAt()EndAt() 方法,將結果限制為指定範圍內的值。

即使查詢只有一個相符結果,快照仍為清單,只是只包含一個項目。

限制結果數量

您可以使用 LimitToFirst()LimitToLast() 方法,設定特定回呼要同步處理的子項數量上限。舉例來說,如果您使用 LimitToFirst() 將限制設為 100,一開始最多只會接收 100 個 ChildAdded 回呼。如果 Firebase 資料庫中儲存的項目少於 100 個,則每個項目都會觸發 ChildAdded 回呼。

當項目有變更時,您也會收到輸入查詢的項目 ChildAdded 回呼,而針對移出查詢的項目,您會收到 ChildRemoved 回呼,因此總數會維持在 100。

例如,以下程式碼會傳回排行榜的最高分:

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score").LimitToLast(1)
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

依鍵或值篩選

您可以使用 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() 相同,但會使用節點的值而非指定子項鍵的值。