[Realm][Swift4対応 完全保存版] 4.クエリによるデータの取得

スポンサーリンク
スポンサーリンク

はじめに

前回はRealmにおけるモデルオブジェクトの作成方法とデータベースへの書き込み方法について説明しました。

第4回目となる今回は、クエリを使用してデータベースからデータを取得する方法について説明します。

過去記事は以下を参照ください。

スポンサーリンク

環境

Xcode:9.4.1
Swift:4.1.2
Realm:3.7.4

スポンサーリンク

目次

  1. 前準備
  2. 全データの取得
  3. 件数の取得
  4. 各レコードデータの参照
  5. filterによるクエリ
  6. 並べ替え

スポンサーリンク

1.前準備

以下のように、選手を表すPlayerに3件のデータがある前提で説明をします。

Player
name height weight
HIRO 163 60.5
CHIHIRO 175 58
SHUHRI 170 61.2

参考までに、上記のモデル定義とデータ登録用のコードを以下に示します。

/// 選手モデル
class Player: Object {
    // 選手名
    @objc dynamic var name : String = ""
    // 身長(単位:m)
    @objc dynamic var height : Double = 0.0
    // 体重(単位:kg)
    @objc dynamic var weight : Double = 0.0
}

// データ登録用コード例
// 1人目の選手
let player1 = Player()
player1.name = "HIRO"
player1.height = 163.0
player1.weight = 60.5

// 2人目の選手
let player2 = Player()
player2.name = "CHIHIRO"
player2.height = 175.0
player2.weight = 58.0

// 3人目の選手
let player3 = Player()
player3.name = "SHURI"
player3.height = 170.0
player3.weight = 61.2

// 上記で作成した3人の選手を格納するリストの作成
let players = List<Player>()
players.append(player1)
players.append(player2)
players.append(player3)

// Realmのインスタンスを生成する
let realm = try! Realm()

// 書き込みトランザクション内でデータを追加する
try! realm.write {
    realm.add(players)
}
スポンサーリンク

2.全データの取得

もっとも基本的なクエリは全データの取得です。

全データを取得する場合の書式は以下の通りです。

書式:全データの取得
let 結果格納用変数 = Realmインスタンス名.objects(モデルクラス名.self)

クエリを実行すると、Resultsクラスのインスタンスが返されます。クエリの結果はデータのコピーではないため、書き込みトランザクション内で変更すると、ディスク上のデータに反映されます。

Playerから全てのデータを取得する例を以下に示します。

全データを取得する例
// (1)Realmのインスタンスを生成する
let realm = try! Realm()

// (2)全データの取得
let results = realm.objects(Player.self)

// (3)取得データの確認
print(results)

上記の実行結果は以下のようになります。

実行結果:全データの取得
Results<Player> <0x7ffdaa611380> (
	[0] Player {
		name = HIRO;
		height = 163;
		weight = 60.5;
	},
	[1] Player {
		name = CHIHIRO;
		height = 175;
		weight = 58;
	},
	[2] Player {
		name = SHURI;
		height = 170;
		weight = 61.2;
	}
)
スポンサーリンク

3.件数の取得

何件取得できたのかを知りたい場合は、countプロパティを使用します。

データ件数の取得例
// 取得件数の表示
print(results.count)
スポンサーリンク

4.各レコードデータの参照

取得結果は配列になっていますので、「取得結果[インデックス].プロパティ」で参照することができます。

取得結果の1件目のデータを参照する例を以下に示します。

取得結果の1件目を参照する例
// 取得結果の1件目を表示
print("氏名 = \(results[0].name)")
print("身長 = \(results[0].height)")
print("体重 = \(results[0].weight)")
スポンサーリンク

5.filterによるクエリ

条件を指定したクエリを実行したい場合は filter メソッドを使用します。

