[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)

 

“[Realm][Swift4対応 完全保存版] 4.クエリによるデータの取得” への1件の返信

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください