はじめに
前回はRealmにおけるモデルオブジェクトの作成方法とデータベースへの書き込み方法について説明しました。
第4回目となる今回は、クエリを使用してデータベースからデータを取得する方法について説明します。
過去記事は以下を参照ください。
環境
Xcode:9.4.1
Swift:4.1.2
Realm:3.7.4
前準備
以下のように、選手を表す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)
}
全データの取得
もっとも基本的なクエリは全データの取得です。
全データを取得する場合の書式は以下の通りです。
書式:全データの取得
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;
}
)
件数の取得
何件取得できたのかを知りたい場合は、countプロパティを使用します。
データ件数の取得例
// 取得件数の表示 print(results.count)
各レコードデータの参照
取得結果は配列になっていますので、「取得結果[インデックス].プロパティ」で参照することができます。
取得結果の1件目のデータを参照する例を以下に示します。
取得結果の1件目を参照する例
// 取得結果の1件目を表示
print("氏名 = \(results[0].name)")
print("身長 = \(results[0].height)")
print("体重 = \(results[0].weight)")
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引数以降には、クエリ文字列の中に埋め込んだ「%@」の数だけ、カンマで区切って値を指定します。
以降のコード例は、文字列によるクエリの方法を使用して説明をしていきます。
比較演算子
クエリ文字列で使用可能な比較演算子には以下のものがあります。
| 演算子 | 説明 | 例 |
|---|---|---|
| == | 等しい | プロパティ名 = 値 |
| < | 未満 | プロパティ名 < 値 |
| <= | 以下 | プロパティ名 <= 値 |
| > | より大きい | プロパティ名 > 値 |
| >= | 以上 | プロパティ名 >= 値 |
| != | 等しくない | プロパティ名 != 値 |
| 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}")
パターン検索演算子
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*'")
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'}")
論理演算子
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'")
クエリの連鎖
クエリは連鎖させることができます。
例えば、「身長が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'")
結果から最初の1件を取得する
複数件の結果から、最初の1件だけを取得したい場合は firstプロパティを使用します。
以下に使用例を示します。
最初の1件を取得する例
let results = realm.objects(Player.self).first
並べ替え
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)

コメント
[…] 4.クエリによるデータの取得 […]
すごく勉強になりました。
ありがとうございました!
[…] 下記URLの「5.filterによるクエリ」が参考になりました。 [Realm][Swift4対応 完全保存版] 4.クエリによるデータの取得 […]
[…] 「SWIFT LIFE」 […]
[…] Realmのデータを検索する方法はググればすぐ出てくると思いますが、こちらの記事は参考になるかと思います。今回修正する箇所はMainViewController.swiftのlongPressed()です!コードは下記です〜! […]