Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

CRUD - 読み取り - Swift SDK

項目一覧

  • Realm からの読み取り
  • 読み取り特性
  • クエリ結果の制限
  • ページ分割
  • Realm オブジェクトの読み取り
  • このページの例について
  • プライマリキーによる特定のオブジェクトの検索
  • 特定の型のすべてのオブジェクトのクエリ
  • オブジェクト プロパティに基づいてクエリをフィルタリングする
  • オブジェクト ID プロパティでフィルタリング
  • 関係のクエリ
  • 逆関係のクエリ
  • 埋め込みオブジェクト プロパティに対するコレクションのクエリ
  • マップ プロパティのクエリ
  • MutableSet プロパティのクエリ
  • RealmValue プロパティの読み取りとクエリ
  • 地理空間データのクエリ
  • カスタム永続プロパティのクエリ
  • オブジェクトの非同期な読み取り
  • クエリ結果のソート
  • セクション クエリ結果
  • データを集計する
  • チェーン クエリ
  • クエリ クラスのプロジェクション

Realm からの読み取りは通常、次の手順で構成されます。

  • Realm から特定のタイプのすべてのオブジェクトを取得します。

  • 必要に応じて、結果をフィルタリングします。

  • オプションで、 は結果を並べ替えます。

  • あるいは、特定のタイプのすべてのオブジェクトを取得し、セクション に分割します。 通常の結果と同様に、セクションされた結果をフィルタリングおよびソートすることができます。

クエリ、フィルタリング、ソート操作は、結果または SessionedResults コレクションのいずれかを返します。 これらのコレクションはライブです。つまり、関連付けられたクエリの最新の結果が常に含まれています。

Realm での読み取りに関する 3 つの主要な特性に基づいてアプリのデータ アクセス パターンを設計すると、データをできるだけ効率的に読み取ることができます。

クエリへの結果はデータのコピーではありません。クエリの結果を変更すると、ディスク上のデータが直接変更されます。 このメモリ マッピングは、結果がライブであることも意味します。つまり、ディスクの現在の状態を常に反映します。

コレクションはライブ 」も参照してください。

Realm は、そのクエリの結果を実際に要求した場合にのみクエリを実行します。 この遅延評価により、大規模なデータセットや複雑なクエリを処理するための洗練された高性能なコードを書込むことができます。 中間状態を処理するために余計な作業を必要とせずに、複数のフィルターやソート操作を連鎖させることができます。

Realm のオブジェクトモデルの利点の 1 つは、Realm がオブジェクトのすべての関係を直接参照として自動的に保持することであるため、クエリの結果から関係のグラフを直接走査できることです。

直接参照(ポインター)を使用すると、参照を介して関連オブジェクトのプロパティに直接アクセスできます。

他のデータベースでは通常、オブジェクトを直接操作する必要がある場合、データベース ストレージからアプリケーション メモリにオブジェクトがコピーされます。 Because application objects contain direct references, you are left with a choice: copy the object referred to by each direct reference out of the database in case it's needed, or just copy the foreign key for each object and query for the object with that key if it's accessed. 参照されたオブジェクトをアプリケーション メモリにコピーすることを選択すると、アクセスされていないオブジェクトの多くのリソースを使用することができますが、外部キーのみをコピーすることを選択した場合は、参照されたオブジェクトの検索によってアプリケーションが遅くなる可能性があります。

Realm は、ゼロコピーのライブ オブジェクトを使用して、これをすべてバイパスします。 Realm オブジェクト アアクセスはメモリ マッピングを使用してデータベース ストレージを直接指すため、Realm 内のオブジェクトとアプリケーション メモリ内のクエリの結果を区別しません。 このため、どのクエリ結果からでも、Realm 全体にわたる直接参照を走査できます。

遅延評価の結果、Realm でクエリ結果を制限するために特別なメカニズムは必要ありません。 たとえば、クエリが数千のオブジェクトと一致するが、最初の 10 個のオブジェクトのみをロードする場合は、結果コレクションの最初の 10 個の要素のみにアクセスします。

遅延評価の代わりに、ページ区切りの一般的なタスクが非常に簡単になります。 たとえば、Realm 内の数千のオブジェクトに一致するクエリに関連付けられた結果コレクションがあるとします。 ページごとに 100 個のオブジェクトを表示します。 任意のページに進むには、ターゲット ページに対応するインデックスから、結果コレクションの要素にアクセスします。

このページの例では、次のモデルを使用します。

