使用 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]) {
                  // ...
                }
              }];

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

排序及篩選資料

您可以使用即時資料庫 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 後,系統不會自動移除在子節點上註冊的事件監聽器;您也必須追蹤這些參照,或追蹤這些參照,或用控制方式將其移除。

後續步驟