Docs Menu
Docs Home
/ /
Atlas Device SDK
/ / /

Realm オブジェクトの読み取り - Kotlin SDK

項目一覧

  • 読み取り操作
  • 凍結された結果とライブ結果
  • データベース オブジェクトの検索
  • オブジェクトの最新バージョンの検索
  • 一定型のすべてのオブジェクトのクエリ
  • 単一オブジェクトのクエリ
  • プロパティでフィルタリング
  • プライマリキーによるフィルタリング
  • 埋め込みオブジェクト プロパティによるフィルタリング
  • RealmAny(混合)プロパティによるフィルタリング
  • 再マッピングされたプロパティでフィルタリング
  • 全文検索(FTS)プロパティでフィルタリング
  • コレクション(リスト、セット、辞書)プロパティでフィルタリング
  • 関係プロパティでフィルタリング
  • 地理空間データのクエリ
  • 結果のソートと制限
  • 結果を集計する
  • フローを使用した結果の反復処理

このページでは、 Kotlin 用の Atlas Device SDK を使用してデータベースに保存されているオブジェクトをクエリし、遅延して読み取る方法について説明します。 この遅延評価により、大規模なデータセットや複雑なクエリを処理する際にコードの効率とパフォーマンスが向上します。

読み取り操作は、データベース オブジェクトをクエリし、結果にアクセスする準備ができたときにクエリを実行することで構成されます。 読み取り操作の構文は、同期されたデータベースと同期されていないデータベースで同じです。

すべてのクエリはオブジェクトタイプに基づいています。 埋め込みオブジェクトを含む、データベースに永続し、そのタイプがデータベース スキーマに含まれる任意のオブジェクトをクエリできます。

SDK のクエリ ビルダ RealmQueryを使用してクエリを構築し、オブジェクトタイプを型パラメータとして渡します。 RealmまたはMutableRealmインスタンス、 RealmResultsコレクション、またはRealmListコレクション上のオブジェクトをクエリできます。

基本のRealmQueryは、指定された型のすべてのオブジェクトを返します。

// Finds all objects of type <T>
.query<T>()

追加のフィルターと条件(たとえば、並べ替え、集計、結果の制限など)を使用してクエリを絞り込むことができます。 RQL ( RQL )は string ベースのクエリ言語で、SDK によって提供される組み込みのKotlin拡張関数とヘルパー メソッドと組み合わせて、1 つ以上のプロパティで結果を絞り込むことができます。

// Finds all objects of type <T> that meet the filter conditions
// and returns them in the specified sort order
.query<T>(filter).sort(sort)

追加の query() メソッドを使用して、クエリを 連鎖 させることもできます。追加された各query()ANDクエリ条件として機能します。 また、SDK の遅延評価により、連続するクエリにデータベースへの個別のトリップは必要ありません。

// Finds all objects of type <T> that meet the first filter conditions
// AND the subsequent filter conditions
.query<T>(filter).query(filter)

データにアクセスして返された結果を操作する準備ができたら、クエリを実行します。

検索された結果では、メモリ内に一致するデータベース オブジェクトが実際には保持されていないことに注意してください。 代わりに、データベースは直接参照、またはポインターを使用します。 結果コレクションまたはフロー内のデータベース オブジェクトは、データベース ファイル内のデータに直接マップされる一致したオブジェクトを参照します。 つまり、クエリの結果からオブジェクトの関係のグラフを直接走査できることも意味します。

クエリを実行する

val queryAllFrogs = realm.query<Frog>()
val queryAllLiveFrogs = this.query<Frog>() // this: MutableRealm
// Calling 'find()' on the query returns a RealmResults collection
// Can be called on a `Realm.query()` or `MutableRealm.query()`
val allFrogs: RealmResults<Frog> = queryAllFrogs.find()
val allLiveFrogs: RealmResults<Frog> = queryAllLiveFrogs.find()
// Calling 'asFlow()' on the query returns a ResultsChange Flow
// Can ONLY be called on a `Realm.query()`
val allFrogsFlow: Flow<ResultsChange<Frog>> = queryAllFrogs.asFlow()

常にライブ結果を返す他の Atlas Device SDK とは異なり、 Kotlin SDK の結果は固定またはライブ化できます。 Kotlin SDK の固定アーキテクチャの詳細については、「 凍結されたアーキテクチャ - Kotlin SDK 」を参照してください。

固定された結果にアクセスするには、 Realmで クエリを実行します。 凍結された結果は変更されず、データベースの最新の変更を反映していません。 Realm.query()には書込みトランザクションは必要ありません。

ライブ結果にアクセスするには、書込みトランザクション (write transaction) のMutableRealmインスタンスに対してクエリを実行します。 MutableRealmはデータベースの書込み可能な状態を表し、書込みトランザクションからのアクセスできます。 MutableRealm .クエリの結果はライブですが、呼び出しスレッドでのみ有効であり、書込みトランザクションが完了すると固定されます。 書込みトランザクションとMutableRealmへのアクセスの詳細については、「 書込みトランザクション 」を参照してください

MutableRealm.find latest()を呼び出して、固定された結果からライブ オブジェクトにアクセスすることもできます。 詳細については、このページの「オブジェクトの最新バージョンの検索」セクションを参照してください。

ライブ結果へのアクセス

// 'Realm.query()' results are always frozen
val frozenResults = realm.query<Frog>("age > $0", 50).find()
// 'MutableRealm.query()' results are live within the current write transaction
realm.write { // this: MutableRealm
val liveResults = this.query<Frog>("age > $0", 50).find()

データベース内に保存されているオブジェクトを検索するには、次の手順に従います。

  1. オブジェクトタイプを型パラメーターとしてquery()に渡します。 オブジェクトタイプはデータベース スキーマにすでに含まれている必要があります。

  2. オプションで、結果をさらに絞り込むために任意のクエリ条件を渡します。

    • 条件を満たすオブジェクトのみを返すフィルターを指定します。 フィルターを指定しない場合、SDK は指定されたタイプのすべてのオブジェクトを返します。

      RealmQueryに追加のquery()メソッドを追加することで、フィルターを連鎖させることができます。

    • 結果のソート順序を指定します。 データベースは順序付けられていないため、ソート順序を含めない場合、SDK はクエリが特定の順序でオブジェクトを返すことを保証できません。

  3. 次のいずれかを使用してクエリを実行します。

    • 同期クエリ用のfind() 結果のコレクションを返します。

    • 非同期クエリの場合はasFlow()を使用します。 結果の変更のFlowにサブスクライブします。

    Tip

    大規模なデータセットでは asFlow() を使用する

    find() は、呼び出されたスレッドで同期クエリを実行します。 そのため、UI スレッド上の大規模なデータセット、または UI スレッドを遅延させる可能性のあるロジックでは、 find()を使用しないでください。

    悪パフォーマンスや UI への影響を防ぐには、 asFlow()を使用することを優先します。

  4. 結果を操作します。 実行したクエリの種類に応じて、オブジェクトは固定されているか保存されている場合があります。

読み取り操作

// Pass the object type as <T> parameter and filter by property
val findFrogs = realm.query<Frog>("age > 1")
// Chain another query filter
.query("owner == $0 AND name CONTAINS $1", "Jim Henson", "K")
// Sort results by property
.sort("age", Sort.ASCENDING)
// Run the query
.find()
// ... work with the results

SDK の固定アーキテクチャにより、常に最新バージョンのオブジェクトまたはコレクションを操作しているわけではありません。

データベースの最新の変更を反映しているオブジェクトまたはコレクションのバージョンを取得するには、 MutableRealmインスタンスからfindLast()を呼び出します。 MutableRealm.query()と同様に、結果はライブです、呼び出し元のスレッドでのみ有効であり、書込みトランザクションが完了すると固定されます。

次の例では、既存のfrozenFrogsクエリのRealmResultsfindLatest()に渡して、コレクションの最新のライブ コピーを取得します。 次に、書込みトランザクション (write transaction) 内の有効なオブジェクトを変更します。

// Open a write transaction to access the MutableRealm
realm.write { // this: MutableRealm
for (frog in frozenFrogs) {
// Call 'findLatest()' on an earlier query's frozen results
// to return the latest live objects that you can modify
// within the current write transaction
findLatest(frog)?.also { liveFrog ->
copyToRealm(liveFrog.apply { age += 1 })
println(liveFrog.name + " is now " + liveFrog.age + " years old")
}
}
}

Tip

isFrozen()メソッドを使用して、オブジェクトが固定されているかどうかを確認できます。

val isFrozen = frog.isFrozen()

特定の型のすべてのオブジェクトをクエリするには、 RealmObjectまたはEmbeddedRealmObjectオブジェクトタイプを型パラメータとしてquery()にクエリ引数なしで渡します。 SDK は、指定されたタイプのすべてのオブジェクトを返します。

注意

非対称オブジェクトは読み取れません

非対称オブジェクトは、データベースに永続しない特殊な書込み専用オブジェクトであるため、読み取りできません。 アプリケーションで非対称オブジェクトを使用する方法の詳細については、「 Atlas へのデータのストリーム - Kotlin SDK 」を参照してください。

次の例では、タイプFrogのすべてのRealmObjectオブジェクトをクエリします。

// Query all Frog objects in the database
val queryAllFrogs = realm.query<Frog>()
val allFrogs = queryAllFrogs.find()

次の例では、タイプEmbeddedAddressのすべてのEmbeddedRealmObjectオブジェクトをクエリします。

val queryAllEmbeddedAddresses = realm.query<EmbeddedAddress>()
val allEmbeddedAddresses = queryAllEmbeddedAddresses.find()

また、親オブジェクトを介して埋め込みオブジェクトをクエリすることもできます。 詳細については、このページの「埋め込みオブジェクト プロパティによるフィルタリング」セクションを参照してください。

Tip

埋め込みオブジェクトが見つかったら、埋め込みRealmObject.parent()メソッドを使用してその親にアクセスできます。

val getParent = embeddedObject.parent<Contact>()

特定のオブジェクトタイプの単一のオブジェクトを検索するには、クエリでfirst()を呼び出します。 クエリを実行すると、SDK は条件に一致する最初のオブジェクトまたはnullを返します。

次の例では、 Frogオブジェクトタイプをクエリし、最初のオブジェクトを返します。

val querySingleFrog = realm.query<Frog>().first()
val singleFrog = querySingleFrog.find()
if (singleFrog != null) {
println("${singleFrog.name} is a frog.")
} else {
println("No frogs found.")
}

データベースに永続するオブジェクトタイプの任意のプロパティでクエリをフィルタリングできます。 これには、ドット表記を使用して参照できる子プロパティが含まれます。

プロパティでフィルタリングするには、 RQL ( RQL )フィルターと演算子を渡し、 Kotlinの組み込み拡張メソッドまたは SDK の便宜メソッドを使用するか、 組み合わせを使用します。 現在サポートされているすべてのRQL演算子と構文の詳細については、 RQLに関する参考ドキュメントを参照してください。

次の例では、 Frogオブジェクトタイプをクエリし、 nameプロパティでフィルタリングします。

val filterByProperty = realm.query<Frog>("name == $0", "Kermit")
val frogsNamedKermit = filterByProperty.find()

プライマリキーは、データベース内のオブジェクトの一意の識別子であるため、特定のオブジェクトをクエリするのに役立ちます。

特定のプライマリキーでフィルタリングするには、オブジェクトタイプを type パラメーターとして渡し、プライマリキー フィールドで目的の値をクエリします。

次の例では、 Frogオブジェクトをクエリし、プライマリキー プロパティ_idでフィルタリングします。

val filterByPrimaryKey = realm.query<Frog>("_id == $0", PRIMARY_KEY_VALUE)
val findPrimaryKey = filterByPrimaryKey.find().first()

Tip

Device Sync では常に _id がプライマリキーとして使用されます

Atlas Device Sync を使用している場合は、いつでもプライマリキー フィールド_idでクエリを実行できます。 これは、Device Sync データモデルでは、オブジェクトが_idという名前のプライマリキーを持っている必要があるためです。 詳細については、「 Device Sync によるデータのモデル化 - Kotlin SDK 」を参照してください。

埋め込みオブジェクトは、単一の特定の親オブジェクト内でネストされたデータとして機能します。 埋め込みオブジェクトを直接、またはその親オブジェクトのプロパティとしてクエリできます。 埋め込みオブジェクトを直接クエリする方法については、このページの「タイプのすべてのオブジェクトをクエリ」セクションを参照してください。

親オブジェクトから埋め込みオブジェクトを検索するには、親オブジェクトタイプを型パラメータとして渡し、ドット表記を使用して埋め込みオブジェクトプロパティでフィルタリングします。

次の例では、 addressという埋め込みオブジェクト プロパティを含むContact親オブジェクトがあります。 埋め込みオブジェクトのaddress.streetプロパティに対してContactオブジェクトタイプをクエリします。

// Use dot notation to access the embedded object properties as if it
// were in a regular nested object
val filterEmbeddedObjectProperty =
realm.query<Contact>("address.street == '123 Pond St'")
// You can also access properties nested within the embedded object
val queryNestedProperty = realm.query<Contact>()
.query("address.propertyOwner.name == $0", "Mr. Frog")

RealmAny(混合)プロパティは、特定の時点でサポートされているデータ型の 1 つを保持できる多態的な値を表します。 RealmAnyプロパティは、任意のプロパティと同じ方法でクエリできます。

次の例では、タイプIntがお気に入りのコレクションを持つfログのfavoriteThingと呼ばれるRealmAnyプロパティをクエリします。

val filterByRealmAnyInt = realm.query<Frog>("favoriteThing.@type == 'int'")
val findFrog = filterByRealmAnyInt.find().first()

他のプロパティと違い、 RealmAnyプロパティを操作する前に、その保存値を抽出する必要があります。 値を抽出するには、保存された型の SDK の getter メソッドを使用します。 型に間違った getter を使用すると、SDK は例外をスローします。

ベストプラクティスとして、条件式を使用して、 RealmAny.type()に現在保存されている型を取得します。 型に基づいて値を抽出します。 getter メソッドの完全なリストについては、 RealmAny API リファレンス を参照してください。

次の例では、 RealmAny.asInt()を使用して 値を抽出します。 これは、返されたカドのお気に入りがInt型の値であることがわかっているためです。

val frogsFavoriteThing = findFrog.favoriteThing // Int
// Using the correct getter method returns the value
val frogsFavoriteNumber = frogsFavoriteThing?.asInt()
println("${findFrog.name} likes the number $frogsFavoriteNumber")

Tip

条件式による多形データの処理

条件付きwhen式を使用して、特定のRealmAnyプロパティの可能な内部値クラスを処理します。

// Handle possible types with a 'when' statement
frogsFavoriteThings.forEach { realmAny ->
if (realmAny != null) {
when (realmAny.type) {
RealmAny.Type.INT -> {
val intValue = realmAny.asInt()
// Do something with intValue ...
}
RealmAny.Type.STRING -> {
val stringValue = realmAny.asString()
// Do something with stringValue ...
}
RealmAny.Type.OBJECT -> {
val objectValue = realmAny.asRealmObject(Frog::class)
// Do something with objectValue ...
}
// Handle other possible types...
else -> {
// Debug or perform a default action for unhandled types
Log.d("Unhandled type: ${realmAny.type}")
}
}
}
}

現在保存されている値を取得したら、その型の別の値と同じ方法でその値を操作できます。

注意

ByteCharIntLongShortの値は、内部的にint64_t値に変換されます。 これらのタイプのRealmAny値を比較、ソート、または集計するときは、この点に注意してください。

データモデルに再マッピングされたプロパティ名が含まれている場合は、コードで使用される Kotlin プロパティ名と、 データベースに保存されている再マッピングされたプロパティ名の両方でフィルタリングできます。

次の例では、 Frogオブジェクトには、 データベース内のlatin_nameに再マッピングされているコード内のspeciesという名前のプロパティがあります。

@PersistedName("latin_name")
var species: String? = null // Remapped property

データベースでは、プロパティ名でフィルタリングして同じ結果を返すことができます。

val filterByKotlinName = realm.query<Frog>("species == $0", "Muppetarium Amphibius")
val findSpecies = filterByKotlinName.find().first()
val filterByRemappedName = realm.query<Frog>("latin_name == $0", "Muppetarium Amphibius")
val find_latin_name = filterByRemappedName.find().first()
// Both queries return the same object
assertEquals(findSpecies, find_latin_name)

バージョン 1.11.0 での変更: プレフィックス ワイルドカード検索のサポート

データモデルに全文検索(FTS)インデックス プロパティが含まれている場合は、 TEXT述語を使用したプロパティでフィルタリングできます。 クエリ内の単語は、次のルールを使用して トークナイザ によってトークンに変換されます。

  • トークンは、ASCII と Atlas 1 の追加文字(西部言語)のみで構成できます。 他のすべての文字は空白と見なされます。

  • ハイフン( - )で区切られた単語は 2 つのトークンに分割されます。 たとえば、 full-textfulltextに分割されます。

  • トークンは、発音区別符号を区別せず、大文字と小文字を区別しません。

単語またはフレーズ全体を検索することも、次の文字で結果を制限することもできます。

  • 単語の前に-文字を付けて、単語の結果を除外します。 たとえば、 fiction -scienceにはfictionのすべての検索結果が含まれ、 scienceという単語を含む検索結果は除外されます。

  • Kotlin SDK バージョン 1.11.0 以降では、単語の末尾に*文字を配置することでプレフィックスを指定できます。 たとえば、 fict*にはfictionfictitiousのすべての検索結果が含まれます。 ( Kotlin SDK は現在、サフィックス検索をサポートしていませ。)

SDK は、指定されたクエリに対して関連性ベースの一致ではなくブール値の一致を返します。

次の例では、 FrogオブジェクトタイプにはphysicalDescriptionという FTS インデックス プロパティがあり、これをフィルタリングしてさまざまなタイプの fログ を検索できます。

// Filter by FTS property value using 'TEXT'
// Find all frogs with "green" in the physical description
val onlyGreenFrogs =
realm.query<Frog>("physicalDescription TEXT $0", "green").find()
// Find all frogs with "green" but not "small" in the physical description
val onlyBigGreenFrogs =
realm.query<Frog>("physicalDescription TEXT $0", "green -small").find()
// Find all frogs with "muppet-" and "rain-" in the physical description
val muppetsInTheRain =
realm.query<Frog>("physicalDescription TEXT $0", "muppet* rain*").find()

オブジェクトタイプの定義方法によっては、サポートされている次のコレクション タイプのいずれかとして定義されるプロパティがある場合があります。

  • RealmList

  • RealmSet

  • RealmDictionary

これらのコレクション プロパティは、RQL を使用して他のプロパティと同じ方法でクエリできます。 Kotlin に組み込まれているコレクション関数を使用して、結果をフィルタリング、ソート、反復処理することもできます。

RealmList プロパティでは Kotlin List と同様にクエリと反復処理ができます。

次の例では、 favoritePondsというRealmListプロパティをクエリします。

// Find frogs with a favorite pond
val allFrogs = query<Frog>().find()
val frogsWithFavoritePond = allFrogs.query("favoritePonds.@size > $0", 0).find()
// Check if the list contains a value
for (frog in frogsWithFavoritePond) {
val likesBigPond = frog.favoritePonds.any { pond -> pond.name == "Big Pond" }
if (likesBigPond) {
Log.v("${frog.name} likes Big Pond")
} else {
Log.v("${frog.name} does not like Big Pond")
}
}

RealmSet プロパティでは Kotlin Set と同様にクエリと反復処理ができます。

次の例では、 favoriteSnacksというRealmSetプロパティをクエリします。

// Find frogs with flies and crickets as a favorite snack
val filterBySnackSet = query<RealmSet_Frog>("favoriteSnacks.name CONTAINS $0 AND favoriteSnacks.name CONTAINS $1", "Flies", "Crickets")
val potentialFrogs = filterBySnackSet.find()
// Check if the set contains a value
val frogsThatLikeWorms = potentialFrogs.filter { frog ->
val requiredSnacks = query<RealmSet_Snack>("name == $0", "Worms")
frog.favoriteSnacks.contains(requiredSnacks.find().first())
}
for (frog in frogsThatLikeWorms) {
Log.v("${frog.name} likes both Flies, Worms, and Crickets")
}

Kotlin マップ と同様に RealmDictionary プロパティをクエリして反復処理できます。

次の例では、 favoritePondsByForestというRealmDictionaryプロパティをクエリします。このプロパティは、 Stringキー(フォスト)をString値(ロード)にマッピングします。

// Find frogs who have forests with favorite ponds
val frogs = realm.query<Frog>().find()
val frogsWithFavoritePonds = frogs.query("favoritePondsByForest.@count > $0", 1).find()
val thisFrog = frogsWithFavoritePonds.first()
// Iterate through the map and log each key-value pair
for (forestName in thisFrog.favoritePondsByForest.keys) {
val pondName = thisFrog.favoritePondsByForest[forestName]
Log.v("Forest: $forestName, Pond: $pondName")
}
// Check if the dictionary contains a key
if (thisFrog.favoritePondsByForest.containsKey("Hundred Acre Wood")) {
Log.v("${thisFrog.name}'s favorite pond in Hundred Acre Wood is ${thisFrog.favoritePondsByForest["Hundred Acre Wood"]}")
}
// Check if the dictionary contains a value
if (thisFrog.favoritePondsByForest.containsValue("Picnic Pond")) {
Log.v("${thisFrog.name} lists Picnic Pond as a favorite pond")
}

オブジェクトタイプの定義方法によっては、別のデータベース オブジェクトを参照するプロパティがある場合があります。 これは 1 対多、対多、または逆の関係にすることができます。

埋め込みオブジェクトを参照する関係プロパティによるフィルタリングの詳細については、このページの「埋め込みオブジェクト プロパティによるフィルタリング 」セクションを参照してください。

対 1 の関係プロパティは、別のオブジェクトタイプの単一のインスタンスにマップされます。 ドット表記を使用して、ネストされたオブジェクトと同様に、 関係 プロパティでフィルタリングできます。

次の例では、 Frogオブジェクトタイプには、タイプPondfavoritePondというプロパティがあります。

// Find frogs who have a favorite pond
val allFrogs = query<Frog>().find()
val frogsWithFavoritePond = allFrogs.query("favoritePond.@count == $0", 1).find()
// Iterate through the results
for (frog in frogsWithFavoritePond) {
Log.v("${frog.name} likes ${frog.favoritePond?.name}")
}

対多の関係プロパティは、別のオブジェクトタイプのコレクション( RealmListまたはRealmSet )です。 関係プロパティでは、他のコレクション プロパティと同様に、 でフィルタリングして反復処理できます。

次の例では、 Forestオブジェクトタイプには、 nearbyPondsというタイプのPond RealmListである というプロパティがあります。

// Find all forests with at least one nearby pond
val allForests = query<Forest>().find()
val forestsWithPonds = allForests.query("nearbyPonds.@count > $0", 0).find()
// Iterate through the results
for (forest in forestsWithPonds) {
val bigPond = query<Pond>("name == $0", "Big Pond").find().first()
if (forest.nearbyPonds.contains(bigPond)) {
Log.v("${forest.name} has a nearby pond named ${bigPond.name}")
} else {
Log.v("${forest.name} does not have a big pond nearby")
}
}

1 対多の関係とは異なり、逆関係では親オブジェクトと子オブジェクト間のバックリンクが自動的に作成されます。 つまり、親と子の両方に対して常にクエリを実行できます。 RQL 固有の構文を使用してバックリンクをクエリすることもできます(詳細については、「 バックリンククエリ」を参照してください)。

次の例では、タイプUserの親オブジェクトとタイプPostの子オブジェクトと逆の関係があります。 親オブジェクトのUser.posts関係(「ユーザーには多数の投稿がある」)と、逆のPost.user関係(「投稿はユーザーに属する」)をクエリできます。

// Query the parent object
val filterByUserName = query<User>("name == $0", "Kermit")
val kermit = filterByUserName.find().first()
// Use dot notation to access child objects
val myFirstPost = kermit.posts[0]
// Iterate through the backlink collection property
kermit.posts.forEach { post ->
Log.v("${kermit.name}'s Post: ${post.date} - ${post.title}")
}
// Filter posts through the parent's backlink property
// using `@links.<ObjectType>.<PropertyName>` syntax
val oldPostsByKermit = realm.query<Post>("date < $0", today)
.query("@links.User.posts.name == $0", "Kermit")
.find()
// Query the child object to access the parent
val post1 = query<Post>("title == $0", "Forest Life").find().first()
val post2 = query<Post>("title == $0", "Top Ponds of the Year!").find().first()
val parent = post1.user.first()

重要

再マッピングされたクラス名による逆関係のクエリ

逆関係プロパティが再マップされた(永続化)クラス名を持つオブジェクトタイプである場合は、未加工 RQL クエリで再マップされたクラス名を使用する必要があります。

@PersistedName(name = "Blog_Author")
class User : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId()
var name: String = ""
var posts: RealmList<Post> = realmListOf()
}
// Filter by the remapped object type name
// using `@links.<RemappedObjectType>.<PropertyName>` syntax
val postsByKermit = realm.query<Post>()
.query("@links.Blog_Author.posts.name == $0", "Kermit")
.find()

