Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

CRUD - 読み取り - Java SDK

項目一覧

  • 読み取り操作
  • 読み取り特性
  • 結果はコピーではない
  • 結果は遅延
  • 参照は保持されます
  • このページの例について
  • Realm からの読み取り
  • プライマリキーによる特定のオブジェクトの検索
  • 特定の型のすべてのオブジェクトのクエリ
  • オブジェクト プロパティに基づいてクエリをフィルタリングする
  • クエリ結果のソート
  • 関係のクエリ
  • 逆関係のクエリ
  • データを集計する

Realm に保存したデータを読み取ることができます。 Realm SDK 全体の標準データ アクセス パターンは、オブジェクトをこの順序で検索、フィルタリング、ソートすることです。 アプリが大きくなり、クエリが複雑になるにつれて Realm から最高のパフォーマンスを得るには、Realm 読み取り特性を確実に理解するためにアプリのデータ アクセス パターンを設計します。

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 全体にわたる直接参照を走査できます。

このページの例では、 ProjectTaskの 2 つの Realm オブジェクトタイプを持つプロジェクト管理アプリのデータモデルを使用します。 Projectには 0 個以上のTasksがあります。

これらの 2 つのクラス、 ProjectTaskのスキーマを以下で参照してください。

ProjectTask.java
import org.bson.types.ObjectId;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.RealmClass;
import io.realm.annotations.Required;
public class ProjectTask extends RealmObject {
@PrimaryKey
public ObjectId _id;
@Required
public String name;
public String assignee;
public int progressMinutes;
public boolean isComplete;
public int priority;
@Required
public String _partition;
}
Project.java
import org.bson.types.ObjectId;
import io.realm.RealmList;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.RealmClass;
import io.realm.annotations.Required;
public class Project extends RealmObject {
@PrimaryKey
public ObjectId _id;
@Required
public String name;
public RealmList<ProjectTask> tasks = new RealmList<>();
}
ProjectTask.kt
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.Required
import org.bson.types.ObjectId
open class ProjectTask(
@PrimaryKey
var _id: ObjectId = ObjectId(),
@Required
var name: String = "",
var assignee: String? = null,
var progressMinutes: Int = 0,
var isComplete: Boolean = false,
var priority: Int = 0,
var _partition: String = ""
): RealmObject()
Project.kt
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.Required
import org.bson.types.ObjectId
open class Project(
@PrimaryKey
var _id: ObjectId = ObjectId(),
@Required
var name: String = "",
var tasks: RealmList<ProjectTask> = RealmList(),
): RealmObject()

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

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

重要

UI スレッドでの同期読み取りと書込み

デフォルトでは、非同期トランザクションを使用して、アプリケーションの UI スレッド内の Realm の読み取りまたは書き込みのみが可能です。 つまり、同期メソッドの使用を明示的に許可しない限り、Android アプリケーションのメイン スレッドでは、名前がAsyncという単語で終わるRealmメソッドのみを使用できます。

この制限はアプリケーション ユーザーのメリットのために存在します。UI スレッドで読み取りおよび書込み操作を実行すると、UI のインタラクションが応答しなくなったり低速になったりする可能性があるため、通常、これらの操作は非同期またはバックグラウンド スレッドで取り扱うことをお勧めします。 ただし、アプリケーションで同期 Realm の読み取りまたは UI スレッドでの書込みを使用する必要がある場合は、次のSyncConfigurationオプションを使用して同期メソッドの使用を明示的に許可できます。

SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION)
.allowQueriesOnUiThread(true)
.allowWritesOnUiThread(true)
.build();
Realm.getInstanceAsync(config, new Realm.Callback() {
@Override
public void onSuccess(Realm realm) {
Log.v(
"EXAMPLE",
"Successfully opened a realm with reads and writes allowed on the UI thread."
);
}
});
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION)
.allowQueriesOnUiThread(true)
.allowWritesOnUiThread(true)
.build()
Realm.getInstanceAsync(config, object : Realm.Callback() {
override fun onSuccess(realm: Realm) {
Log.v("EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread.")
}
})

特定のプライマリキー値を持つオブジェクトを検索するには、Realm を開き、 RealmQuery.equalTo() メソッドを使用して、目的のプライマリキー値をプライマリキー フィールドでクエリします。 メソッド:

ProjectTask task = realm.where(ProjectTask.class).equalTo("_id", PRIMARY_KEY_VALUE.get()).findFirst();
Log.v("EXAMPLE", "Fetched object by primary key: " + task);
val task = realm.where(ProjectTask::class.java)
.equalTo("_id", ObjectId.get()).findFirst()
Log.v("EXAMPLE", "Fetched object by primary key: $task")

読み取りの最初のステップは、Realm 内の特定のタイプのすべてのオブジェクトを取得することです。 この結果コレクションでは、タイプまたはフィルターのすべての インスタンスに対して を操作し、並べ替えて結果を絞り込むことができます。

ProjectTaskProjectのすべてのインスタンスにアクセスするには、 where()メソッドを使用してクラスを指定します。

RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class);
RealmQuery<Project> projectsQuery = realm.where(Project.class);
val tasksQuery = realm.where(ProjectTask::class.java)
val projectsQuery = realm.where(Project::class.java)

フィルターは、1 つ以上のオブジェクト プロパティの値に基づいて結果のサブセットを選択します。 Realm は、フィルターの定義に使用できるフル機能のクエリ エンジンを提供します。 最も一般的なユースケースは、特定のプロパティが特定の値と一致するオブジェクトを検索することです。 さらに、文字列を比較したり、数値のコレクションを集計したり、論理演算子を使用して複雑なクエリを構築したりすることもできます。

次の例では、クエリ エンジンの比較演算子を使用して次のようにします。

  • priorityプロパティ値の値をしきい値と比較して、優先順位の高いタスクを見つけます。どの優先順位を超えると、優先順位が高いと見なされます。

  • progressMinutesプロパティが特定の範囲内にあるかどうかを確認して、開始されたばかりのタスクまたは実行時間が短いタスクを見つけます。

  • assigneeプロパティが null に等しいタスクを見つけて、割り当てられていないタスクを見つけます。

  • assigneeプロパティが名前のリストにあるかどうかを確認して、特定のチームメイト エイリアスまたはレイテンシに割り当てられたタスクを見つけます。

RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class);
Log.i("EXAMPLE", "High priority tasks: " + tasksQuery.greaterThan("priority", 5).count());
Log.i("EXAMPLE", "Just-started or short tasks: " + tasksQuery.between("progressMinutes", 1, 10).count());
Log.i("EXAMPLE", "Unassigned tasks: " + tasksQuery.isNull("assignee").count());
Log.i("EXAMPLE", "Ali or Jamie's tasks: " + tasksQuery.in("assignee", new String[]{"Ali", "Jamie"}).count());
val tasksQuery = realm.where(ProjectTask::class.java)
Log.i(
"EXAMPLE", "High priority tasks: " + tasksQuery.greaterThan(
"priority",
5
).count()
)
Log.i(
"EXAMPLE", "Just-started or short tasks: " + tasksQuery.between(
"progressMinutes",
1,
10
).count()
)
Log.i(
"EXAMPLE",
"Unassigned tasks: " + tasksQuery.isNull("assignee").count()
)
Log.i(
"EXAMPLE", "Ali or Jamie's tasks: " + tasksQuery.`in`(
"assignee", arrayOf(
"Ali",
"Jamie"
)
).count()
)

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

Realm は、結果がソートされる場合にのみ、一貫した結果の順序を保証します。

次のコードは、プロジェクトを名前で逆アルファベット順にソートします(つまり 「降順」の順序)を超えるドキュメントを選択します。

RealmQuery<Project> projectsQuery = realm.where(Project.class);
RealmResults<Project> results = projectsQuery.sort("name", Sort.DESCENDING).findAll();
val projectsQuery = realm.where(Project::class.java)
val results = projectsQuery.sort("name", Sort.DESCENDING).findAll()

クラスHumanCatの次の関係を考慮します。 この配置により、各人間は 1 月のコレクションを所有することができます。

import org.bson.types.ObjectId;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
public class Human extends RealmObject {
@PrimaryKey
private ObjectId _id = new ObjectId();
private String name;
private Cat cat;
public Human(String name) {
this.name = name;
}
public Human() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public ObjectId get_id() {
return _id;
}
}
import org.bson.types.ObjectId;
import io.realm.RealmObject;
import io.realm.RealmResults;
import io.realm.annotations.LinkingObjects;
import io.realm.annotations.PrimaryKey;
public class Cat extends RealmObject {
@PrimaryKey
private ObjectId _id = new ObjectId();
private String name = null;
@LinkingObjects("cat")
private final RealmResults<Human> owner = null;
public Cat(String name) {
this.name = name;
}
public Cat() {
}
public ObjectId get_id() {
return _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public RealmResults<Human> getOwner() {
return owner;
}
}

この関係をクエリするには、クエリでドット表記を使用して、リンクされたオブジェクトの任意のプロパティにアクセスします。

SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION)
.allowQueriesOnUiThread(true)
.allowWritesOnUiThread(true)
.build();
Realm.getInstanceAsync(config, new Realm.Callback() {
@Override
public void onSuccess(Realm realm) {
Log.v(
"EXAMPLE",
"Successfully opened a realm with reads and writes allowed on the UI thread."
);
realm.executeTransaction(transactionRealm -> {
Human owner = transactionRealm.where(Human.class).equalTo("cat.name", "bucky").findFirst();
Cat cat = owner.getCat();
Log.v("EXAMPLE", "Queried for humans with cats named 'bucky'. Found " + owner.getName() + ", who owns " + cat.getName());
});
realm.close();
}
});

クラスPersonDogの次の関係を考慮します。 この配置により、各人は 1 台の犬を所有することができます。

import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import org.bson.types.ObjectId
open class Person(var name : String? = null) : RealmObject() {
@PrimaryKey
var _id : ObjectId = ObjectId()
var dog: Dog? = null
}
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey
import org.bson.types.ObjectId
open class Dog(var name : String? = null): RealmObject() {
@PrimaryKey
var _id : ObjectId = ObjectId()
@LinkingObjects("dog")
val owner: RealmResults<Person>? = null
}