// DogToy.h
@interface DogToy : RLMObject
@property NSString *name;
@end
// Dog.h
@interface Dog : RLMObject
@property NSString *name;
@property int age;
@property NSString *color;
// To-one relationship
@property DogToy *favoriteToy;
@end
// Enable Dog for use in RLMArray
RLM_COLLECTION_TYPE(Dog)
// Person.h
// A person has a primary key ID, a collection of dogs, and can be a member of multiple clubs.
@interface Person : RLMObject
@property int _id;
@property NSString *name;
// To-many relationship - a person can have many dogs
@property RLMArray<Dog *><Dog> *dogs;
// Inverse relationship - a person can be a member of many clubs
@property (readonly) RLMLinkingObjects *clubs;
@end
RLM_COLLECTION_TYPE(Person)
// DogClub.h
@interface DogClub : RLMObject
@property NSString *name;
@property RLMArray<Person *><Person> *members;
@end
// Dog.m
@implementation Dog
@end
// DogToy.m
@implementation DogToy
@end
// Person.m
@implementation Person
// Define the primary key for the class
+ (NSString *)primaryKey {
return @"_id";
}
// Define the inverse relationship to dog clubs
+ (NSDictionary *)linkingObjectsProperties {
return @{
@"clubs": [RLMPropertyDescriptor descriptorWithClass:DogClub.class propertyName:@"members"],
};
}
@end
// DogClub.m
@implementation DogClub
@end
class DogToy: Object {
@Persisted var id: ObjectId
@Persisted var name = ""
}
class Dog: Object {
@Persisted var name = ""
@Persisted var age = 0
@Persisted var color = ""
@Persisted var currentCity = ""
@Persisted var citiesVisited: MutableSet<String>
@Persisted var companion: AnyRealmValue
// To-one relationship
@Persisted var favoriteToy: DogToy?
// Map of city name -> favorite park in that city
@Persisted var favoriteParksByCity: Map<String, String>
// Computed variable that is not persisted, but only
// used to section query results.
var firstLetter: String {
return name.first.map(String.init(_:)) ?? ""
}
}
class Person: Object {
@Persisted(primaryKey: true) var id = 0
@Persisted var name = ""
// To-many relationship - a person can have many dogs
@Persisted var dogs: List<Dog>
// Inverse relationship - a person can be a member of many clubs
@Persisted(originProperty: "members") var clubs: LinkingObjects<DogClub>
// Embed a single object.
// Embedded object properties must be marked optional.
@Persisted var address: Address?
convenience init(name: String, address: Address) {
self.init()
self.name = name
self.address = address
}
}
class DogClub: Object {
@Persisted var name = ""
@Persisted var members: List<Person>
// DogClub has an array of regional office addresses.
// These are embedded objects.
@Persisted var regionalOfficeAddresses: List<Address>
convenience init(name: String, addresses: [Address]) {
self.init()
self.name = name
self.regionalOfficeAddresses.append(objectsIn: addresses)
}
}
class Address: EmbeddedObject {
@Persisted var street: String?
@Persisted var city: String?
@Persisted var country: String?
@Persisted var postalCode: String?
}

特定のオブジェクトのプライマリキーがわかっている場合は、 +[RLObjectForPrimaryKey:] を使用して直接検索できます。

// Get a specific person from the default realm
Person *specificPerson = [Person objectForPrimaryKey:@12345];

特定のオブジェクトのプライマリキーがわかっている場合は、 Realm.object(OfType:forPrimaryKey:) を使用して直接検索できます。

let realm = try! Realm()
let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345)

Realm 内の特定のタイプのオブジェクトをクエリするには、Realm インスタンスを+[ YourRealmObjectClass allObjectsInRealm:]に渡します。 YourRealmObjectClassを Realm オブジェクト クラス名に置き換えます。 これにより、Realm 内の指定された型のすべてのオブジェクトを表すRMResultsオブジェクトが返されます。

RLMRealm *realm = [RLMRealm defaultRealm];
RLMResults *dogs = [Dog allObjectsInRealm:realm];
RLMResults *people = [Person allObjectsInRealm:realm];

Realm 内の特定の型のオブジェクトをクエリするには、メタタイプ インスタンスYourClassName.selfRealm.objects(_:)に渡します。 これにより、Realm 内の指定された型のすべてのオブジェクトを表す結果オブジェクトが返されます。

let realm = try! Realm()
// Access all dogs in the realm
let dogs = realm.objects(Dog.self)

フィルターは、1 つ以上のオブジェクト プロパティの値に基づいて結果のサブセットを選択します。 Realm は、フィルターの定義に使用できるフル機能のクエリ エンジンを提供します。

バージョン 10.19.0 の新機能

Realm Swift Query APIを使用するには、 .where クエリ式を引数として含む 閉じる 。

let realm = try! Realm()
// Access all dogs in the realm
let dogs = realm.objects(Dog.self)
// Query by age
let puppies = dogs.where {
$0.age < 2
}
// Query by person
let dogsWithoutFavoriteToy = dogs.where {
$0.favoriteToy == nil
}
// Query by person's name
let dogsWhoLikeTennisBalls = dogs.where {
$0.favoriteToy.name == "Tennis ball"
}

