使用 Apple 平台上的資料清單

取得 FIRDatabaseReference

如要從資料庫讀取或寫入資料,您需要 FIRDatabaseReference 的例項:

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

讀取及寫入清單

將資料附加至資料清單

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

您可以使用 childByAutoId 方法傳回的新資料參照,取得子項的自動產生鍵值,或為子項設定資料。在 childByAutoId 參照上呼叫 getKey 會傳回自動產生的金鑰。

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

監聽子項事件

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

事件類型 常見用途
FIRDataEventTypeChildAdded 擷取項目清單,或監聽項目清單的新增項目。系統會為每個現有子項觸發一次這項事件,然後每次在指定路徑中新增新子項時再次觸發。事件監聽器會傳遞含有新子項資料的快照。
FIRDataEventTypeChildChanged 監聽清單中項目的變更。每次修改子節點時,系統都會觸發這項事件。包括對子節點後代所做的任何修改。傳遞至事件監聽器的快照包含子項的更新資料。
FIRDataEventTypeChildRemoved 監聽清單中項目的移除作業。當移除直接子項時,系統會觸發這項事件。傳遞至回呼區塊的快照包含已移除子項的資料。
FIRDataEventTypeChildMoved 監聽有序清單中項目順序的變更。 每當更新導致子項重新排序時,系統就會觸發這項事件。可搭配以 queryOrderedByChild queryOrderedByValue 排序的資料使用。

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

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
// Listen for new comments in the Firebase database
commentsRef.observe(.childAdded, with: { (snapshot) -> Void in
  self.comments.append(snapshot)
  self.tableView.insertRows(
    at: [IndexPath(row: self.comments.count - 1, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})
// Listen for deleted comments in the Firebase database
commentsRef.observe(.childRemoved, with: { (snapshot) -> Void in
  let index = self.indexOfMessage(snapshot)
  self.comments.remove(at: index)
  self.tableView.deleteRows(
    at: [IndexPath(row: index, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
// Listen for new comments in the Firebase database
[_commentsRef
              observeEventType:FIRDataEventTypeChildAdded
              withBlock:^(FIRDataSnapshot *snapshot) {
                [self.comments addObject:snapshot];
                [self.tableView insertRowsAtIndexPaths:@[
                  [NSIndexPath indexPathForRow:self.comments.count - 1 inSection:kSectionComments]
                ]
                                      withRowAnimation:UITableViewRowAnimationAutomatic];
              }];
// Listen for deleted comments in the Firebase database
[_commentsRef
 observeEventType:FIRDataEventTypeChildRemoved
 withBlock:^(FIRDataSnapshot *snapshot) {
   int index = [self indexOfMessage:snapshot];
   [self.comments removeObjectAtIndex:index];
   [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:kSectionComments]]
                         withRowAnimation:UITableViewRowAnimationAutomatic];
 }];

監聽值事件

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

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

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

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
_commentsRef.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
[_commentsRef
              observeEventType:FIRDataEventTypeValue
              withBlock:^(FIRDataSnapshot *snapshot) {
                // Loop over children
                NSEnumerator *children = [snapshot children];
                FIRDataSnapshot *child;
                while (child = [children nextObject]) {
                  // ...
                }
              }];

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

排序及篩選資料

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

排序資料

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

方法 用量
queryOrderedByKey 依子項索引鍵排序結果。
queryOrderedByValue 依子項值排序結果。
queryOrderedByChild 依指定子項鍵或巢狀子項路徑的值排序結果。

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

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

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
// My top posts by number of stars
let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
// My top posts by number of stars
FIRDatabaseQuery *myTopPostsQuery = [[[self.ref child:@"user-posts"]
                                      child:[super getUid]]
                                     queryOrderedByChild:@"starCount"];

這項查詢會根據使用者 ID,從資料庫中的路徑擷取使用者的貼文,並依每則貼文收到的星號數排序。這種使用 ID 做為索引鍵的做法稱為資料扇形展開,您可以參閱「建立資料庫結構」一文,進一步瞭解這項做法。

queryOrderedByChild 方法的呼叫會指定要依據哪個子項鍵排序結果。在這個範例中,系統會依據每則貼文中的 "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",
  }
},

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

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
 
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
 
FIRDatabaseQuery *postsByMostPopular = [[ref child:@"posts"] queryOrderedByChild:@"metrics/views"];

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

篩選資料

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

方法 用量
queryLimitedToFirst 設定從排序結果清單開頭傳回的項目數量上限。
queryLimitedToLast 設定從排序結果清單結尾傳回的項目數量上限。
queryStartingAtValue 傳回大於或等於指定鍵或值的項目,具體取決於所選排序方法。
queryStartingAfterValue 傳回大於指定鍵或值的項目,具體取決於所選排序方法。
queryEndingAtValue 傳回小於或等於指定鍵或值的項目,具體取決於所選排序方式。
queryEndingBeforeValue 傳回小於指定鍵或值的項目,具體取決於所選排序方法。
queryEqualToValue 傳回等於指定鍵或值的項目,具體取決於所選排序方法。

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

限制結果數量

您可以使用 queryLimitedToFirstqueryLimitedToLast 方法,為特定回呼設定要同步的子項數量上限。舉例來說,如果您使用 queryLimitedToFirst 設定 100 的限制,則一開始只會收到最多 100 個 FIRDataEventTypeChildAdded 回呼。如果 Firebase 資料庫中儲存的項目少於 100 個,系統會針對每個項目觸發 FIRDataEventTypeChildAdded 回呼。

隨著項目變更,您會收到 FIRDataEventTypeChildAdded 回呼,針對進入查詢的項目,以及 FIRDataEventTypeChildRemoved 回呼,針對從查詢中移除的項目,這樣總數就會維持在 100。

以下範例說明部落格應用程式如何擷取所有使用者最近 100 篇貼文的清單:

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
let recentPostsQuery = (ref?.child("posts").queryLimited(toFirst: 100))!

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
FIRDatabaseQuery *recentPostsQuery = [[self.ref child:@"posts"] queryLimitedToFirst:100];

依鍵或值篩選

您可以使用 queryStartingAtValuequeryStartingAfterValuequeryEndingAtValuequeryEndingBeforeValuequeryEqualToValue 為查詢選擇任意起始、結束和等價點。這項功能可用於分頁資料,或找出具有特定值的子項項目。

查詢資料的排序方式

本節說明如何依據 FIRDatabaseQuery 類別中的各個排序方法排序資料。

queryOrderedByKey

使用 queryOrderedByKey 排序資料時,系統會依鍵值以遞增順序傳回資料。

  1. 可解析為 32 位元整數的鍵的子項會排在最前面,並以遞增順序排序。
  2. 接著是使用字串值做為鍵的子項,以字典順序遞增排序。

queryOrderedByValue

使用 queryOrderedByValue 時,子項會依值排序。排序條件與 queryOrderedByChild 相同,只是會使用節點的值,而非指定子項鍵的值。

queryOrderedByChild

使用 queryOrderedByChild 時,包含指定子鍵的資料會依下列順序排序:

  1. 針對指定子項鍵,具有 nil 值的子項會優先顯示。
  2. 接著是指定子項鍵的值為 false 的子項。如果有多個子項的值為 false,系統會依鍵值排序
  3. 接著是指定子項鍵的值為 true 的子項。如果有多個子項的值為 true,系統會依字典順序依鍵排序。
  4. 接著是具有數值的子項,以遞增順序排列。如果多個子項的數值與指定子項節點相同,系統會依鍵值排序。
  5. 字串會排在數字之後,並依字典順序遞增排列。如果多個子項的值與指定子節點相同,系統會依字典順序排序。
  6. 物件會列在最後,並依字母順序依鍵遞增排序。

卸離監聽器

當您離開 ViewController 時,觀察者不會自動停止同步處理資料。如果未妥善移除觀察器,觀察器會繼續將資料同步至本機記憶體,並保留事件處理常式結束時擷取的任何物件,這可能會導致記憶體耗盡。不再需要觀察器時,請將相關聯的 FIRDatabaseHandle 傳遞至 removeObserverWithHandle 方法,藉此移除觀察器。

將回呼區塊新增至參照時,系統會傳回 FIRDatabaseHandle。這些句柄可用來移除回呼區塊。

如果資料庫參照已新增多個事件監聽器,系統會在事件發生時呼叫每個事件監聽器。如要停止同步處理該位置的資料,您必須呼叫 removeAllObservers 方法,移除該位置的所有觀察器。

在事件監聽器上呼叫 removeObserverWithHandleremoveAllObservers 不會自動移除在子節點上註冊的事件監聽器;您也必須追蹤這些參照或句柄,才能將其移除。

後續步驟