使用資料清單

取得資料庫參照

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

DatabaseReference ref = FirebaseDatabase.instance.ref();

讀取和寫入清單

附加至資料清單

在多使用者應用程式中,使用 push() 方法將資料附加至清單。每當有新的子項新增至指定的 Firebase 參照時,push() 方法就會產生一組專屬金鑰。為清單中的每個新元素使用這些自動生成鍵,多個用戶端可以同時將子項新增至相同位置,而不會發生寫入衝突。push() 產生的不重複索引鍵是以時間戳記為基礎,因此清單項目會自動依時間順序排列。

您可以使用 push() 方法傳回的新資料參照,取得子項自動產生的索引鍵值,或為子項設定資料。push() 參照的 .key 屬性包含自動產生的金鑰。

您可以使用這些自動產生的鍵,簡化資料結構扁平化作業。詳情請參閱資料展開範例。

舉例來說,push() 可用於在社群應用程式的貼文清單中新增貼文:

DatabaseReference postListRef = FirebaseDatabase.instance.ref("posts");
DatabaseReference newPostRef = postListRef.push();
newPostRef.set({
  // ...
});

監聽子事件

子事件會因應節點子項發生的特定作業而觸發,例如透過 push() 方法新增子項,或透過 update() 方法更新子項。

事件 一般用途
onChildAdded 擷取項目清單,或監聽項目清單的新增內容。 系統會為每個現有子項觸發一次這個事件,然後在每次有新子項新增至指定路徑時再次觸發。監聽器會收到包含新子項資料的快照。
onChildChanged 監聽清單中項目的變更。 每當子節點遭到修改,就會觸發這個事件。包括對子節點後代所做的任何修改。傳遞至事件監聽器的快照包含子項的更新資料。
onChildRemoved 監聽從清單中移除的項目。移除直接子項時,系統會觸發這個事件。傳遞至回呼區塊的快照包含已移除子項的資料。
onChildMoved 監聽已排序的清單中項目順序的變更。onChildMoved 事件一律會接在導致項目順序變更 (根據目前的排序方法) 的 onChildChanged 事件之後。

這些方法可以搭配使用,監聽資料庫中特定節點的變更。舉例來說,社群網誌應用程式可能會同時使用這些方法,監控貼文留言中的活動,如下所示:

final commentsRef = FirebaseDatabase.instance.ref("post-comments/$postId");
commentsRef.onChildAdded.listen((event) {
  // A new comment has been added, so add it to the displayed list.
});
commentsRef.onChildChanged.listen((event) {
  // A comment has changed; use the key to determine if we are displaying this
  // comment and if so displayed the changed comment.
});
commentsRef.onChildRemoved.listen((event) {
  // A comment has been removed; use the key to determine if we are displaying
  // this comment and if so remove it.
});

監聽值事件

雖然建議透過監聽子事件來讀取資料清單,但在某些情況下,監聽清單參照的值事件也很有用。

將 value 監聽器附加至資料清單,會以單一快照的形式傳回整個資料清單,您可以透過迴圈存取個別子項。

即使查詢只有一個相符項目,快照仍會是清單,只是其中只有一個項目。如要存取項目,您必須對結果執行迴圈:

myTopPostsQuery.onValue.listen((event) {
  for (final child in event.snapshot.children) {
    // Handle the post.
  }
}, onError: (error) {
  // Error.
});

如果想在單一作業中擷取清單的所有子項,而不是監聽其他子項新增事件,這個模式就很有用。

排序及篩選資料

您可以使用 Query 類別,擷取依鍵、值或子項值排序的資料。您也可以篩選排序結果,只顯示特定數量的結果,或特定範圍的鍵或值。

排序資料

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

方法 用量
orderByChild() 依指定子項索引鍵或巢狀子項路徑的值排序結果。
orderByKey() 依子項索引鍵排序結果。
orderByValue() 依子項值排序結果。

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

以下範例說明如何擷取使用者的熱門貼文清單,並依星號數量排序:

final myUserId = FirebaseAuth.instance.currentUser?.uid;
final topUserPostsRef = FirebaseDatabase.instance
    .ref("user-posts/$myUserId")
    .orderByChild("starCount");