フィルタリングするには、クエリ述語を指定してResult.filter(_:)を呼び出します。

let realm = try! Realm()
// Access all dogs in the realm
let dogs = realm.objects(Dog.self)
// Filter by age
let puppies = dogs.filter("age < 2")
// Filter by person
let dogsWithoutFavoriteToy = dogs.filter("favoriteToy == nil")
// Filter by person's name
let dogsWhoLikeTennisBalls = dogs.filter("favoriteToy.name == 'Tennis ball'")

フィルタリングするには、クエリ述語を使用して-[RMResults objectsWwhere:]を呼び出します。

RLMRealm *realm = [RLMRealm defaultRealm];
// Access all dogs in the realm
RLMResults *dogs = [Dog allObjectsInRealm:realm];
// Filter by age
RLMResults *puppies = [dogs objectsWhere:@"age < 2"];
// Filter by favorite toy
RLMResults *dogsWithoutFavoriteToy = [dogs objectsWhere:@"favoriteToy == nil"];
// Filter by favorite toy's name
RLMResults *dogsWhoLikeTennisBalls = [dogs objectsWhere:@"favoriteToy.name == %@", @"Tennis ball"];

Tip

関連プロパティと埋め込みオブジェクト プロパティでフィルタリング

埋め込みオブジェクトまたは関連オブジェクトのプロパティに基づいてクエリをフィルタリングするには、通常のネストされたオブジェクトと同様に ドット表記 を使用します。

述語内の型は、プロパティの型と一致する必要があります。 Realm は string を ObjectId に自動的に変換しないため、 ObjectIdプロパティを string と比較しないでください。

バージョン 10.19.0 の新機能

Realm Swift Query API に組み込まれている型の安全性により、 ObjectId を使用したクエリの作成が簡素化されます。

let realm = try! Realm()
let dogToys = realm.objects(DogToy.self)
// Get specific user by ObjectId id
let specificToy = dogToys.where {
$0.id == ObjectId("11223344556677889900aabb")
}

次の例えは、次の Realm オブジェクトで ObjectId を使用してクエリを作成する方法と正しくない方法を示しています。

let realm = try! Realm()
let dogToys = realm.objects(DogToy.self)
// Get specific toy by ObjectId id
let specificToy = dogToys.filter("id = %@", ObjectId("11223344556677889900aabb")).first
// WRONG: Realm will not convert the string to an object id
// users.filter("id = '11223344556677889900aabb'") // not ok
// users.filter("id = %@", "11223344556677889900aabb") // not ok

通常の Swift または Objective-C オブジェクトのメンバーにアクセスするのと同じ方法で、関係を介してクエリを実行できます。

RLMRealm *realm = [RLMRealm defaultRealm];
// Establish a relationship
Dog *dog = [[Dog alloc] init];
dog.name = @"Rex";
dog.age = 10;
Person *person = [[Person alloc] init];
person._id = 12345;
[person.dogs addObject:dog];
[realm transactionWithBlock:^() {
[realm addObject:person];
}];
// Later, query the specific person
Person *specificPerson = [Person objectForPrimaryKey:@12345];
// Access directly through a relationship
NSLog(@"# dogs: %lu", [specificPerson.dogs count]);
NSLog(@"First dog's name: %@", specificPerson.dogs[0].name);
let realm = try! Realm()
// Establish a relationship
let dog = Dog()
dog.name = "Rex"
dog.age = 10
let person = Person()
person.id = 12345
person.dogs.append(dog)
try! realm.write {
realm.add(person)
}
// Later, query the specific person
let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345)
// Access directly through a relationship
let specificPersonDogs = specificPerson!.dogs
let firstDog = specificPersonDogs[0]
print("# dogs: \(specificPersonDogs.count)")
print("First dog's name: \(firstDog.name)")

通常の Swift または Objective-C オブジェクトのメンバーにアクセスするのと同じ方法で、逆関係を介してクエリを実行できます。

RLMRealm *realm = [RLMRealm defaultRealm];
// Establish a relationship
Person *person = [[Person alloc] init];
person._id = 12345;
DogClub *club = [[DogClub alloc] init];
club.name = @"Pooch Pals";
[club.members addObject:person];
[realm transactionWithBlock:^() {
[realm addObject:club];
}];
// Later, query the specific person
Person *specificPerson = [Person objectForPrimaryKey:@12345];
// Access directly through an inverse relationship
NSLog(@"# memberships: %lu", [specificPerson.clubs count]);
NSLog(@"First club's name: %@", [specificPerson.clubs[0] name]);
let realm = try! Realm()
// Establish an inverse relationship
let person = Person()
person.id = 12345
let club = DogClub()
club.name = "Pooch Pals"
club.members.append(person)
try! realm.write {
realm.add(club)
}
// Later, query the specific person
let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345)
// Access directly through an inverse relationship
let clubs = specificPerson!.clubs
let firstClub = clubs[0]
print("# memberships: \(clubs.count)")
print("First club's name: \(firstClub.name)")

