取得 FIRDatabaseReference
如要從資料庫讀取或寫入資料,您需要 FIRDatabaseReference
的執行個體:
var ref: DatabaseReference! ref = Database.database().reference()
@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 排序的資料。
|
這些方法結合起來,可用於監聽資料庫中特定節點的變更。舉例來說,社群部落格應用程式可能會一併使用這些方法,監控貼文留言中的活動,如下所示:
// 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 ) })
// 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 傳回,您隨後可以逐一存取個別子項。
即使查詢只找到一個相符項目,快照仍會是清單,只是只包含一個項目。如要存取項目,您需要對結果進行迴圈:
_commentsRef.observe(.value) { snapshot in for child in snapshot.children { ... } }
[_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 |
依據指定子項鍵或巢狀子項路徑的值排序結果。 |
一次只能使用一種排序依據方法。在同一項查詢中多次呼叫 order-by 方法會擲回錯誤。
以下範例說明如何擷取使用者熱門貼文的清單,並依星等排序:
// My top posts by number of stars let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")
// 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
鍵下巢狀結構的值排序清單元素。
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")
FIRDatabaseQuery *postsByMostPopular = [[ref child:@"posts"] queryOrderedByChild:@"metrics/views"];
如要進一步瞭解其他資料類型的排序方式,請參閱查詢資料的排序方式。
篩選資料
如要篩選資料,建構查詢時,您可以將任何限制或範圍方法與排序方法合併。
方法 | 用量 |
---|---|
queryLimitedToFirst |
設定要從排序結果清單開頭傳回的項目數量上限。 |
queryLimitedToLast |
設定要從排序結果清單結尾傳回的項目數量上限。 |
queryStartingAtValue |
根據所選的排序依據方法,傳回大於或等於指定鍵或值的項目。 |
queryStartingAfterValue |
根據所選排序依據方法,傳回大於指定鍵或值的項目。 |
queryEndingAtValue |
根據所選的排序依據方法,傳回小於或等於指定鍵或值的項目。 |
queryEndingBeforeValue |
根據所選的排序依據方法,傳回小於指定鍵或值的項目。 |
queryEqualToValue |
根據所選的排序依據方法,傳回與指定鍵或值相等的項目。 |
與排序方法不同,您可以合併多個限制或範圍函式。
舉例來說,您可以結合 queryStartingAtValue
和 queryEndingAtValue
方法,將結果限制在指定的值範圍內。
限制結果數量
您可以使用 queryLimitedToFirst
和 queryLimitedToLast
方法,為指定的回呼設定要同步處理的子項數量上限。舉例來說,如果您使用 queryLimitedToFirst
將限制設為 100,一開始只會收到最多 100 個 FIRDataEventTypeChildAdded
回呼。如果 Firebase 資料庫中儲存的項目少於 100 個,系統會為每個項目觸發 FIRDataEventTypeChildAdded
回呼。
項目變更時,你會收到進入查詢的項目 FIRDataEventTypeChildAdded
回呼,以及退出查詢的項目 FIRDataEventTypeChildRemoved
回呼,因此總數會維持在 100。
以下範例示範範例部落格應用程式如何擷取所有使用者最近 100 則貼文的清單:
// Last 100 posts, these are automatically the 100 most recent // due to sorting by push() keys let recentPostsQuery = (ref?.child("posts").queryLimited(toFirst: 100))!
// Last 100 posts, these are automatically the 100 most recent // due to sorting by push() keys FIRDatabaseQuery *recentPostsQuery = [[self.ref child:@"posts"] queryLimitedToFirst:100];
依鍵或值篩選
您可以使用 queryStartingAtValue
、queryStartingAfterValue
、queryEndingAtValue
、queryEndingBeforeValue
和 queryEqualToValue
,為查詢選擇任意的開始、結束和等效點。這項功能可用於資料分頁,或尋找具有特定值的子項目的項目。
查詢資料的排序方式
本節說明 FIRDatabaseQuery
類別中各個排序依據方法如何排序資料。
queryOrderedByKey
使用 queryOrderedByKey
排序資料時,系統會依鍵值以遞增順序傳回資料。
- 如果子項的鍵可剖析為 32 位元整數,則會先顯示這些子項,並依遞增順序排序。
- 接著是金鑰為字串值的子項,並依字典順序遞增排序。
queryOrderedByValue
使用 queryOrderedByValue
時,子項會依值排序。排序條件與 queryOrderedByChild
相同,但會使用節點的值,而不是指定子項鍵的值。
queryOrderedByChild
使用 queryOrderedByChild
時,包含指定子項鍵的資料會依下列順序排序:
- 指定子項鍵的
nil
值會優先顯示。 - 接著是指定子項鍵的值為
false
的子項。如果多個子項的值為false
,系統會依鍵依字母順序排序。 - 接著是指定子項鍵的值為
true
的子項。如果多個子項的值為true
,系統會依鍵的字典順序排序。 - 接著是數值,並以遞增順序排序。如果多個子項的指定子項節點具有相同的數值,系統會依鍵排序。
- 字串會排在數字後面,並依字典順序遞增排序。如果多個子項在指定的子項節點中具有相同的值,系統會依鍵的字典順序排序。
- 物件會排在最後,並依鍵以遞增順序按字母排序。
卸離監聽器
離開 ViewController
後,觀察員不會自動停止同步資料。如果觀察器未正確移除,系統會繼續將資料同步至本機記憶體,並保留事件處理常式封閉中擷取的任何物件,這可能會導致記憶體洩漏。不再需要觀察器時,請將相關聯的 FIRDatabaseHandle
傳遞至 removeObserverWithHandle
方法,即可移除觀察器。
將回呼區塊新增至參照時,系統會傳回 FIRDatabaseHandle
。這些控制代碼可用來移除回呼區塊。
如果已將多個監聽器新增至資料庫參照,系統會在引發事件時呼叫每個監聽器。如要停止同步處理該位置的資料,您必須呼叫 removeAllObservers
方法,移除該位置的所有觀察者。
在監聽器上呼叫 removeObserverWithHandle
或 removeAllObservers
不會自動移除在子節點上註冊的監聽器,您也必須追蹤這些參照或控制代碼,才能移除監聽器。