filterメソッドはいくつかのオーバーライドがあります。代表的な書式を以下に示します。1つは文字列によるクエリ式を使用する方法、もう1つはNSPredicateクラスでクエリ式を作成して filterメソッドに渡す方法です。

filterメソッドの書式
// (1)文字列によるクエリ
var クエリ結果格納用変数 = realm.objects(モデルクラス名.self).filter("クエリ文字列")

// (2)NSPredicateクラスによるクエリ
let predicate = NSPredicate(format: "クエリ文字列", パラメータ1, ... パラメータn)
var クエリ結果格納用変数 = realm.objects(モデルクラス名.self).filter(predicate)

Playerモデルの nameプロパティが「HIRO」であるレコードを取得するクエリ例を以下に示します。

// 文字列によるクエリ
let results = realm.objects(Player.self).filter("name == 'HIRO'")

// NSPredicateクラスを使用したクエリ
let predicate = NSPredicate(format: "name == %@", "HIRO")
let results = realm.objects(Player.self).filter(predicate)

文字列によるクエリでは、「name = ‘HIRO’」という文字列を渡すことで、データを取得しています。

もう1つのNSPredicateによるクエリは、はじめにNSPredicateクラスを使用してfilterに渡す条件式を作成します。NSPredicateの第1引数にはクエリの文字列を指定するのですが、この文字列の中に 「%@」を埋め込むと、その部分は第2引数以降に指定した値で置換されます。「%@」はいくつでも使用することができます。また第2引数以降には、クエリ文字列の中に埋め込んだ「%@」の数だけ、カンマで区切って値を指定します。

以降のコード例は、文字列によるクエリの方法を使用して説明をしていきます。

5-1.比較演算子

クエリ文字列で使用可能な比較演算子には以下のものがあります。

演算子 説明
== 等しい プロパティ名 = 値
< 未満 プロパティ名 < 値
<= 以下 プロパティ名 <= 値
> より大きい プロパティ名 > 値
>= 以上 プロパティ名 >= 値
!= 等しくない プロパティ名 != 値
BETWEEN 最小値と最大値の間 プロパティ名 BETWEEN {最小値, 最大値}

上記で示した演算子の使用例を以下に示します。

比較演算子の使用例
// 「=」演算子 nameプロパティが'HIRO'と等しい
let results = realm.objects(Player.self).filter("name == 'HIRO'")

// 「<」演算子 heightプロパティが170未満
let results = realm.objects(Player.self).filter("height < 170")

// 「<=」演算子 heightプロパティが170以下
let results = realm.objects(Player.self).filter("height <= 170")

// 「>」演算子 heightプロパティが170より大きい
let results = realm.objects(Player.self).filter("height > 170")

// 「>=」演算子 heightプロパティが170以上
let results = realm.objects(Player.self).filter("height >= 170")

// 「!=」演算子 nameプロパティが'HIRO'以外
let results = realm.objects(Player.self).filter("name != 'HIRO'")

// 「BETWEEN」演算子 heightプロパティが165から175の間
let results = realm.objects(Player.self).filter("height BETWEEN {165, 175}")

5-2.パターン検索演算子

Realmでは、パターン検索を行うことも可能です。以下にパターン検索で使用できる演算子を示します。String型とData型のプロパティに対して使用可能です。

演算子 説明

BEGINSWITH

先頭が指定した文字で始まるデータを検索 プロパティ名 BEGINSWITH = 値
ENDSWITH 末尾が指定した文字で終わるデータを検索 プロパティ名 ENDSWITH  値
CONTAINS 指定した文字が含まれるデータを検索 プロパティ名 CONTAINS  値
LIKE LIKE検索 プロパティ名 like 値

※「?」と「*」をワイルドカード文字として使用可能。

「?」は1つの文字と一致、「*」は0以上の文字との一致を表す

以下に、パターン検索演算子の使用例を示します。

パターン検索演算子の使用例
// 「BEGINSWITH」演算子 先頭が「CH」で始まるデータを検索
let results = realm.objects(Player.self).filter("name BEGINSWITH 'CH'")