這會定義查詢,與子項事件監聽器結合時,會根據使用者 ID,將用戶端與資料庫路徑中的使用者貼文同步處理,並依每篇貼文獲得的星數排序。這種使用 ID 做為索引鍵的技術稱為資料展開,詳情請參閱「建構資料庫」。

呼叫 orderByChild() 方法時,會指定要用來排序結果的子項鍵。在這種情況下,貼文會依各自 "starCount" 子項的值排序。如果資料結構如下,查詢也可以依巢狀子項排序:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

在這種情況下,我們可以在 orderByChild() 呼叫中指定巢狀子項的相對路徑,依 metrics 鍵下的巢狀值排序清單元素。

final mostViewedPosts =
    FirebaseDatabase.instance.ref('posts').orderByChild('metrics/views');

如要進一步瞭解其他資料類型的排序方式,請參閱「查詢資料的排序方式」。

篩選資料

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

方法 用量
limitToFirst() 設定從已排序的清單結果開頭傳回的項目數量上限。
limitToLast() 設定從已排序結果清單結尾傳回的項目數量上限。
startAt() 根據所選排序方法,傳回大於或等於指定鍵或值的項目。
startAfter() 根據所選排序方法,傳回大於指定鍵或值的項目。
endAt() 根據所選排序方法,傳回小於或等於指定鍵或值的項目。
endBefore() 根據所選排序方法,傳回小於指定鍵或值的項目。
equalTo() 根據所選排序方法,傳回與指定鍵或值相等的項目。

與排序方法不同,您可以合併多個限制或範圍函式。舉例來說,您可以結合 startAt() 和 endAt() 方法,將結果限制在指定的值範圍內。

限制結果數量

您可以使用 limitToFirst() 和 limitToLast() 方法,設定特定事件要同步處理的子項數量上限。舉例來說,如果您使用 limitToFirst() 將限制設為 100,一開始最多只會收到 100 個 onChildAdded 事件。如果 Firebase 資料庫中儲存的項目少於 100 個,系統會為每個項目觸發 onChildAdded 事件。

當項目變更時,您會收到進入查詢的項目的 onChildAdded 事件,以及退出查詢的項目的 onChildRemoved 事件,因此總數會保持在 100。

以下範例說明範例網誌應用程式如何定義查詢,擷取所有使用者最近 100 則貼文的清單:

final recentPostsRef = FirebaseDatabase.instance.ref('posts').limitToLast(100);

這個範例只定義了查詢,如要實際同步處理資料,則必須附加事件監聽器。

依鍵或值篩選

您可以使用 startAt()、startAfter()、endAt()、endBefore() 和 equalTo(),為查詢選擇任意的起始、結束和等值點。這項功能可用於分頁資料,或尋找具有特定值的子項。

查詢資料的排序方式

本節說明 Query 類別中各個排序方法的資料排序方式。

orderByChild

使用 orderByChild() 時,包含指定子項索引鍵的資料會依下列方式排序:

  1. 指定子項索引鍵的值為 null 的子項會排在最前面。
  2. 接著是指定子鍵值為 false 的子項。如果多個子項的值為 false,系統會依鍵按字母順序排序。
  3. 接著是指定子鍵值為 true 的子項。如果多個子項的值為 true,則會依鍵的字母順序排序。
  4. 接著是具有數值的子項目,按照遞增順序排序。如果多個子項的指定子節點具有相同的數值,則會依鍵排序。
  5. 字串排在數字之後,並依字母順序遞增排序。如果多個子項在指定子節點的值相同,則會依鍵的字母順序排列。
  6. 物件排在最後,並依鍵的字母順序遞增排序。

orderByKey

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

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

orderByValue

使用 orderByValue() 時,子項會依其值排序。排序條件與 orderByChild() 相同,但會使用節點的值,而非指定子項索引鍵的值。

卸載事件監聽器

如要移除回呼,請在 Firebase 資料庫參照上呼叫 off() 方法。

如要移除單一事件監聽器,請將其做為參數傳遞至 off()。在不含引數的位置呼叫 off(),會移除該位置的所有事件監聽器。

在父項事件監聽器上呼叫 off(),並不會自動移除在其子節點上註冊的事件監聽器;您也必須在任何子項事件監聽器上呼叫 off(),才能移除回呼。

後續步驟