Firebase Summit で発表されたすべての情報をご覧ください。Firebase を使用してアプリ開発を加速し、自信を持ってアプリを実行する方法を紹介しています。詳細

Appleプラットフォームでデータのリストを操作する

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

FIRDatabaseReference を取得する

データベースからデータを読み書きするには、 FIRDatabaseReferenceのインスタンスが必要です。

迅速

注:この 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メソッドを使用します。 childByAutoIdメソッドは、指定された Firebase 参照に新しい子が追加されるたびに一意のキーを生成します。リスト内の新しい要素ごとにこれらの自動生成されたキーを使用することにより、複数のクライアントが、書き込みの競合なしで同時に同じ場所に子を追加できます。 childByAutoIdによって生成される一意のキーはタイムスタンプに基づいているため、リスト アイテムは自動的に時系列順に並べられます。

childByAutoIdメソッドによって返された新しいデータへの参照を使用して、子の自動生成キーの値を取得したり、子のデータを設定したりできます。 childByAutoId参照でgetKeyを呼び出すと、自動生成されたキーが返されます。

これらの自動生成されたキーを使用して、データ構造のフラット化を簡素化できます。詳細については、データ ファンアウトのを参照してください。

子イベントをリッスンする

子イベントは、 childByAutoId updateChildValuesによって更新された子などの操作からノードの子に発生する特定の操作に応答してトリガーされます。

イベントタイプ典型的な使用法
FIRDataEventTypeChildAddedアイテムのリストを取得するか、アイテムのリストへの追加をリッスンします。このイベントは、既存の子ごとに 1 回トリガーされ、指定されたパスに新しい子が追加されるたびに再度トリガーされます。リスナーには、新しい子のデータを含むスナップショットが渡されます。
FIRDataEventTypeChildChangedリスト内の項目への変更をリッスンします。このイベントは、子ノードが変更されるたびにトリガーされます。これには、子ノードの子孫への変更が含まれます。イベント リスナーに渡されるスナップショットには、子の更新されたデータが含まれています。
FIRDataEventTypeChildRemovedリストから削除される項目をリッスンします。このイベントは、直接の子が削除されたときにトリガーされます。コールバック ブロックに渡されるスナップショットには、削除された子のデータが含まれています。
FIRDataEventTypeChildMoved順序付きリスト内のアイテムの順序の変更をリッスンします。このイベントは、更新によって子の並べ替えが発生するたびにトリガーされます。 queryOrderedByChildまたはqueryOrderedByValueによって並べ替えられたデータで使用されます。

これらはそれぞれ、データベース内の特定のノードへの変更をリッスンするのに役立ちます。たとえば、ソーシャル ブログ アプリでは、以下に示すように、これらのメソッドを一緒に使用して、投稿のコメント内のアクティビティを監視できます。

迅速

注:この 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 として返されます。これをループして個々の子にアクセスできます。

クエリに一致するものが 1 つしかない場合でも、スナップショットはリストのままです。単一のアイテムが含まれているだけです。アイテムにアクセスするには、結果をループする必要があります。

迅速

注:この 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]) {
                  // ...
                }
              }];

このパターンは、追加の子追加イベントをリッスンするのではなく、1 回の操作でリストのすべての子をフェッチする場合に役立ちます。

データのソートとフィルタリング

Realtime Database FIRDatabaseQueryクラスを使用して、キー、値、または子の値で並べ替えられたデータを取得できます。並べ替えられた結果を特定の数の結果またはキーまたは値の範囲にフィルター処理することもできます。

データの並べ替え

並べ替えられたデータを取得するには、次のいずれかの order-by メソッドを指定して、結果の並べ替え方法を決定することから始めます。

方法使用法
queryOrderedByKey結果を子キーで並べ替えます。
queryOrderedByValue結果を子の値で並べ替えます。
queryOrderedByChild指定された子キーまたはネストされた子パスの値で結果を並べ替えます。

一度に使用できる order-by メソッドは1 つだけです。同じクエリで order-by メソッドを複数回呼び出すと、エラーがスローされます。

次の例は、星の数で並べ替えられたユーザーのトップ投稿のリストを取得する方法を示しています。

迅速

注:この 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キーの下にネストされた値でリスト要素を並べ替えることができます。

迅速

注:この 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"];

他のデータ型の順序付けの詳細については、クエリ データの順序付け方法を参照してください。

データのフィルタリング

データをフィルター処理するには、クエリを作成するときに limit メソッドまたは range メソッドを order-by メソッドと組み合わせることができます。

