【Swift】Realmのデータ取得方法!where/filter/sortedメソッドの使い方
この記事からわかること
- Realm Swiftでデータを取得する方法
- Results<Element>構造体の使い方
- whereやfilter、sortedメソッドの使い方
- Query<Element>型とは?
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
Swiftに導入できるモバイルデータベースRealm
に保存しているデータを取得する方法をまとめていきます。
データベースからデータを取得する
まずはシンプルにデータベースに保存されたデータを取得してみます。
取得するにはobjects
メソッドの引数に取り出したいデータベースクラス名をクラス名.self
形式で記述します。これでそのテーブルに格納されているデータを全て取得することができます。
let realm = try! Realm()
let shopTable = realm.objects(Shop.self)
Results型
取得できるデータは配列や辞書型ではなく Realm独自のResults<Element>
型になります。その中に定義したテーブルクラスがコレクション形式で格納されています。
コレクション形式なので配列などと同じように要素番号(インデックス)を指定することで対象の値にアクセスすることもできます。
print(shopTable)
Results<Shop> <0x14df301a0> (
[0] Shop {
name = Chez Ame;
menu = Menu {
name = Chocolate;
price = 400;
};
}
)
データを取り出すタイミング
一度に全てのデータを取得することができますが、実際に読み込みに行くタイミングは対象のデータにアクセスされたタイミングとなっており読み込みを遅延(遅延ロード)させて高速化を図っているようです。
”Data is only read when objects and properties are accessed. This allows you to represent large sets of data in a performant way.”
”データは、オブジェクトとプロパティがアクセスされたときにのみ読み取られます。これにより、パフォーマンスの高い方法で大量のデータ セットを表すことができます。”
また取得したデータはコピーではなくテーブルのデータ本体なので変更が実際のテーブルデータにも影響します。
主キーを指定して取り出す
テーブルに主キーを設定していた場合はobject
メソッドのforPrimaryKey
に値を指定することで決め打ちで取得することができます。
let person = realm.object(ofType: Person.self, forPrimaryKey: 12345)
ここからはデータを取り出す際に使用できる機能を持ったAPIをまとめていきます。
filterメソッド
RealmCollection型のデータに対してフィルタリングをかけられるようにfilter
メソッドが用意されています。配列などに使うfilter
メソッドとは異なりRealmで定義されているメソッドです。配列などのfilter
メソッドはクロージャで条件を指定するのに対してこちらは引数にNSPredicateクエリという文字列で構築した式形式で条件を指定します。
let shopTable = realm.objects(Shop.self).filter("name == 'Chez Ame'")
@Persistedを付与しないと使えない?
そもそもRealmで保存しているデータはテーブル(クラス)定義の際に@Persisted(パーシスト)を付与しないと永続的に保存してくれません。
filterメソッドは Realmデータベースに保存されている値を見に行くよう?なので、@Persisted
(パーシスト)を付与していないプロパティを参照しようとすると以下のようなエラーが発生します。
"Invalid keypath 'share': Property 'share' not found in object of type 'Travel'"
テーブル定義
class Travel :Object,ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var id:ObjectId
@Persisted var name:String = "
@Persisted var persistedShare:Bool = true
var share:Bool = false
}
filterメソッド
let travelTable = realm.objects(Travel.self).filter("share == true")
whereメソッド
public func where(_ query: ((Query<Element>) -> Query<Element>)) -> Results<Element>
RealmCollection型の持つwhere
メソッドでも条件を絞ってデータを取得することが可能です。使用方法は先ほどよりSwiftっぽくクロージャーの中に条件を指定することができます。
if let result = shopTable.where({ $0.menu.price > 300 }).first {
print(result)
}
使用できる比較演算子など
- 等しい:==
- 等しくない:!=
- より大きい:<
- より小さい:>
- 以上:<=
- 未満:>=
- 範囲が含まれるか:.contains(_ range:)
- 値が含まれるか:.contains(_ element:)
- AND:&&
- OR:||
Query<Element>について
クロージャ内に指定できるのはQuery<Element>
となっており、データベースに問い合わせるクエリを構築する専用の型となっています。ここで指定した条件が内部的にNSPredicateクエリ置き換えられています。
なので例えばキャストしようとしたり、クロージャーで返す型を違う型にすると以下のようなエラーを吐いてしまいました。
Cannot convert value of type 'Bool' to closure result type 'Query<Bool>'
sortedメソッド
取得したResult<Element>インスタンスに対してsorted
メソッドを使用することでデータを並び替えることができます。sorted(byKeyPath:ascending:)
形式の場合は引数に対象となる項目名と昇順か降順を指定する真偽値を渡します。
let result = realm.objects(Shop.self).sorted(byKeyPath: "name", ascending: true)
print(result)
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。