この関係をクエリするには、クエリでドット表記を使用して、リンクされたオブジェクトの任意のプロパティにアクセスします。

val config = SyncConfiguration.Builder(app.currentUser(), PARTITION)
.allowQueriesOnUiThread(true)
.allowWritesOnUiThread(true)
.build()
Realm.getInstanceAsync(config, object : Realm.Callback() {
override fun onSuccess(realm: Realm) {
Log.v(
"EXAMPLE",
"Successfully opened a realm with reads and writes allowed on the UI thread."
)
realm.executeTransaction { transactionRealm ->
val owner = transactionRealm.where<Person>().equalTo("dog.name", "henry").findFirst()
val dog = owner?.dog
Log.v("EXAMPLE", "Queried for people with dogs named 'henry'. Found $owner, owner of $dog")
}
realm.close()
}
})

クラスCatHumanの次の関係を考慮します。 この例では、すべての環境は人間(または複数の人間オブジェクトが同じ月を参照する場合は複数の人間)にリンクします。 Realm は、 @LinkingObjectsアノテーションに指定されたフィールド名に基づいて、各コストの所有者を計算します。

import org.bson.types.ObjectId;
import io.realm.RealmObject;
import io.realm.RealmResults;
import io.realm.annotations.LinkingObjects;
import io.realm.annotations.PrimaryKey;
public class Cat extends RealmObject {
@PrimaryKey
private ObjectId _id = new ObjectId();
private String name = null;
@LinkingObjects("cat")
private final RealmResults<Human> owner = null;
public Cat(String name) {
this.name = name;
}
public Cat() {
}
public ObjectId get_id() {
return _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public RealmResults<Human> getOwner() {
return owner;
}
}
import org.bson.types.ObjectId;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
public class Human extends RealmObject {
@PrimaryKey
private ObjectId _id = new ObjectId();
private String name;
private Cat cat;
public Human(String name) {
this.name = name;
}
public Human() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public ObjectId get_id() {
return _id;
}
}

この関係をクエリするには、クエリでドット表記を使用して、リンクされたオブジェクトの任意のプロパティにアクセスします。

SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION)
.allowQueriesOnUiThread(true)
.allowWritesOnUiThread(true)
.build();
Realm.getInstanceAsync(config, new Realm.Callback() {
@Override
public void onSuccess(Realm realm) {
Log.v("EXAMPLE", "Successfully opened a realm.");
realm.executeTransaction(transactionRealm -> {
Cat cat = transactionRealm.where(Cat.class)
.equalTo("owner.name", "steven").findFirst();
Human owner = cat.getOwner().first();
Log.v("EXAMPLE", "Queried for cats with owners named 'steven'. Found " + cat.getName() + ", owned by " + owner.getName());
});
realm.close();
}
});

クラスDogPersonの次の関係を考慮します。 この例では、すべての犬が所有者(または複数の所有者が同じ犬を参照している場合は複数の所有者)にリンクします。 Realm は、 @LinkingObjectsアノテーションに指定されたフィールド名に基づいて、各犬の所有者を計算します。

import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey
import org.bson.types.ObjectId
open class Dog(var name : String? = null): RealmObject() {
@PrimaryKey
var _id : ObjectId = ObjectId()
@LinkingObjects("dog")
val owner: RealmResults<Person>? = null
}
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import org.bson.types.ObjectId
open class Person(var name : String? = null) : RealmObject() {
@PrimaryKey
var _id : ObjectId = ObjectId()
var dog: Dog? = null
}

この関係をクエリするには、クエリでドット表記を使用して、リンクされたオブジェクトの任意のプロパティにアクセスします。

val config = SyncConfiguration.Builder(app.currentUser(), PARTITION)
.allowQueriesOnUiThread(true)
.allowWritesOnUiThread(true)
.build()
Realm.getInstanceAsync(config, object : Realm.Callback() {
override fun onSuccess(realm: Realm) {
Log.v(
"EXAMPLE",
"Successfully opened a realm with reads and writes allowed on the UI thread."
)
realm.executeTransaction { transactionRealm ->
val dog = transactionRealm.where<Dog>()
.equalTo("owner.name", "dwayne").findFirst()
val owner = dog?.owner?.first()
Log.v("EXAMPLE", "Queried for dogs with owners named 'dwayne'. Found $dog, owned by $owner")
}
realm.close()
}
})
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class);
/*
Aggregate operators do not support dot-notation, so you
cannot directly operate on a property of all of the objects
in a collection property.
You can operate on a numeric property of the top-level
object, however:
*/
Log.i("EXAMPLE", "Tasks average priority: " + tasksQuery.average("priority"));
val tasksQuery = realm.where(ProjectTask::class.java)
/*
Aggregate operators do not support dot-notation, so you
cannot directly operate on a property of all of the objects
in a collection property.
You can operate on a numeric property of the top-level
object, however:
*/Log.i("EXAMPLE", "Tasks average priority: " + tasksQuery.average("priority"))

戻る

作成