使用網路上的資料清單

取得資料庫參照

如要從資料庫讀取或寫入資料,您需要 firebase.database.Reference 的例項:

Web

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web

var database = firebase.database();

讀取及寫入清單

將資料附加至資料清單

使用 push() 方法,將資料附加至多用戶端應用程式中的清單。每次在指定的 Firebase 參照資料中新增子項時,push() 方法都會產生專屬索引鍵。只要為清單中的每個新元素使用這些自動產生的鍵,多個用戶端就能同時將子項新增至相同位置,而不會發生寫入衝突。push() 產生的專屬索引會以時間戳記為依據,因此系統會自動依時間順序排序清單項目。

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

您可以使用這些自動產生的鍵,簡化資料結構的平坦化作業。詳情請參閱資料分支示例

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

Web

import { getDatabase, ref, push, set } from "firebase/database";

// Create a new post reference with an auto-generated id
const db = getDatabase();
const postListRef = ref(db, 'posts');
const newPostRef = push(postListRef);
set(newPostRef, {
    // ...
});

Web

// Create a new post reference with an auto-generated id
var postListRef = firebase.database().ref('posts');
var newPostRef = postListRef.push();
newPostRef.set({
    // ...
});

監聽子項事件

子項事件會在特定作業發生時觸發,例如透過 push() 方法新增子項,或是透過 update() 方法更新子項。

事件 常見用途
child_added 擷取項目清單,或監聽項目清單的新增項目。系統會為每個現有子項觸發一次這項事件,然後每次在指定路徑中新增新子項時再次觸發。事件監聽器會傳遞含有新子項資料的快照。
child_changed 監聽清單中項目的變更。 每次修改子節點時,系統都會觸發這項事件。包括對子節點後代所做的任何修改。傳遞至事件監聽器的快照包含子項的更新資料。
child_removed 監聽清單中項目的移除作業。當移除直接子項時,系統會觸發這項事件。傳遞至回呼區塊的快照包含已移除子項的資料。
child_moved 監聽有序清單中項目順序的變更。 child_moved 事件一律會在 child_changed 事件之後發生,而這會導致商品的訂單發生變更 (依據目前的排序方式)。

這些事件都很實用,可用於監聽資料庫中特定節點的變更。舉例來說,社群網站的部落格應用程式可能會同時使用這些方法,監控貼文留言中的活動,如下所示:

Web

import { getDatabase, ref, onChildAdded, onChildChanged, onChildRemoved } from "firebase/database";

const db = getDatabase();
const commentsRef = ref(db, 'post-comments/' + postId);
onChildAdded(commentsRef, (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

onChildChanged(commentsRef, (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

onChildRemoved(commentsRef, (data) => {
  deleteComment(postElement, data.key);
});

Web

var commentsRef = firebase.database().ref('post-comments/' + postId);
commentsRef.on('child_added', (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_changed', (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_removed', (data) => {
  deleteComment(postElement, data.key);
});

監聽值事件

雖然建議您監聽子項事件來讀取資料清單,但在某些情況下,監聽清單參照的值事件也相當實用。

value 觀察器附加至資料清單,系統會將整個資料清單做為單一快照傳回,您可以循環處理該快照來存取個別子項。

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

Web

import { getDatabase, ref, onValue } from "firebase/database";

const db = getDatabase();
const dbRef = ref(db, '/a/b/c');

onValue(dbRef, (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    const childKey = childSnapshot.key;
    const childData = childSnapshot.val();
    // ...
  });
}, {
  onlyOnce: true
});

Web

ref.once('value', (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    var childKey = childSnapshot.key;
    var childData = childSnapshot.val();
    // ...
  });
});

如要擷取清單的所有子項,而非監聽其他子項新增事件,這類模式就很實用。

排序及篩選資料

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

排序資料

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

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

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

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

Web

import { getDatabase, ref, query, orderByChild } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const myUserId = auth.currentUser.uid;
const topUserPostsRef = query(ref(db, 'user-posts/' + myUserId), orderByChild('starCount'));

Web

var myUserId = firebase.auth().currentUser.uid;
var topUserPostsRef = firebase.database().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 鍵下的值排序清單元素。

Web

import { getDatabase, ref, query, orderByChild } from "firebase/database";

const db = getDatabase();
const mostViewedPosts = query(ref(db, 'posts'), orderByChild('metrics/views'));

Web

var mostViewedPosts = firebase.database().ref('posts').orderByChild('metrics/views');

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

篩選資料

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

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

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

限制結果數量

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

隨著項目變更,您會收到 child_added 事件 (針對進入查詢的項目) 和 child_removed 事件 (針對退出查詢的項目),這樣總數就會維持在 100。

以下範例說明如何定義查詢,以便擷取所有使用者最近 100 篇貼文的清單:

Web

import { getDatabase, ref, query, limitToLast } from "firebase/database";

const db = getDatabase();
const recentPostsRef = query(ref(db, 'posts'), limitToLast(100));

Web

var recentPostsRef = firebase.database().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(),才能移除回呼。

後續步驟