ドット表記 を使用して、埋め込みオブジェクト プロパティ値に基づいてオブジェクトのコレクションをフィルタリングまたはソートする:

注意

埋め込みオブジェクトを直接クエリすることはできません。 代わりに、親オブジェクトタイプに対するクエリを介して埋め込みオブジェクトにアクセスします。

バージョン 10.19.0 の新機能

// Open the default realm
let realm = try! Realm()
// Get all contacts in Los Angeles, sorted by street address
let losAngelesPeople = realm.objects(Person.self)
.where {
$0.address.city == "Los Angeles"
}
.sorted(byKeyPath: "address.street")
print("Los Angeles Person: \(losAngelesPeople)")
// Open the default realm
let realm = try! Realm()
// Get all people in Los Angeles, sorted by street address
let losAngelesPeople = realm.objects(Person.self)
.filter("address.city = %@", "Los Angeles")
.sorted(byKeyPath: "address.street")
print("Los Angeles Person: \(losAngelesPeople)")
RLMRealm *realm = [RLMRealm defaultRealm];
RLMResults<Contact *> *losAngelesContacts = [Contact objectsInRealm:realm where:@"address.city = %@", @"Los Angeles"];
losAngelesContacts = [losAngelesContacts sortedResultsUsingKeyPath:@"address.street" ascending:YES];
NSLog(@"Los Angeles Contacts: %@", losAngelesContacts);

邦土 マップ の値を、標準の 辞書 と同様に反復処理して確認できます。

let realm = try! Realm()
let dogs = realm.objects(Dog.self)
// Find dogs who have favorite parks
let dogsWithFavoriteParks = dogs.where {
$0.favoriteParksByCity.count >= 1
}
for dog in dogsWithFavoriteParks {
// Check if an entry exists
if dog.favoriteParksByCity.keys.contains("Chicago") {
print("\(dog.name) has a favorite park in Chicago")
}
// Iterate over entries
for element in dog.favoriteParksByCity {
print("\(dog.name)'s favorite park in \(element.key) is \(element.value)")
}
}

MutableSetをクエリして、要素が含まれているかどうかを確認できます。 複数のセットを操作している場合は、2 つのセットの共通部分を確認したり、一方のセットが他方のセットのサブセットであるかどうかを確認できます。

let realm = try! Realm()
// Find dogs who have visited New York
let newYorkDogs = realm.objects(Dog.self).where {
$0.citiesVisited.contains("New York")
}
// Get some information about the cities they have visited
for dog in newYorkDogs {
print("Cities \(dog.name) has visited: \(dog.citiesVisited)")
}
// Check whether two dogs have visited some of the same cities.
// Use "intersects" to find out whether the values of the two sets share common elements.
let isInBothCitiesVisited = (dog.citiesVisited.intersects(dog2.citiesVisited))
print("The two dogs have visited some of the same cities: \(isInBothCitiesVisited)")
// Prints "The two dogs have visited some of the same cities: true"
// Or you can check whether a set is a subset of another set. In this example,
// the first dog has visited "New York" and "Toronto", while dog2 has visited both of
// those but also "Toronto" and "Boston".
let isSubset = (dog.citiesVisited.isSubset(of: dog2.citiesVisited))
print("\(dog.name)'s set of cities visited is a subset of \(dog2.name)'s: \(isSubset)")
// Prints "Maui's set of cities visited is a subset of Lita's: true"

AnyRealmValue プロパティを読み取る場合は、その値を操作する前にその値の型を確認します。 Realm Swift SDK は、AnyRealmValue が保存できるすべてのタイプを反復処理するAnyRealmValue 列挙型を提供します。

let realm = try! Realm()
let dogs = realm.objects(Dog.self)
for dog in dogs {
// Verify the type of the ``AnyRealmProperty`` when attempting to get it. This
// returns an object whose property contains the matched type.
// If you only care about one type, check for that type.
if case let .string(companion) = dog.companion {
print("\(dog.name)'s companion is: \(companion)")
// Prints "Wolfie's companion is: Fluffy the Cat"
}
// Or if you want to do something with multiple types of data
// that could be in the value, switch on the type.
switch dog.companion {
case .string:
print("\(dog.name)'s companion is: \(dog.companion)")
// Prints "Wolfie's companion is: string("Fluffy the Cat")
case .object:
print("\(dog.name)'s companion is: \(dog.companion)")
// Prints "Fido's companion is: object(Dog { name = Spot })"
case .none:
print("\(dog.name) has no companion")
// Prints "Rex has no companion" and "Spot has no companion"
default:
print("\(dog.name)'s companion is another type.")
}
}