バージョン 1.11.0 の新機能

Kotlin SDK バージョン 1.11.0 以降では、地理空間データによるクエリをサポートする実験的な地理空間 API が追加されています。

注意

地理空間データを保持するには、データモデル内に GeoJSON 互換のカスタム埋め込みクラスを定義する必要があります。 要件の詳細については、「 永続的な地理空間データ 」を参照してください。

地理空間データは、カスタム埋め込みオブジェクトのcoordinatesプロパティに緯度と経度のペアとして保持されます。 地理空間クエリは、 coordinatesプロパティによって定義された点が定義された地理空間形状の境界内に含まれているかどうかを確認します。

SDK は次の地理空間の形状をサポートしています。

  • GeoCircle: 中心GeoPointと半径Distanceによって定義

  • GeoBox: ボックスのエスケープとメンバーシップを表す 2 つのGeoPoint座標によって定義されます

  • GeoPolygon: 閉じた形状を表す少なくとも 4 つのGeoPoint座標のセットによって定義されます。 この形状には、定義された多角形の範囲内の排他的な境界を表す穴を含めることができます。

地理空間の形状とその定義方法について詳しくは、「地理空間データ - Kotlin SDK 」を参照してください。

地理空間データをクエリするには、次のようにします。

  1. 埋め込み地理空間データを含むオブジェクトを作成します。

  2. 地理空間の形状を定義して、クエリの境界を設定します。

  3. GEOWITHIN RQL 演算子を使用してクエリを実行します。 このメソッドは、GeoJSON 互換埋め込みオブジェクトのcoordinatesプロパティを受け取り、その点が定義された形状の境界内に含まれているかどうかを確認します。 地理空間の形状に関係なく、構文は同じです。

