取得資料庫參照
如要從資料庫讀取或寫入資料,您需要 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() 時,包含指定子項索引鍵的資料會依下列方式排序:
- 指定子項索引鍵的值為
null的子項會排在最前面。 - 接著是指定子鍵值為
false的子項。如果多個子項的值為false,系統會依鍵按字母順序排序。 - 接著是指定子鍵值為
true的子項。如果多個子項的值為true,則會依鍵的字母順序排序。 - 接著是具有數值的子項目,按照遞增順序排序。如果多個子項的指定子節點具有相同的數值,則會依鍵排序。
- 字串排在數字之後,並依字母順序遞增排序。如果多個子項在指定子節點的值相同,則會依鍵的字母順序排列。
- 物件排在最後,並依鍵的字母順序遞增排序。
orderByKey
使用 orderByKey() 排序資料時,系統會依鍵值遞增傳回資料。
- 如果子項的鍵可剖析為 32 位元整數,則會優先顯示,並依遞增順序排序。
- 接著是鍵值為字串值的子項,按照字典順序遞增排序。
orderByValue
使用 orderByValue() 時,子項會依其值排序。排序條件與 orderByChild() 相同,但會使用節點的值,而非指定子項索引鍵的值。
卸載事件監聽器
如要移除回呼,請在 Firebase 資料庫參照上呼叫 off() 方法。
如要移除單一事件監聽器,請將其做為參數傳遞至 off()。在不含引數的位置呼叫 off(),會移除該位置的所有事件監聽器。
在父項事件監聽器上呼叫 off(),並不會自動移除在其子節點上註冊的事件監聽器;您也必須在任何子項事件監聽器上呼叫 off(),才能移除回呼。