// 「ENDSWITH」演算子 末尾が「RO」で終わるデータを検索
let results = realm.objects(Player.self).filter("name ENDSWITH 'RO'")

// 「CONTAINS」演算子 「HI」を含むデータを検索
let results = realm.objects(Player.self).filter("name CONTAINS 'HI'")

// 「like」演算子 「任意の1文字 + 'IR' + 0個以上の文字」のデータを検索
let results = realm.objects(Player.self).filter("name LIKE '?IR*'")

5-3.IN句

RealmでもIN句を使用することが可能です。

演算子 説明

IN

指定して複数の値のいずれかと一致するデータを検索 プロパティ名 IN {値1, 値2, … 値n}

以下に、IN句の使用例を示します。

IN句の使用例
// 「IN句」 name が'HIRO', 'SHURI'のいずれかと一致するデータを取得
let results = realm.objects(Player.self).filter("name IN {'HIRO','SHURI'}")

5-4.論理演算子

Realmでも論理演算子を使用して、複合条件を指定したクエリを実行することができます。

以下に使用可能な論理演算子を示します。

演算子 説明

AND

指定した両方の式に合致するデータを検索します 条件式1 AND 条件式2
OR 指定した式のいずれかに合致するデータを検索します 条件式1 OR 条件式2
NOT 指定した式を否定するデータを検索します NOT 条件式

以下に、論理演算子の使用例を示します。

論理演算子の使用例
// 「AND」演算子 nameの末尾が'RO' かつ heightが165より大きい データを取得
let results = realm.objects(Player.self).filter("name ENDSWITH 'RO' AND height > 165")

// 「OR」演算子 nameの末尾が'RO' または heightが165より大きい データを取得
let results = realm.objects(Player.self).filter("name ENDSWITH 'RO' AND height > 160")

// 「NOT」演算子 nameの末尾が'RO' または heightが165より大きい データを取得
let results = realm.objects(Player.self).filter("NOT name ENDSWITH 'RO'")

5-5.クエリの連鎖

クエリは連鎖させることができます。

例えば、「身長が170以上」というクエリの後に、「名前に’HIRO’を含む」というクエリを連鎖して実行することができます。

filetrをメソッドチェーンで実行することも、複数行に分けて実行することもできます。

以下に使用例を示します。

クエリの連鎖例
// (1)メソッドチェーンによるクエリの実行
let results = realm.objects(Player.self).filter("height >= 170").filter("name CONTAINS 'HIRO'")

// (2)複数行でのクエリの実行
let results = realm.objects(Player.self).filter("height >= 170")
let results2 = results.filter("name CONTAINS 'HIRO'")

5-6.結果から最初の1件を取得する

複数件の結果から、最初の1件だけを取得したい場合は firstプロパティを使用します。

以下に使用例を示します。

最初の1件を取得する例
let results = realm.objects(Player.self).first

6.並べ替え

sortedメソッドを使用することで、取得結果を並べ替えることができます。

いくつかのオーバーロードメソッドがありますが、一番使用しやすいのは以下の書式です。

sortedメソッドの第1引数には並べ替えのキーとなるプロパティ名を、第2引数は昇順の場合はtrue、降順の場合はfalseを指定します。

let 結果格納用変数 = realm.objects(モデルクラス名.self).sorted(byKeyPath: "プロパティ", ascending: Bool値)

以下にsortedメソッドの使用例を示します。この例ではnameプロパティを降順で並べ替えて結果を取得します。

sortedメソッドの使用例

// nameプロパティを降順で並べ替えた結果を取得
let results = realm.objects(Player.self).sorted(byKeyPath: "name", ascending: false)

 

コメント

  1. […] 4.クエリによるデータの取得 […]

  2. test より:

    すごく勉強になりました。
    ありがとうございました!

タイトルとURLをコピーしました