【Swift】Realmのデータ取得方法!where/filter/sortedメソッドの使い方

この記事からわかること

  • Realm Swiftデータ取得する方法
  • Results<Element>構造体の使い方
  • wherefiltersortedメソッド使い方
  • 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.”

”データは、オブジェクトとプロパティがアクセスされたときにのみ読み取られます。これにより、パフォーマンスの高い方法で大量のデータ セットを表すことができます。”

引用:CRUD - Read - Swift SDK

また取得したデータはコピーではなくテーブルのデータ本体なので変更が実際のテーブルデータにも影響します。

主キーを指定して取り出す

テーブルに主キーを設定していた場合は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)
}

使用できる比較演算子など

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)

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index