これらの混合値の型を比較できます。

  • 数値: int、bool、float、double、decimal

  • バイトベース: string、binary

  • 時間ベース: タイムスタンプ、 ObjectId

AnyRealmValue混合データ型を使用する場合は、次の点に注意してください。

  • equals 値と型に一致するクエリ

  • not equals クエリが、異なる値または異なる型を持つオブジェクトと一致する

  • Realm は、可能な場合は同等の数値プロパティを変換します。 たとえば、混合型フィールドでは、1 は 1.0、1、true のすべてと一致します。

  • string プロパティは数値クエリと一致しません。 たとえば、混合型フィールドでは、1 は "1" と一致しません。 "1" は 1、1.0、または true には一致しません。

バージョン 10.47.0 の新機能

Swift SDK は地理空間データのクエリを簡素化するためのいくつかのシェイプを提供します。 地理空間データ クエリの境界を設定するには、 GeoCircleGeoBoxGeoPolygonのシェイプを使用できます。

SDK は、形状を定義するための 2 つの専用非永続データ型を提供します。

  • GeoPoint: これらの値で構成される double のペアによって作成される点の座標を表す構造体。

    • 緯度: -90 から 90 度の範囲。

    • 経度: -180 から 180 度の範囲。

  • RLMDistance: 距離を表現して変換するヘルパー構造体。

GeoCircleは、その境界が中心GeoPointから始まり、ラジアンで測定された半径に対応するサイズを持つ円形の形状です。 SDK の便利なRLMDistanceデータ型を使用して、さまざまな単位のラジアンを簡単に操作できます。

RLMDistance を使用すると、地理的形状の半径距離を 4 つの単位のいずれかで指定できます。

  • .degrees

  • .kilometers

  • .miles

  • .radians

オプションで、提供されている便宜的メソッドを使用して、測定値を別の距離単位に変換できます。

// You can create a GeoCircle radius measured in radians.
// This radian distance corresponds with 0.25 degrees.
let smallCircle = GeoCircle(center: (47.3, -121.9), radiusInRadians: 0.004363323)
// You can also create a GeoCircle radius measured with a Distance.
// You can specify a Distance in .degrees, .kilometers, .miles, or .radians.
let largeCircle = GeoCircle(center: GeoPoint(latitude: 47.8, longitude: -122.6)!, radius: Distance.kilometers(44.4)!)
2 つの地理的円
クリックして拡大します

GeoBoxは、左下と右上の隅の座標によって境界が決定される直列型です。

let largeBox = GeoBox(bottomLeft: (47.3, -122.7), topRight: (48.1, -122.1))
let smallBoxBottomLeft = GeoPoint(latitude: 47.5, longitude: -122.4)!
let smallBoxTopRight = GeoPoint(latitude: 47.9, longitude: -121.8)
let smallBox = GeoBox(bottomLeft: smallBoxBottomLeft, topRight: smallBoxTopRight!)
2 ジオボックス
クリックして拡大します

GeoPolygonは、地理空間クエリから除外する外側の円と0以上の内側の穴で境界が構成される多角形の形状です。

多角形の外側の円には少なくとも 3 つのセグメントが含まれている必要があります。 最後の GeoPoint と最初のは同じである必要があり、これは閉じた多角形であることを示します。 つまり、多角形を構築するには少なくとも 4 つのGeoPoint値が必要です。

GeoPolygon内の穴は完全に外側の円内に収まっている必要があります。

穴には次の制限があります。

  • 穴は交差できません。 穴の境界は、他の穴の内側と外側の両方と交差することはできません。

  • 穴はエッジを共有しない場合があります。 埋め込みにエッジ AB が含まれている場合、他の埋め込みにはそれが含まれることはありません。

  • 穴はサイズを共有する場合があります。 ただし、どのバーテックスも 1 つの埋め込みに 2 回表示されることはありません。

  • 空の穴はありません。

  • ネストは 1 つのみです。

