使用網路上的資料清單

取得資料庫參照

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

網頁模組 API

import { getDatabase } from "firebase/database";

const database = getDatabase();

網路命名空間 API

var database = firebase.database();

讀取及寫入清單

附加至資料清單

使用 push() 方法,將資料附加至多使用者應用程式中的清單。每當在指定的 Firebase 參考資料中加入新子項時,push() 方法就會產生專屬金鑰。透過為清單中的每個新元素使用自動產生的金鑰,多個用戶端即可同時將子項新增至相同位置,而不會發生寫入衝突。push() 產生的唯一索引鍵會根據時間戳記,因此清單項目會自動依時間排序。

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

您可以使用這些自動產生的金鑰來簡化資料結構。詳情請參閱資料擴散傳遞範例

舉例來說,push() 可用來將新貼文新增至社交應用程式的貼文清單:

網頁模組 API

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, {
    // ...
});

網路命名空間 API

// 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 事件 (以目前的排序方式為準)。

這兩者都有助於監聽資料庫中特定節點的變更。舉例來說,社交網誌應用程式可以搭配使用下列方法,監控貼文留言中的活動,如下所示:

網頁模組 API

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);
});

網路命名空間 API

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 觀察器附加至資料清單後,整個資料清單會以單一快照的形式傳回,接著您可以循環顯示,存取個別子項。

即使查詢只有一個符合項目,快照仍是一個清單,它只會包含一個項目。如要存取該項目,您需要循環處理結果:

網頁模組 API

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
});

網路命名空間 API

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

如果您想在單一作業中擷取清單的所有子項,而不監聽其他子項新增事件,這種模式就能派上用場。

排序及篩選資料

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

排序資料

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

方式 用量
orderByChild() 按指定子項鍵或巢狀子路徑的值排序結果。
orderByKey() 按子項鍵排序結果。
orderByValue() 按照子項值排序結果。

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

以下範例說明如何擷取使用者最受歡迎的貼文清單 (依星級評等排序):

網頁模組 API

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'));

網路命名空間 API

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 鍵底下巢狀的值來排序清單元素。

網頁模組 API

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

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

網路命名空間 API

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 事件,而為了讓總數維持在 100,則從項目中排除為 child_removed 事件。

以下範例展示網誌應用程式如何定義查詢,以擷取所有使用者最新發布的 100 篇文章清單:

網頁模組 API

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

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

網路命名空間 API

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(),才能移除回呼。

後續步驟