次の例では、埋め込まれたlocationプロパティを使用して、 Companyオブジェクトに保存されている地理空間データをクエリします。 クエリ境界を設定するために 2 つのGeoCircleオブジェクトを作成します。

val circle1 = GeoCircle.create(
center = GeoPoint.create(47.8, -122.6),
radius = Distance.fromKilometers(44.4)
)
val circle2 = GeoCircle.create(
center = GeoPoint.create(47.3, -121.9),
radius = Distance.fromDegrees(0.25)
)

次に、定義されたGeoCircle境界内に含まれるlocationを持つCompanyオブジェクトをクエリします。

val companiesInLargeCircle =
realm.query<Company>("location GEOWITHIN $circle1").find()
println("Companies in large circle: ${companiesInLargeCircle.size}")
val companiesInSmallCircle =
realm.query<Company>("location GEOWITHIN $circle2").find()
println("Companies in small circle: ${companiesInSmallCircle.size}")
Companies in large circle: 1
Companies in small circle: 0
Georound のクエリの例
クリックして拡大します

結果が期待どおりに返されるようにするには、 RQL ソート、制限、個別の 演算子、次の SDK 便利メソッド、または両方の組み合わせを使用して、ソート順序と制限条件を指定できます。

重要

順序は重要

RQL メソッドまたは便宜的メソッドのどちらを使用するかにかかわらず、SDK はクエリに追加された順序で各リクエストを実行します。 これは返される結果に影響を与える可能性があります。 たとえば、クエリを制限する前にソートすると制限してからソートすることとは異なる結果が返される可能性があります。