// Create a basic polygon
let basicPolygon = GeoPolygon(outerRing: [
(48.0, -122.8),
(48.2, -121.8),
(47.6, -121.6),
(47.0, -122.0),
(47.2, -122.6),
(48.0, -122.8)
])
// Create a polygon with one hole
let outerRing: [GeoPoint] = [
GeoPoint(latitude: 48.0, longitude: -122.8)!,
GeoPoint(latitude: 48.2, longitude: -121.8)!,
GeoPoint(latitude: 47.6, longitude: -121.6)!,
GeoPoint(latitude: 47.0, longitude: -122.0)!,
GeoPoint(latitude: 47.2, longitude: -122.6)!,
GeoPoint(latitude: 48.0, longitude: -122.8)!
]
let hole: [GeoPoint] = [
GeoPoint(latitude: 47.8, longitude: -122.6)!,
GeoPoint(latitude: 47.7, longitude: -122.2)!,
GeoPoint(latitude: 47.4, longitude: -122.6)!,
GeoPoint(latitude: 47.6, longitude: -122.5)!,
GeoPoint(latitude: 47.8, longitude: -122.6)!
]
let polygonWithOneHole = GeoPolygon(outerRing: outerRing, holes: [hole])
// Add a second hole to the polygon
let hole2: [GeoPoint] = [
GeoPoint(latitude: 47.55, longitude: -122.05)!,
GeoPoint(latitude: 47.55, longitude: -121.9)!,
GeoPoint(latitude: 47.3, longitude: -122.1)!,
GeoPoint(latitude: 47.55, longitude: -122.05)!
]
let polygonWithTwoHoles = GeoPolygon(outerRing: outerRing, holes: [hole, hole2])
3 GeoPolygon
クリックして拡大します

次に、これらのシェイプを地理空間クエリで使用できます。 地理空間データは、次の 3 つの方法でクエリできます。

  • 型安全性のある Realm Swift Query API での.geoWithin()演算子の使用

  • RQL で.filter()を使用する

  • NPredate クエリと.filter()の使用

以下の例では、これら 2 つのCompanyオブジェクトを使用するクエリの結果を示しています。

let company1 = Geospatial_Company()
company1.location = CustomGeoPoint(47.68, -122.35)
let company2 = Geospatial_Company(CustomGeoPoint(47.9, -121.85))
2 GeoPoints
クリックして拡大します
let companiesInSmallCircle = realm.objects(Geospatial_Company.self).where {
$0.location.geoWithin(smallCircle!)
}
print("Number of companies in small circle: \(companiesInSmallCircle.count)")
let companiesInLargeCircle = realm.objects(Geospatial_Company.self)
.filter("location IN %@", largeCircle)
print("Number of companies in large circle: \(companiesInLargeCircle.count)")
GeoCIDR の例をクエリします。
クリックして拡大します
let companiesInSmallBox = realm.objects(Geospatial_Company.self).where {
$0.location.geoWithin(smallBox)
}
print("Number of companies in small box: \(companiesInSmallBox.count)")
let filterArguments = NSMutableArray()
filterArguments.add(largeBox)
let companiesInLargeBox = realm.objects(Geospatial_Company.self)
.filter(NSPredicate(format: "location IN %@", argumentArray: filterArguments as? [Any]))
print("Number of companies in large box: \(companiesInLargeBox.count)")
GeoBox の例のクエリ。
let companiesInBasicPolygon = realm.objects(Geospatial_Company.self).where {
$0.location.geoWithin(basicPolygon!)
}
print("Number of companies in basic polygon: \(companiesInBasicPolygon.count)")
let companiesInPolygonWithTwoHoles = realm.objects(Geospatial_Company.self).where {
$0.location.geoWithin(polygonWithTwoHoles!)
}
print("Number of companies in polygon with two holes: \(companiesInPolygonWithTwoHoles.count)")
GeoPolygon のクエリの例をご覧ください。
クリックして拡大します

タイププロジェクションを使用してサポートされていないタイプをサポートされているタイプにマッピングする場合、それらのプロパティへのアクセスは多くの場合、永続化されたタイプに基づきます。

プロジェクションされた型を使用する場合、クエリは永続化された型で動作します。 ただし、ほとんどの場合、マップされた型は引数で永続化された型とどちらも使用できます。 例外は、埋め込みオブジェクトに対するクエリです。

Tip

プロジェクションされた型は、永続化された型がソートと集計をサポートする場合、ソートと集計をサポートします。

let akcClub = realm.objects(Club.self).where {
$0.name == "American Kennel Club"
}.first!
// You can use type-safe expressions to check for equality
XCTAssert(akcClub.url == URL(string: "https://akc.org")!)
let clubs = realm.objects(Club.self)
// You can use the persisted property type in NSPredicate query expressions
let akcByUrl = clubs.filter("url == 'https://akc.org'").first!
XCTAssert(akcByUrl.name == "American Kennel Club")

ノードごとの等価性を使用して、 オブジェクト内でサポートされているプロパティ型の埋め込み型をクエリできます。

オブジェクト リンク プロパティは等価比較をサポートしていますが、メンバーごとの比較はサポートしていません。 すべてのプリミティブ タイプで、埋め込みオブジェクトのノードごとの等価性をクエリできます。 オブジェクトとコレクションに対してメンバーごとの比較を実行することはできません。

スキーマにはカスタム型マッピングの概念がないため、動的 API のいずれかを経由してデータを読み取ると、基礎となる永続化された型が提供されます。 Realm は、動的 API 経由でマップされた型の書き込みをサポートしており、プロジェクションの型を永続的な型に変換します。

