CRUD - 読み取り - Flutter SDK
項目一覧
オブジェクトを検索、フィルタリング、ソートすることで、 データベースに保存したデータを読み取ることができます。
データベースからの読み取りには通常、次の手順で構成されます。
データベースから特定の型のすべてのオブジェクトを取得します。
必要に応じて、結果をフィルタリングします。
クエリ操作により返される結果コレクション の コレクション 。これらのコレクションはライブです。つまり、関連付けられたクエリの最新の結果が常に含まれています。
読み取り特性
これらの 3 つの主要な読み取り特性に関連するアプリのデータアクセス パターンを設計し、データをできるだけ効率的に読み取るようにします。
結果はコピーではない
クエリの結果はデータのコピーではない クエリの結果を変更すると、ディスク上のデータが直接変更されます。 このメモリ マッピングは、結果がライブであることも意味します。つまり、ディスクの現在の状態を常に反映します。
結果は遅延
SDK は、そのクエリの結果を実際に要求した場合にのみクエリを実行します。 この遅延評価により、大規模なデータセットや複雑なクエリを処理するための高パフォーマンスのコードを記述できます。 中間状態を処理するために追加の作業なしに、複数のフィルター操作を連鎖させることができます。
参照は保持されます
SDK のオブジェクトモデルの利点の 1 つは、SDK がオブジェクトのすべての関係を直接参照として自動的に保持することです。 これにより、クエリの結果から関係のグラフを直接走査できます。
直接参照(ポインター)を使用すると、参照を介して関連オブジェクトのプロパティに直接アクセスできます。
他のデータベースでは通常、オブジェクトを直接操作する必要がある場合、データベース ストレージからアプリケーション メモリにオブジェクトがコピーされます。 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. 参照されたオブジェクトをアプリケーション メモリにコピーすることを選択すると、アクセスされていないオブジェクトの多くのリソースを使用することができますが、外部キーのみをコピーすることを選択した場合は、参照されたオブジェクトの検索によってアプリケーションが遅くなる可能性があります。
SDK は、ゼロ コピーのライブ オブジェクトを使用して、これをすべてバイパスします。 SDK のオブジェクト アアクセスは、メモリ マッピングを使用してデータベース ストレージを直接指すため、データベース内のオブジェクトとアプリケーション メモリ内のクエリの結果を区別しません。 このため、どのクエリ結果からでもデータベース全体の直接参照を走査できます。
クエリ結果の制限
遅延評価の結果、SDK でクエリ結果を制限するために特別なメカニズムは必要ありません。 たとえば、クエリが数千のオブジェクトと一致するが、最初の 10 個のオブジェクトのみをロードする場合は、結果コレクションの最初の 10 個の要素のみにアクセスします。
ページ分割
遅延評価の代わりに、ページ区切りの一般的なタスクが非常に簡単になります。 たとえば、データベース内の数千のオブジェクトに一致するクエリに関連付けられた結果のコレクションがあるとします。 ページごとに 100 個のオブジェクトを表示します。 任意のページに進むには、ターゲット ページに対応するインデックスから、結果コレクションの要素にアクセスします。
オブジェクトの読み取り
特に指定がない限り、このページの例では Person
とTeam
の 2 つのオブジェクトタイプを使用します。
()class _Person { () late ObjectId id; late String name; late List<String> hobbies; } ()class _Team { () late ObjectId id; late String name; late List<_Person> crew; late RealmValue eventLog; }
プライマリキーによるオブジェクトの検索
Realm.find() を使用して、プライマリキーでオブジェクトを検索します。
final luke = realm.find<Person>(lukePrimaryKey);
すべてのオブジェクトのクエリ
Realm.all() メソッド を使用して、 データベース内のデータモデルのすべてのオブジェクトのコレクションを検索します使用して複数のドキュメントを挿入できます。
final people = realm.all<Person>();
クエリ関連オブジェクト
バージョン 1.8.0 の新機能。
データモデルに他のオブジェクトを参照するオブジェクトが含まれている場合は、 getBacklinks() メソッド を使用して 関係 をクエリできます 使用して複数のドキュメントを挿入できます。
このメソッドは 結果のコレクションを 返します 対 1、対多、または逆の関係で指定されたオブジェクトにリンクするすべてのオブジェクトの 。次の例では、関係ページで定義されたモデルを使用します。
対 1 の関係:この例では、
Person
オブジェクトと 1 の関係を持つBike
オブジェクトモデルがあります。getBacklinks()
メソッドを使用して、owner
プロパティを通じて指定されたユーザーにリンクするBike
オブジェクトを検索します。// Persons have a to-one relationship with Bikes final person = realm.query<Person>("firstName == 'Anakin'").first; // Find all Bikes owned by a Person named 'Anakin' final allBikes = person.getBacklinks<Bike>('owner'); 対多の関係:この例では、
ScooterShop
オブジェクトとの対多関係を持つScooter
オブジェクトモデルがあります。getBacklinks()
メソッドを使用して、scooters
リスト プロパティから指定されたスクーターにリンクするScooterShops
オブジェクトを検索します。// Scooters have a to-many relationship with ScooterShops final scooters = realm.query<Scooter>("name == 'Scooterbug'").first; // Find all ScooterShops with a Scooter named 'Scooterbug' final shops = scooters.getBacklinks<ScooterShop>('scooters'); 逆の関係:この例では、
User
オブジェクトと逆の関係を持つTask
オブジェクトモデルがあります。getBacklinks()
メソッドを使用して、tasks
バックリンク プロパティを介して指定されたタスクにリンクするUser
オブジェクトを検索します。// Tasks have an inverse relationship to Users final inCompleteTasks = realm.query<Task>("isComplete == false"); // Find all Users who have an incomplete Task for (final task in inCompleteTasks) { final ownersWithIncompleteTasks = task.getBacklinks<User>('tasks'); for (final user in ownersWithIncompleteTasks) { print("User ${user.username} has incomplete tasks."); } }
クエリ リスト
RealmObject の任意のリストをクエリできます または プリミティブ。
final config = Configuration.local([Person.schema, Team.schema]); final realm = Realm(config); final heroes = Team(ObjectId(), 'Millenium Falcon Crew', crew: [ Person(ObjectId(), 'Luke'), Person(ObjectId(), 'Leia'), Person(ObjectId(), 'Han'), Person(ObjectId(), 'Chewbacca') ]); realm.write(() => realm.add(heroes)); final lukeAndLeia = heroes.crew.query('name BEGINSWITH \$0', ['L']);
混合データのネストされたコレクションのクエリ
バージョン2.0.0の新機能。
Flutter SDK v 2.0.0以降では、 RealmValueプロパティに混合データのコレクション(リストまたはマップ)を含めることができます。 これらのコレクションはコレクション内にネストでき、混合データの他のコレクションを含めることができます。
これらは、通常のリストまたは辞書コレクションと同じ構文を使用してクエリできます。 を参照しますサポートされている演算子とリスト比較の詳細については、ドキュメントを参照してください。
ネストされたコレクションの場合は、次のコレクションも使用できます。
括弧表記。次のコレクションクエリ演算子を提供します。
[FIRST]
および [LAST
]: コレクション内の最初または最後の要素と一致します。[<int>]
: 特定のインデックスの要素と一致する。[*]
: コレクション内の任意の要素と一致します(この演算子は、そのパスにあるコレクション タイプを想定しています)。[SIZE]
: コレクションの長さに一致します。
次の値をサポートする
@type
演算子。array
およびlist
: リスト コレクションに一致します。dictionary
およびobject
: マップ コレクションに一致します。collection
: リストまたはマップ コレクションに一致します。
realm.write(() { realm.addAll([ (Team(ObjectId(), 'Janitorial Staff', eventLog: RealmValue.from({ '1': { 'date': DateTime.utc(5622, 8, 18, 12, 30, 0), 'type': ['work_order', 'maintenance'], 'summary': 'leaking pipes in control room', 'priority': 'high', }, '2': { 'date': DateTime.utc(5622, 9, 18, 12, 30, 0), 'type': ['maintenance'], 'summary': 'trash compactor jammed', 'priority': 'low', 'comment': 'this is the second time this week' } }))), (Team(ObjectId(), 'IT', eventLog: RealmValue.from({ '1': { 'date': DateTime.utc(5622, 9, 20, 12, 30, 0), 'type': ['hardware', 'repair'], 'summary': 'lightsaber damage to server room', 'priority': 'high', } }))) ]); final teams = realm.all<Team>(); // Use bracket notation to query collection values at the specified path final teamsWithHighPriorityEvents = // Check any element at that path with [*] teams.query("eventLog[*].priority == 'high'"); print(teamsWithHighPriorityEvents.length); // prints `2` final teamsWithMaintenanceEvents = // Check for the first element at that path with [FIRST] teams.query("eventLog[*].type[FIRST] == 'maintenance'"); print(teamsWithMaintenanceEvents.length); // prints `1` final teamsWithMultipleEvents = // Check for collection at that path with matching elements // Note that the order must match unless you use ANY or ALL teams.query("eventLog[*].type[*] == {'maintenance', 'work_order'}"); print( teamsWithMultipleEvents.length); // prints `0` because order matters final teamsWithEventsAsLists = // Check the collection type with @type teams.query("eventLog[*].type.@type == 'list'"); print(teamsWithEventsAsLists.length); // prints `2` });
リストまたはセットの結果への変換
それぞれの方法を使用して、 RealmList
またはRealmSet
をRealmResults
のインスタンスに変換できます。
これらのメソッドは、 RealmObjects
のリストとセット、およびプリミティブ値をサポートします。
final config = Configuration.local([Person.schema, Team.schema]); final realm = Realm(config); final heroes = Team(ObjectId(), 'Millenium Falcon Crew', crew: [ Person(ObjectId(), 'Luke', hobbies: [ 'Going to Tashi Station', 'Fixing the Moisture Vaporators' ]), Person(ObjectId(), 'Leia', hobbies: [ 'Going on diplomatic missions', 'Rescuing short stormtroopers' ]), Person(ObjectId(), 'Han', hobbies: ['Shooting first', 'Making fast Kessel Runs']), Person(ObjectId(), 'Chewbacca', hobbies: [ 'Fixing the Millenium Falcon', 'Tearing the arms off of droids' ]) ]); realm.write(() => realm.add(heroes)); // Converts the Team object's 'crew' List into a RealmResults<Person>. final heroesCrewAsResults = heroes.crew.asResults(); final luke = heroesCrewAsResults.query("name == 'Luke'").first; // Converts Luke's 'hobbies' list into a RealmResults<String> final lukeHobbiesAsResults = luke.hobbies.asResults();
結果のフィルタリング
RealmList
Realm.query() でオブジェクトの特定のセグメントを取得するには、 をフィルタリングします。使用して複数のドキュメントを挿入できます。 query()
メソッドの引数では、 RQLを使用してフィルタリングを実行します。 RQLは、データベースからオブジェクトを検索するために使用できる string ベースのクエリ言語です。
final team = realm.query<Team>('name == \$0', ['Millennium Falcon Crew']).first; final humanCrewMembers = team.crew.query('name != \$0', ['Chewbacca']);
フィルターでは反復可能な引数を使用できます。 例:
final listOfNames = ['Luke', 'Leia']; final matchingRealmObjects = realm.query<Person>('name IN \$0', [listOfNames]);
フィルター逆関係
@links.<Type>.<Property>
構文を使用して、逆の関係でフィルタリングすることもできます。 たとえば、フィルターは、それを参照するUser
オブジェクトのプロパティに基づいて、 Task
オブジェクトと一致させることができます。
// Filter Tasks through the User's backlink property // using `@links.<ObjectType>.<PropertyName>` syntax final jarjarsIncompleteTasks = realm.query<Task>( "ALL @links.User.tasks.username == 'jarjar_binks' AND isComplete == false"); final tasksForHan = realm.query<Task>("ALL @links.User.tasks.username == 'han'");
クエリの構築の詳細については、 RQLに関する参考ドキュメント を参照してください。
全文検索でフィルタリング
RQL ( RQL )を使用して、全文検索インデックス(FTS)注釈を持つプロパティをクエリできます。 これらのプロパティをクエリするには、クエリでTEXT
述語を使用します。
単語の前に-
文字を付けて、単語の結果を除外します。 たとえば、 -sheep wool
を検索すると、 sheep
を持つ検索結果を除くwool
のすべての検索結果が含まれます。
Flutter SDK バージョン 1.6.0 以降では、単語の末尾に*
文字を配置することでプレフィックスを指定できます。 たとえば、 wo*
にはwool
とwoven
のすべての検索結果が含まれます。 Flutter SDK は現在、サフィックス検索をサポートしていません。
次の例では、 フィールドと フィールドをクエリします。Rug.pattern
Rug.material
// Find rugs with a chevron pattern final chevronRugs = realm.query<Rug>("pattern TEXT \$0", ["chevron"]); // Find rugs with a wool material but not sheep wool final notSheepWoolRugs = realm.query<Rug>("material TEXT \$0", [" -sheep wool"]); // Find rugs with a material starting with "co-" final coRugs = realm.query<Rug>("material TEXT \$0", ["co*"]);
全文検索トークナイザの詳細
全文検索(FTS)インデックスは以下をサポートします。
ブール値一致単語検索。関連性検索ではありません。
トークンは、発音区別符号を区別せず、大文字と小文字を区別しません。
トークンは、ASCII と Atlas 1 の追加文字(西部言語)のみで構成できます。
他のすべての文字は空白と見なされます。 全文のようにハイフン(-)で区切られた単語は、2 つのトークンに分割されます。
FTS インデックスの機能の詳細については、 RealmIndexType の API リファレンスを参照してください。
結果を並べ替える
query()
メソッドの 引数でRQL SORT() 演算子を使用してクエリ結果を並べ替えます。
RQL SORT() 句では、パラメータ付きのクエリは使用できないことに注意してください。 代わりに、string または string 補間を使用してください。
realm.write(() { realm.addAll([ Person(ObjectId(), 'Luke'), Person(ObjectId(), 'Leia'), Person(ObjectId(), 'Han'), Person(ObjectId(), 'Chewbacca') ]); }); final alphabetizedPeople = realm.query<Person>('TRUEPREDICATE SORT(name ASC)'); for (var person in alphabetizedPeople) { print(person.name); } // prints 'Chewbacca', 'Han', 'Leia', 'Luke'
結果を制限する
query()
メソッドの 引数でRQL ()演算子を使用してクエリ結果を制限します。
RQL LIT()句では、パラメータ付きのクエリは使用できないことに注意してください。 代わりに、string または string 補間を使用してください。
realm.write(() { realm.addAll([ Person(ObjectId(), 'Luke'), Person(ObjectId(), 'Luke'), Person(ObjectId(), 'Luke'), Person(ObjectId(), 'Luke') ]); }); final limitedPeopleResults = realm.query<Person>('name == \$0 LIMIT(2)', ['Luke']); // prints `2` print(limitedPeopleResults.length);