次の例では、便宜的メソッドのみ、RQL のみ、および両方の組み合わせを使用してソートと制限を行い、同じ結果を返します。

// Query for all frogs owned by Jim Henson, then:
// 1. Sort results by age in descending order
// 2. Limit results to only distinct names
// 3. Limit results to only the first 2 objects
val organizedWithMethods = realm.query<Frog>("owner == $0", "Jim Henson")
.sort("age", Sort.DESCENDING)
.distinct("name")
.limit(2)
.find()
organizedWithMethods.forEach { frog ->
Log.v("Method sort: ${frog.name} is ${frog.age}")
}
val organizedWithRql = realm.query<Frog>()
.query("owner == $0 SORT(age DESC) DISTINCT(name) LIMIT(2)", "Jim Henson")
.find()
organizedWithRql.forEach { frog ->
Log.v("RQL sort: ${frog.name} is ${frog.age}")
}
val organizedWithBoth = realm.query<Frog>()
.query("owner == $0 SORT(age DESC)", "Jim Henson")
.distinct("name")
.limit(2)
.find()
organizedWithBoth.forEach { frog ->
Log.v("Combined sort: ${frog.name} is ${frog.age}")
}
Method sort: Kermit, Sr. is 100
Method sort: Kermit is 42
RQL sort: Kermit, Sr. is 100
RQL sort: Kermit is 42
Combined sort: Kermit, Sr. is 100
Combined sort: Kermit is 42