動的 API の最も一般的な用途は移行です。 移行中にプロジェクションされたタイプを書き込むことができ、Realm はプロジェクションされたタイプを永続的なタイプに変換します。 ただし、移行中にデータを読み取ると、基礎となる永続化されたタイプが提供されます。

アクター分離された Realm を使用する場合、Swift 同時実行機能を使用してオブジェクトを非同期にクエリできます。

let actor = try await RealmActor()
// Read objects in functions isolated to the actor and pass primitive values to the caller
func getObjectId(in actor: isolated RealmActor, forTodoNamed name: String) async -> ObjectId {
let todo = actor.realm.objects(Todo.self).where {
$0.name == name
}.first!
return todo._id
}
let objectId = await getObjectId(in: actor, forTodoNamed: "Keep it safe")

メイン スレッドまたはアクター分離された Realm で監視対象の Realm の状態を手動で高度化する必要がある場合は、 await realm.asyncRefresh()を呼び出します。 これにより、Realm によって管理される Realm と未処理のオブジェクトが更新され、最新データを指し、該当する通知が送信されます。

Swift 同時実行機能を使用して Realm を操作する方法の詳細については、 「 アクターで Realm を使用する - Swift SDK 」を参照してください。

ソート操作を使用すると、Realm Database がクエリされたオブジェクトを返す順序を構成できます。 結果コレクション内のオブジェクトの 1 つ以上のプロパティに基づいて並べ替えることができます。 Realm では、明示的にソートした場合にのみ、結果の一貫した順序が保証されます。

ソートするには、ソートするキー パスを指定して-[RMResults sortResultsUsingKeyPath:ascending:]を呼び出します。

RLMRealm *realm = [RLMRealm defaultRealm];
RLMResults *dogs = [Dog allObjectsInRealm:realm];
// Sort dogs by name
RLMResults *dogsSorted = [dogs sortedResultsUsingKeyPath:@"name" ascending:NO];
// You can also sort on the members of linked objects. In this example,
// we sort the dogs by their favorite toys' names.
RLMResults *dogsSortedByFavoriteToyName = [dogs sortedResultsUsingKeyPath:@"favoriteToy.name" ascending:YES];

バージョン10.11.0の新機能

型セーフなキーパスを使用してソートするには、keyPath 名とオプションのソート順序を指定してResults.sorted(by: )を呼び出します。

let realm = try! Realm()
// Access all dogs in the realm
let dogs = realm.objects(Dog.self)
// Sort by type-safe keyPath
let dogsSorted = dogs.sorted(by: \.name)

古い API を使用して並べ替えるには、並べ替えるキー パスを指定してResult.sorted(byKeyPath:ascending:)を呼び出します。

let realm = try! Realm()
// Access all dogs in the realm
let dogs = realm.objects(Dog.self)
let dogsSorted = dogs.sorted(byKeyPath: "name", ascending: false)
// You can also sort on the members of linked objects. In this example,
// we sort the dogs by their favorite toys' names.
let dogsSortedByFavoriteToyName = dogs.sorted(byKeyPath: "favoriteToy.name")

Tip

関連性と埋め込みオブジェクトのプロパティでソート

埋め込みオブジェクトまたは関連オブジェクトのプロパティに基づいてクエリをソートするには、通常のネストされたオブジェクトと同様に ドット表記 を使用します。

注意

stringソートと大文字と小文字を区別しないクエリは、「ラテン語の基本」、「ラテン語の追加」、「ラテン語の拡張 A」、および「ラテン語の拡張 B」の文字セットでのみサポートされます(UTF-8 範囲 0 ~ 591)。

結果を個々のセクションに分割できます。 各セクションは、表すオブジェクトのプロパティから生成されたキーに対応します。

たとえば、 nameプロパティの最初の文字を取得するには、 オブジェクトに計算変数を追加します。

// Computed variable that is not persisted, but only
// used to section query results.
var firstLetter: String {
return name.first.map(String.init(_:)) ?? ""
}

次に、そのオブジェクトに対してSessionedResults型セーフなコレクションを作成し、それを使用して、その計算された変数によってセクション化されたオブジェクトを検索できます。

var dogsByFirstLetter: SectionedResults<String, Dog>
dogsByFirstLetter = realm.objects(Dog.self).sectioned(by: \.firstLetter, ascending: true)

セクションの数を取得したり、キーのリストを取得したり、インデックスによって個々のResultSectionにアクセスしたりできます。