方法使用法
queryLimitedToFirst結果の順序付きリストの先頭から返す項目の最大数を設定します。
queryLimitedToLast結果の順序付けられたリストの最後から返される項目の最大数を設定します。
queryStartingAtValue選択した order-by メソッドに応じて、指定されたキーまたは値以上のアイテムを返します。
queryStartingAfterValue選択した order-by メソッドに応じて、指定されたキーまたは値より大きいアイテムを返します。
queryEndingAtValue選択した order-by メソッドに応じて、指定されたキーまたは値以下のアイテムを返します。
queryEndingBeforeValue選択された order-by メソッドに応じて、指定されたキーまたは値より少ないアイテムを返します。
queryEqualToValue選択した order-by メソッドに応じて、指定されたキーまたは値に等しい項目を返します。

order-by メソッドとは異なり、複数の limit または range 関数を組み合わせることができます。たとえば、 queryStartingAtValueメソッドとqueryEndingAtValueメソッドを組み合わせて、結果を指定された範囲の値に制限できます。

結果の数を制限する

queryLimitedToLast queryLimitedToFirstを使用して、特定のコールバックで同期する子の最大数を設定できます。たとえば、 queryLimitedToFirstを使用して制限を 100 に設定した場合、最初は最大 100 のFIRDataEventTypeChildAddedコールバックしか受け取りません。 Firebase データベースに保存されているアイテムが 100 未満の場合、アイテムごとにFIRDataEventTypeChildAddedコールバックが発生します。

項目が変更されると、クエリに入る項目に対してFIRDataEventTypeChildAddedコールバックを受け取り、クエリから脱落する項目に対してFIRDataEventTypeChildRemovedコールバックを受け取り、合計数が 100 のままになるようにします。

次の例は、サンプル ブログ アプリがすべてのユーザーによる最新の 100 件の投稿のリストを取得する方法を示しています。

迅速

注:この 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];

キーまたは値でフィルタ

queryStartingAtValuequeryStartingAfterValuequeryEndingAtValuequeryEndingBeforeValue 、およびqueryEqualToValueを使用して、クエリの任意の開始点、終了点、および等価点を選択できます。これは、データのページ付けや、特定の値を持つ子を持つアイテムの検索に役立ちます。

クエリ データの順序付け方法

このセクションでは、 FIRDatabaseQueryクラスの各 order-by メソッドによってデータがどのように並べ替えられるかについて説明します。

queryOrderedByKey

queryOrderedByKeyを使用してデータを並べ替えると、データはキーの昇順で返されます。

  1. 32 ビット整数として解析できるキーを持つ子が最初に来て、昇順でソートされます。
  2. 次にキーとして文字列値を持つ子が来て、辞書式に昇順にソートされます。

queryOrderedByValue

queryOrderedByValueを使用すると、子はその値によって並べ替えられます。指定された子キーの値の代わりにノードの値が使用されることを除いて、順序付け基準はqueryOrderedByChildと同じです。

queryOrderedByChild

queryOrderedByChildを使用する場合、指定された子キーを含むデータは次のように並べられます。

  1. 指定された子キーの値がnilの子が最初に来ます。
  2. 指定された子キーの値がfalseの子が次に来ます。複数の子の値がfalseの場合、それらはキーによって辞書順にソートされます。
  3. 指定された子キーの値がtrueの子が次に来ます。複数の子の値がtrueの場合、それらは辞書式にキーでソートされます。
  4. 次に、数値を持つ子が昇順でソートされます。複数の子が指定された子ノードに対して同じ数値を持つ場合、それらはキーでソートされます。
  5. 文字列は数値の後に続き、辞書式に昇順にソートされます。指定された子ノードに対して複数の子が同じ値を持つ場合、それらはキーによって辞書順に並べられます。
  6. オブジェクトは最後に来て、キーの昇順で辞書式にソートされます。

リスナーを切り離す

ViewControllerを離れても、オブザーバーはデータの同期を自動的に停止しません。オブザーバーが適切に削除されない場合、オブザーバーは引き続きデータをローカル メモリに同期し、イベント ハンドラー クロージャーでキャプチャされたオブジェクトを保持します。これにより、メモリ リークが発生する可能性があります。オブザーバーが不要になったら、関連するFIRDatabaseHandleremoveObserverWithHandleメソッドに渡して削除します。

コールバック ブロックを参照に追加すると、 FIRDatabaseHandleが返されます。これらのハンドルを使用して、コールバック ブロックを削除できます。

複数のリスナーがデータベース参照に追加されている場合、イベントが発生すると各リスナーが呼び出されます。その場所でデータの同期を停止するには、 removeAllObserversメソッドを呼び出して、その場所にあるすべてのオブザーバーを削除する必要があります。

リスナーでremoveObserverWithHandleまたはremoveAllObserversを呼び出しても、その子ノードに登録されているリスナーは自動的に削除されません。それらを削除するには、それらの参照またはハンドルを追跡する必要もあります。

次のステップ