注意

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

結果を集計することもできます。これにより、指定された数値プロパティまたはコレクションに基づいて、結果を単一の値に縮小します。 RQL 集計演算子、次のいずれかの便利なメソッド、または両方の組み合わせを使用できます。

次の例では、 Frogオブジェクトタイプのageプロパティを集計します。

val jimHensonsFrogs = realm.query<Frog>("owner == $0", "Jim Henson")
// Find the total number of frogs owned by Jim Henson
val numberOfJimsFrogs = jimHensonsFrogs.count().find()
// Find the oldest frog owned by Jim Henson
val maxAge = jimHensonsFrogs.max<Int>("age").find()
val oldestFrog = jimHensonsFrogs.query("age == $0", maxAge).find().first()

Kotlin コルーチン フローを使用して結果を反復処理できます。

クエリ結果を非同期Flowに変換するには、クエリでasFlow()を呼び出します。 SDK は、 Flowflow.collection () を使用して反復処理できる 結果変更 を返します 。

次の例では、 FrogオブジェクトのFlowを反復処理します。

// Get a Flow of all frogs in the database
val allFrogsQuery = realm.query<Frog>()
val frogsFlow: Flow<ResultsChange<Frog>> = allFrogsQuery.asFlow()
// Iterate through the Flow with 'collect()'
val frogsObserver: Deferred<Unit> = async {
frogsFlow.collect { results ->
when (results) {
is InitialResults<Frog> -> {
for (frog in results.list) {
Log.v("Frog: $frog")
}
}
else -> { /* no-op */ }
}
}
}
// ... Later, cancel the Flow, so you can safely close the database
frogsObserver.cancel()
realm.close()

Tip

フローをサブスクライブして変更をリッスンする

クエリからFlowを生成したら、通知ハンドラーを登録して、 ResultsChangesへの変更をリッスンできます。 詳細については、「変更に対応する - React Kotlin SDK 」を参照してください。

戻る

作成