let realm = try! Realm()
var dogsByFirstLetter: SectionedResults<String, Dog>
dogsByFirstLetter = realm.objects(Dog.self).sectioned(by: \.firstLetter, ascending: true)
// You can get a count of the sections in the SectionedResults
let sectionCount = dogsByFirstLetter.count
// Get an array containing all section keys for objects that match the query.
let sectionKeys = dogsByFirstLetter.allKeys
// This example realm contains 4 dogs, "Rex", "Wolfie", "Fido", "Spot".
// Prints ["F", "R", "S", "W"]
print(sectionKeys)
// Get a specific key by index position
let sectionKey = dogsByFirstLetter[0].key
// Prints "Key for index 0: F"
print("Key for index 0: \(sectionKey)")
// You can access Results Sections by the index of the key you want in SectionedResults.
// "F" is the key at index position 0. When we access this Results Section, we get dogs whose name begins with "F".
let dogsByF = dogsByFirstLetter[0]
// Prints "Fido"
print(dogsByF.first?.name)

コールバックを使用してセクションを作成することもできます。 これにより、プリミティブのコレクションをセクション化したり、セクションキーの生成方法をより制御したりできます。

let realm = try! Realm()
let results = realm.objects(Dog.self)
let sectionedResults = results.sectioned(by: { String($0.name.first!) },
sortDescriptors: [SortDescriptor.init(keyPath: "name", ascending: true)])
let sectionKeys = sectionedResults.allKeys

SectionedResultsResultsSectionインスタンスが確認できます。どちらもThreadConfinedに準拠しています。

Realm の集計演算子を使用して、リスト プロパティに対する高度なクエリを実行できます。

バージョン 10.19.0 の新機能

let realm = try! Realm()
let people = realm.objects(Person.self)
// People whose dogs' average age is 5
people.where {
$0.dogs.age.avg == 5
}
// People with older dogs
people.where {
$0.dogs.age.min > 5
}
// People with younger dogs
people.where {
$0.dogs.age.max < 2
}
// People with many dogs
people.where {
$0.dogs.count > 2
}
// People whose dogs' ages combined > 10 years
people.where {
$0.dogs.age.sum > 10
}
let realm = try! Realm()
let people = realm.objects(Person.self)
// People whose dogs' average age is 5
people.filter("dogs.@avg.age == 5")
// People with older dogs
people.filter("dogs.@min.age > 5")
// People with younger dogs
people.filter("dogs.@max.age < 2")
// People with many dogs
people.filter("dogs.@count > 2")
// People whose dogs' ages combined > 10 years
people.filter("dogs.@sum.age > 10")
RLMRealm *realm = [RLMRealm defaultRealm];
RLMResults *people = [Person allObjectsInRealm:realm];
// People whose dogs' average age is 5
[people objectsWhere:@"dogs.@avg.age == 5"];
// People with older dogs
[people objectsWhere:@"dogs.@min.age > 5"];
// People with younger dogs
[people objectsWhere:@"dogs.@max.age < 2"];
// People with many dogs
[people objectsWhere:@"dogs.@count > 2"];
// People whose dogs' ages combined > 10 years
[people objectsWhere:@"dogs.@sum.age > 10"];

結果は 遅延評価 されるため、複数のクエリを連結できます。 従来のデータベースとは異なり、連続するクエリごとにデータベースを個別に使用する必要はありません。

タンジェントの結果セットと、名前が「B」で始まる名前のタームの結果セットを取得するには、次のように 2 つのクエリを連鎖させます。

バージョン 10.19.0 の新機能

let realm = try! Realm()
let tanDogs = realm.objects(Dog.self).where {
$0.color == "tan"
}
let tanDogsWithBNames = tanDogs.where {
$0.name.starts(with: "B")
}
let realm = try! Realm()
let tanDogs = realm.objects(Dog.self).filter("color = 'tan'")
let tanDogsWithBNames = tanDogs.filter("name BEGINSWITH 'B'")
RLMRealm *realm = [RLMRealm defaultRealm];
RLMResults<Dog *> *tanDogs = [Dog objectsInRealm:realm where:@"color = 'tan'"];
RLMResults<Dog *> *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH 'B'"];

Realm 内のクラス プロジェクションをクエリするには、メタタイプ インスタンスYourProjectionName.selfRealm.objects(_:)に渡します。 これにより、Realm 内のすべてのクラス プロジェクション オブジェクトを表す結果オブジェクトが返されます。

// Retrieve all class projections of the given type `PersonProjection`
let people = realm.objects(PersonProjection.self)
// Use projection data in your view
print(people.first?.firstName)
print(people.first?.homeCity)
print(people.first?.firstFriendsName)

Tip

クラスのプロジェクション結果に対して派生したクエリを実行しないでください。 代わりに、Realm オブジェクトに対して直接クエリを実行し、結果をプロジェクションします。 クラスのプロジェクション結果に対して派生クエリを実行しようとすると、元のオブジェクトと同じ名前とタイプを持つフィールドのクエリは機能しますが、元のオブジェクトにない名前やタイプのフィールドのクエリは失敗します。

戻る

作成