FIRDatabaseReference の取得
データベースでデータの読み書きを行うには、FIRDatabaseReference
のインスタンスが必要です。
Swift
var ref: DatabaseReference! ref = Database.database().reference()
Objective-C
@property (strong, nonatomic) FIRDatabaseReference *ref; self.ref = [[FIRDatabase database] reference];
リストの読み取りと書き込み
リストへのデータの追加
マルチユーザー アプリケーションでリストにデータを追加するには childByAutoId
メソッドを使用します。指定した Firebase 参照に新しい子が追加されるたびに、childByAutoId
メソッドは一意のキーを生成します。この自動生成されたキーをリスト内の新しい各要素に使用することで、書き込みの競合を伴わずに複数のクライアントが同時に子を同じ場所に追加できます。childByAutoId
によって生成される一意のキーはタイムスタンプに基づいているため、リストのアイテムは自動的に時系列で並べ替えられます。
childByAutoId
メソッドによって返された新しいデータを参照することで、子の自動生成されたキーの値を取得することも、子のデータを設定することもできます。childByAutoId
参照の getKey
を呼び出すと、自動生成されたキーが返されます。
この自動生成されたキーを使用すると、データ構造を平坦化しやすくなります。詳細については、データのファンアウトの例をご覧ください。
child イベントのリッスン
childByAutoId
メソッドによる新しい子の追加や、updateChildValues
メソッドによる子の更新など、ノードの子に対して発生した特定のオペレーションに応じて child イベントがトリガーされます。
イベントの種類 | 一般的な使用方法 |
---|---|
FIRDataEventTypeChildAdded |
アイテムのリストを取得します。また、アイテムのリストへの追加をリッスンします。このイベントは既存の子ごとに 1 回トリガーされます。さらに、指定されたパスに新しい子が追加されると、そのたびに再びトリガーされます。リスナーには、新しい子のデータを含んでいるスナップショットが渡されます。 |
FIRDataEventTypeChildChanged |
リスト内のアイテムに対する変更がないかリッスンします。子ノードが修正されるたびにこのイベントがトリガーされます。この変更には、子ノードの子孫に対する変更も含まれます。イベント リスナーに渡されるスナップショットには、子の更新済みデータが含まれています。 |
FIRDataEventTypeChildRemoved |
リストから削除されるアイテムがないかリッスンします。このイベントは直接の子が削除されるとトリガーされます。コールバック ブロックに渡されるスナップショットには、削除された子のデータが含まれています。 |
FIRDataEventTypeChildMoved |
並べ替えリストの項目順変更をリッスンします。このイベントは、更新により子の再並べ替えが発生するたびにトリガーされます。このイベントは queryOrderedByChild
または queryOrderedByValue によるデータの並べ替えで使用されます。 |
それぞれのイベントを組み合わせると、データベース内の特定のノードの変更内容をリッスンするうえで役立つことがあります。たとえば、ソーシャルブログ アプリでは、以下に示すようにこれらのメソッドを組み合わせて使用し、投稿のコメントでのアクティビティをモニタリングできます。
Swift
// 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
// 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]; }];
value イベントのリッスン
データのリストを読み取るための推奨される方法は child イベントのリッスンですが、リスト参照で value イベントをリッスンするのが有効な場合もあります。
データのリストに FIRDataEventTypeValue
オブザーバーをアタッチすると、データのリスト全体が単一の DataSnapshot として返されるため、これをループして個別の子にアクセスできます。
クエリで一致が 1 つしかない場合でも、スナップショットはリストになります(ただし、アイテムは 1 つしか含まれていません)。アイテムにアクセスするには、結果をループする必要があります。
Swift
_commentsRef.observe(.value) { snapshot in for child in snapshot.children { ... } }
Objective-C
[_commentsRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // Loop over children NSEnumerator *children = [snapshot children]; FIRDataSnapshot *child; while (child = [children nextObject]) { // ... } }];
このパターンは、child が追加された他のイベントをリッスンするのではなく、単一のオペレーションでリストのすべての子を取得する場合に便利です。
データの並べ替えとフィルタリング
Realtime Database FIRDatabaseQuery
クラスを使用すると、キー、値、または子の値で並べ替えられたデータを取得できます。また、並べ替えられた結果を、特定の件数またはある範囲のキーや値に限定するようフィルタリングできます。
データを並べ替える
並べ替えられたデータを取得するには、最初にいずれかの order-by メソッドを指定して、結果の並べ替え方法を決定します。
メソッド | 用途 |
---|---|
queryOrderedByKey
| 子キーで結果を並べ替えます。 |
queryOrderedByValue |
子の値によって結果を並べ替えます。 |
queryOrderedByChild |
指定した子キーまたはネストされた子のパスの値によって結果を並べ替えます。 |
同時に使用できる order-by メソッドは 1 つだけです。同じクエリで order-by メソッドを複数回呼び出すとエラーがスローされます。
次の例では、スターの数で並べ替えられたユーザーの上位の投稿のリストを取得する方法について示しています。
Swift
// My top posts by number of stars let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")
Objective-C
// My top posts by number of stars FIRDatabaseQuery *myTopPostsQuery = [[[self.ref child:@"user-posts"] child:[super getUid]] queryOrderedByChild:@"starCount"];
このクエリは、ユーザー ID に基づいてデータベース内のパスからユーザーの投稿を取得しています。ユーザー 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
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")
Objective-C
FIRDatabaseQuery *postsByMostPopular = [[ref child:@"posts"] queryOrderedByChild:@"metrics/views"];
他の種類のデータを並べ替える方法について詳しくは、クエリデータが並べ替えられる仕組みをご覧ください。
データのフィルタリング
データをフィルタリングするために、クエリの構築時に、制限メソッドまたは範囲メソッドのいずれかを order-by メソッドと組み合わせることができます。
メソッド | 用途 |
---|---|
queryLimitedToFirst |
並べ替えられた結果リストの先頭から返すアイテムの最大数を設定します。 |
queryLimitedToLast |
並べ替えられた結果リストの末尾から返すアイテムの最大数を設定します。 |
queryStartingAtValue |
選択した order-by メソッドに応じて、指定したキーまたは値以上のアイテムを返します。 |
queryStartingAfterValue |
選択した order-by メソッドに応じて、指定したキーまたは値より大きいアイテムを返します。 |
queryEndingAtValue |
選択した order-by メソッドに応じて、指定したキーまたは値以下のアイテムを返します。 |
queryEndingBeforeValue |
選択した order-by メソッドに応じて、指定したキーまたは値より小さいアイテムを返します。 |
queryEqualToValue |
選択した order-by メソッドに応じて、指定したキーまたは値に等しいアイテムを返します。 |
order-by メソッドとは異なり、複数の制限関数または範囲関数を組み合わせることができます。たとえば、queryStartingAtValue
メソッドと queryEndingAtValue
メソッドを組み合わせて、結果を特定の範囲の値に制限できます。
結果の個数を制限する
queryLimitedToFirst
メソッドと queryLimitedToLast
メソッドを使用して、特定のコールバックに対して同期する子の最大数を設定できます。たとえば、queryLimitedToFirst
を使用して上限 100 を設定した場合は、初期状態で最大 100 個の FIRDataEventTypeChildAdded
コールバックのみを受け取ります。Firebase データベースに保存されているアイテムが 100 個よりも少ない場合、それぞれのアイテムに対する FIRDataEventTypeChildAdded
コールバックが発生します。
アイテムの変更に応じて、クエリに加わったアイテムに対する FIRDataEventTypeChildAdded
コールバックと、クエリから外れたアイテムに対する FIRDataEventTypeChildRemoved
コールバックを受け取り、合計数が 100 に保たれます。
次の例は、サンプルのブログアプリで全ユーザーの最新 100 件の投稿のリストを取得する方法を示しています。
Swift
// 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
// 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
クラスのそれぞれの order-by メソッドでデータがどのように並べ替えられるのかを説明します。
queryOrderedByKey
queryOrderedByKey
を使用してデータを並べ替えると、キー名で昇順にデータが返されます。
- 32 ビット整数として解析できるキーを持つ子が最初に来ます。ただし、昇順に並べ替えられます。
- 文字列値をキーとして持つ子が次に来ます。ただし、辞書順で昇順に並べ替えられます。
queryOrderedByValue
queryOrderedByValue
を使用すると、子がその値で並べ替えられます。並べ替えの条件は、指定した子キーの値の代わりにノードの値が使用されるという点を除いて、queryOrderedByChild
の場合と同じです。
queryOrderedByChild
queryOrderedByChild
を使用すると、指定した子キーを含むデータは次のように並べ替えられます。
- 指定した子キーに
nil
値を持つ子が最初に来ます。 - 指定した子キーの値が
false
である子が次に来ます。複数の子が値false
を持つ場合、キーで辞書順に並べ替えられます。 - 指定した子キーの値が
true
である子が次に来ます。複数の子が値true
を持つ場合、キーで辞書順に並べ替えられます。 - 数値を持つ子が次に来ます。ただし、昇順に並べ替えられます。指定した子ノードに同じ数値を持つ複数の子がある場合、キーで並べ替えられます。
- 文字列は数値の後に来て、辞書順で昇順に並べ替えられます。指定した子ノードに同じ値を持つ複数の子がある場合、キーで辞書順に並べ替えられます。
- オブジェクトが最後に来て、キー名の辞書順で昇順に並べ替えられます。
リスナーのデタッチ
ViewController
から離れても、オブザーバーはデータの同期を自動的に停止するわけではありません。オブザーバーが適切に削除されないと、オブザーバーによってデータがローカルメモリに同期され続けます。イベント ハンドラのクロージャでキャプチャされたオブジェクトがすべて保持されるため、メモリリークが発生する恐れがあります。オブザーバーが不要になったときは、関連付けられている FIRDatabaseHandle
を removeObserverWithHandle
メソッドに渡してオブザーバーを削除してください。
参照にコールバック ブロックを追加すると、FIRDatabaseHandle
が返されます。これらのハンドルを使用して、コールバック ブロックを削除できます。
データベース参照に複数のリスナーが追加されている場合、イベントが発生したときにそれぞれのリスナーが呼び出されます。ある場所でのデータの同期を停止するには、removeAllObservers
メソッドを呼び出して、その場所のすべてのオブザーバーを削除する必要があります。
リスナーで removeObserverWithHandle
または removeAllObservers
を呼び出しても、その子ノードに登録されているリスナーは自動的に削除されません。これらの参照やハンドルも追跡して削除する必要があります。