Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

同期サブスクリプションの管理 - Flutter SDK

項目一覧

  • 前提条件
  • バックエンド アプリによるサブスクリプションの整合性
  • クエリにサブスクライブ
  • クエリにサブスクライブ
  • クエリ サブスクリプションが同期するまで待機する
  • クエリからのサブスクライブの解除
  • サブスクリプションの手動管理
  • サブスクリプションを取得する
  • サブスクリプションのセットへのクエリの追加
  • 新しいクエリによるサブスクリプションの更新
  • サブスクリプションの削除
  • サブスクリプションの変更が同期されるまで待機する
  • サブスクリプション状態
  • Flexible Sync RQL の要件と制限
  • インデックス付きクエリ可能なフィールドのサブスクリプション要件
  • Flexible Sync でサポートされていないクエリ演算子
  • クエリをリストする
  • 埋め込みオブジェクトまたはリンクされたオブジェクト
  • クエリ サイズの制限
  • パフォーマンスに関する考慮事項
  • API 効率
  • パフォーマンス向上のためのグループ更新

Atlas Device Sync と Flexible Sync は、サブスクリプションと権限を使用して、Atlas とアプリ間で同期するデータを決定します。

クエリ サブスクライブを追加、更新、削除して、クライアント デバイスに同期するデータを決定できます。

注意

Flexible Sync の前提条件

アプリで Flexible Sync を有効にするには、 MongoDB 5.0以上を実行中のシャーディングされていない Atlas クラスターが必要です。

Flutter アプリケーションで Flexible Sync を使用するには、次の手順に従います。

  1. Atlas App Services バックエンドでの Flexible Sync の構成

  2. アプリ クライアントを初期化

  3. クライアントでユーザーを認証する

  4. 同期された Realmをクライアントで開きます

クライアント側のサブスクリプション クエリは、バックエンド App Services App の Device Sync 構成と一致する必要があります。

サブスクライブ クエリは、次のいずれかになります。

バージョン v1.6.0 の新機能

Flutter v1.6.0 では、クエリの結果にサブスクライブしたり、サブスクライブを解除したりする実験的な API が追加されています。 これらの API では、サブスクリプションの手動追加と削除の詳細は抽象化されます。

すべてのサブスクライブでは、認証されたユーザー同期された Realm が必要です。

パフォーマンスの最適化やビジネス ロジック上の理由でサブスクライブをより制御する必要がある場合は、 subscriptions API を使用してサブスクリプションセットを手動で管理できます。 詳細については、このページの「パフォーマンスに関する考慮事項」セクションを参照してください。

サブスクライブ() メソッドを使用してクエリの をサブスクライブできますRealmResults 使用して複数のドキュメントを挿入できます。呼び出されると、SDK は新しいサブスクリプションを作成し、 MutableSubscriptionSetに追加します。これは、サブスクリプションを手動で作成するのと同様です。

オプションで、クエリに一意のサブスクリプション名を渡すことができます。 既存のサブスクライブと同じ名前のサブスクリプションを追加すると、SDK は既存のサブスクライブを上書きします。

サブスクリプション名を渡さない場合、名前は null に設定され、サブスクライブ識別子はクエリstringに基づいて作成されます。 つまり、クエリstringが変更されるたびに、subscribe() は新しいサブスクリプションを作成します。

クエリをサブスクライブするには、次の引数をsubscribe()に渡します。

  • RealmResults query: 必須。 RQLを使用して作成できる RealmResults オブジェクト。

  • String name: 任意。 参照できるサブスクライブの名前。

  • bool update: 任意。 true の場合、既存の名前でサブスクリプションを追加すると、既存のクエリが新しいクエリに置き換えられます。 false の場合、SDK は重複するサブスクライブの例外をスローします。 名前付きサブスクリプションでのみ使用します。

次の例では、2 つの新しい名前付きクエリをサブスクライブしています。

final boatQuery = realm.all<Boat>();
final bigPlaneQuery = realm.query<Plane>("numSeats > 100");
final boatSubscription = await boatQuery.subscribe(name: "boats");
final planeSubscription =
await bigPlaneQuery.subscribe(name: "big-planes");

Tip

サブスクリプション名の指定

特にアプリケーションで複数のサブスクライブを使用する場合は、常にサブスクリプション名を指定することをお勧めします。 これにより、サブスクライブを見つけて管理しやすくなります。

クエリの結果をサブスクライブする場合、同期されたデータがダウンロードされるまで、その結果にはオブジェクトが含まれません。 同期されたオブジェクトのダウンロードが完了するまで待機する必要がある場合は、 waitForSyncMode を構成します オプションを使用します。

この例では、デフォルトの動作であるfirstTimeオプションを使用しています。 firstTime動作のサブスクライブは、サブスクリプションが最初に作成されたときにのみ同期が完了することを待機します。

final bigPlaneQuery = realm.query<Plane>("numSeats > 100");
final planeSubscription = await bigPlaneQuery.subscribe(
name: "firstTimeSync",
waitForSyncMode: WaitForSyncMode.firstTime,
);

サポートされているその他のwaitForSyncModeオプションは次のとおりです。

  • always: アプリを起動するたびに一致するオブジェクトをダウンロードするまで待機します。 アプリは起動時にインターネットに接続する必要があります。

  • never: 一致するオブジェクトがダウンロードされるのを待たない。 アプリは、アプリが初めて起動するときにユーザーが認証するためにインターネット接続を必要としますが、キャッシュされた認証情報を使用して以降の起動ではオフラインで開くことができます。

オプションで、 CancelToken を指定できます 同期ダウンロードの実行時間を制限するには、以下の手順を行います。

final bigPlaneQuery = realm.query<Plane>("numSeats > 200");
final planeSubscription = await bigPlaneQuery.subscribe(
name: "alwaysWaitSync",
waitForSyncMode: WaitForSyncMode.always,
cancellationToken: TimeoutCancellationToken(Duration(seconds: 5)),
);

サブスクリプションは、サブスクライブを解除しない限り、ユーザー セッション間で保持されます。 unsubscribe() を使用して、クエリの結果からサブスクライブを解除できます。

これにより、 サブスクリプションを手動で削除すると同様に、アクティブなサブスクリプションのリストからサブスクリプションが削除されます。 重複するオブジェクトを含む別のサブスクライブが存在する場合は、 unsubscribe()を呼び出した後も結果リストにオブジェクトが含まれる可能性があることに注意してください。

クエリでunsubscribe()を呼び出すと、SDK はunsubscribe()を呼び出したクエリと完全に一致するクエリを持つサブスクライブを削除します。 このメソッドは、削除されたサブスクリプションに一致するオブジェクトが Realm から削除される前にを返します。 新しいサブスクライブセットに基づいて、同期はバックグラウンドで続行されます。

planeQuery.unsubscribe();
trainQuery.unsubscribe();

バックエンドで Flexible Sync を構成するときは、クライアント アプリケーションがクエリできるフィールドを指定します。 クライアント アプリケーションで、 Realm.subscriptions を使用しますプロパティを使用して、クエリ可能なフィールドに対する特定のクエリへのサブスクリプションのセットを管理します。

サブスクライブでは、次のことが可能です。

  • すべてのサブスクライブの一覧を取得する

  • サブスクライブを追加する

  • サブスクリプション状態の確認

  • 新しいクエリでサブスクライブを更新する

  • サブスクライブを削除する

データがサブスクリプションと一致し、認証されたユーザーに適切な権限がある場合、Device Sync はバックエンド データをクライアント アプリと同期します。

コードにサブスクリプションを含めなくなった場合でも、セッション全体のサブスクリプションセットは保持されます。 サブスクリプション情報は、同期された Realm のデータベース ファイルに保存されます。 一致するデータの同期を停止するには、サブスクライブを明示的に削除する必要があります。

サブスクライブの string 名を指定できます。 サブスクリプションに名前を付けない場合、名前はnullに設定されます。

サブスクリプションを作成すると、Realm は特定のオブジェクトタイプに対するクエリに一致するデータを検索します。 Flexible Sync サブスクライブでは、複数の異なるオブジェクトタイプに対するサブスクライブまたは同じオブジェクトタイプに対する複数のクエリを持つことができます。

Flexible Sync を使用する場合、 SubscriptionSet にアクセスできます (サブスクライブのコレクション)、 プロパティを通じてのRealm.subscriptions

以下の例に示すように、このサブスクリプションセットを使用して、このサブスクリプションのリストにクエリを追加したり、既存のサブスクライブを更新したりできます。

final subscriptions = realm.subscriptions;

アップデート ブロック内に設定されたサブスクライブに対してすべてのミューテーションを実行する必要があります。 更新 ブロックを作成するには、 SubscriptionSet.update() を呼び出します。

アップデート ブロック コールバック 関数には MutableSubscriptionSet() オブジェクトを引数として指定します。SubscriptionSetのメソッドを変更して、サブスクライブにクエリを追加できます。

重要

Flexible SyncはRQLで利用可能なすべての演算子をサポートしていません。 詳細については、「 Flexible Sync RQL の制限」を参照してください。

MutableSubscriptionSet.add()メソッドは 3 つの引数を取ります。

  • RealmResults query: 必須。 RQLクエリを使用して作成できる RealmResults オブジェクト。

  • String name: 任意。 参照できるサブスクライブの名前。

  • bool update: 任意。 true の場合、既存の名前でサブスクリプションを追加すると、既存のクエリが新しいクエリに置き換えられます。 名前付きサブスクリプションでのみ使用します。

注意

重複するサブスクリプション

同じクエリで重複する 名前のない サブスクリプションを追加すると、Realm はそれを自動的に削除します。同一の 名前 付きサブスクリプションを追加しても何も操作はあり ません 。したがって、どちらの場合も、重複するサブスクライブは無視されます。

単一のクエリを追加することも、 SubscriptionSet.updateブロック内に複数のクエリをバッチすることもできます。 クエリ更新の実行は、サーバーに対してコストのかかる操作です。 サブスクリプションの更新を最小限に抑えるようにアプリケーションを設計することを強くお勧めします。 そのためには、ユーザーが初めてアプリを起動し、サブスクライブ セットに対するその後の変更をバッチすることで、1 回の更新ブロックですべてのサブスクリプションを作成できます。

以下の例では、2 つのクエリをサブスクライブしています。

final planeQuery = realm.all<Plane>();
final longTrainQuery = realm.query<Train>("numCars >= 5");
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.add(planeQuery, name: "planes");
mutableSubscriptions.add(longTrainQuery,
name: 'long-trains', update: true);
});
await realm.subscriptions.waitForSynchronization();

新しいクエリを使用して 名前付きサブスクライブ を更新できます。 サブスクライブのクエリを更新するには、 SubscriptionSet.update()を使用して更新ブロックを開きます。 アップデート ブロックのコールバック 関数で、次の引数をMutableSubscriptionSet.add()に渡します。

  • 新しいクエリ

  • 更新するサブスクライブの名前

  • update: true

名前のないサブスクライブを更新することはできません。 あるいは、名前のないサブスクリプションを削除し、目的のクエリで新しいサブスクリプションを作成することもできます。

次の例では、長い列は、車両が 10 台を超えるドキュメントであるように再定義されています。

final longerTrainQuery = realm.query<Train>("numCars > 10");
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.add(longerTrainQuery,
name: 'long-trains', update: true);
});

サブスクリプションセットからサブスクリプションを削除するには、次の操作を実行します。

  • 指定されたクエリを使用して単一のサブスクライブを削除

  • 指定された名前の単一のサブスクライブを削除

  • サブスクリプション参照を使用して単一のサブスクライブを削除

  • Realm オブジェクトタイプのすべてのサブスクライブを削除

  • すべてのサブスクライブを削除

サブスクリプション クエリを削除すると、サーバーはクライアント デバイスから同期されたデータも削除します。

更新ブロック内では、クエリによって特定のサブスクリプションを削除できます。 SubscriptionSet.update()を使用してアップデート ブロックを開きます。 Subscription MutableSubscriptionSet.removeByQuery() に渡します。

次の例では、すべてのPlaneオブジェクトのサブスクリプションが削除されています。

realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.removeByQuery(realm.all<Plane>());
});

更新ブロック内では、名前を使用して特定のサブスクリプションを削除できます。 名前を MutableSubscriptionSet.removeByName() に渡す

realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.removeByName('long-trains');
});

サブスクリプション への参照がある場合は、サブスクライブを削除できます オブジェクト。サブスクライブ更新ブロック内で、Subscription 参照を MutableSubscriptionSet.remove() に渡します。

final sub = realm.subscriptions[0];
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.remove(sub);
});

特定の Realm オブジェクトタイプのすべてのサブスクリプションを削除できます。 サブスクリプション更新ブロック内で、 MutableSubscriptionSet.removeByType() を呼び出します。

realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.removeByType<Train>();
});

サブスクリプション更新ブロック内で、 MutableSubscriptionSet.client() を使用してサブスクリプションセットから名前のないすべてのサブスクリプションを削除できます。

realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.clear();
});

アップデート ブロック内でサブスクリプションセットをミューテーションすることは、サブスクリプション変更の一部に相当します。 ローカル サブスクリプションの変更後、Realm はサーバーと同期して、サブスクリプションの変更によるデータの更新を解決します。 これには、同期された Realm からのデータの追加または削除が含まれます。

Realm.subscriptions.waitForSynchronization() の 使用サーバーがこのサブスクライブ セットを確認するまで待機します。 サーバーが変更を拒否した場合、 と の例外がスローされます。

次の場合、例外が発生する可能性があります。

  • サポートされていないクエリにサブスクライブした場合。 サポートされていないクエリをサブスクライブすると、同期が一時停止されます。 同期を再開するには、サポートされていないクエリを削除します。

  • サブスクライブに一致しないオブジェクトの追加など、無効なアクションを実行している。 これにより、クライアント リセットがトリガーされます。データが Realm から削除され、セット内にサブスクライブなしでデータの新しいコピーが作成されます。

await realm.subscriptions.waitForSynchronization();

Realm.subscriptions . State を使用する プロパティを使用して、サブスクライブ セットの現在の状態を読み取ります。

superseded状態は SubscriptionSetState これは、サブスクライブセットの別のインスタンスで別のスレッドがサブスクリプションを更新したときに発生する可能性があります。状態がsupersededになった場合は、更新する前にサブスクライブセットの新しいインスタンスを取得する必要があります。

注意

サブスクリプション状態「完了」

サブスクリプションセットの状態「完了」は、「同期が実行された」または「すべてのドキュメントが同期された」を意味するものではありません。 「完了」とは、次の 2 つの処理が発生したことを意味します。

  • サブスクライブは、現在サーバーと同期されているアクティブなサブスクリプションセットになりました。

  • サブスクリプションがサーバーに送信されたときにサブスクリプションに一致したドキュメントは、現在、ローカルデバイス上にあります。 これには、現在サブスクリプションに一致しているすべてのドキュメントが必ずしも含まれるわけではないことに注意してください。

Realm SDK には、サブスクリプションに一致するすべてのドキュメントがデバイスに同期されているかどうかを確認する方法は提供されていません。

インデックス付きのクエリ可能なフィールドをアプリに追加すると、厳密にパーティション化されたデータに対する単純なクエリのパフォーマンスが向上します。 たとえば、クエリがデバイス、ストア、またはユーザーにデータを厳密にマッピングするアプリuser_id == $0, “641374b03725038381d2e1fb”など)は、インデックス付きクエリ可能なフィールドの候補となります。 ただし、インデックス付きのクエリ可能なフィールドには、クエリ サブスクリプションで使用するための特定の要件があります。

  • インデックス付きクエリ可能なフィールドは、すべてのサブスクライブ クエリで使用する必要があります。 クエリから欠落することはできません。

  • インデックス付きクエリ可能なフィールドは、サブスクライブ クエリで少なくとも 1 回、定数に対して==またはINの比較を使用する必要があります。 たとえば、 user_id == $0, "641374b03725038381d2e1fb"store_id IN $0, {1,2,3}などです。

オプションとして、インデックス付きクエリ可能なフィールドが==またはINを少なくとも 1 回使用して定数と直接比較される限り、 AND比較を含めることができます。 たとえば、 store_id IN {1,2,3} AND region=="Northeast"store_id == 1 AND (active_promotions < 5 OR num_employees < 10)などです。

インデックス付きクエリ可能なフィールドに対する無効なFlexible Sync クエリには、次のクエリが含まれます。

  • インデックス付きクエリ可能なフィールドは、クエリの残りの部分でANDを使用しません。 store_id IN {1,2,3} OR region=="Northeast"ORたとえば、AND は ではなく を使用しているため無効です。同様に、 store_id == 1 AND active_promotions < 5 OR num_employees < 10は無効です。 ANDはクエリ全体ではなく、その横にあるタームにのみ適用されるためです。

  • インデックス付きクエリ可能なフィールドは 等価演算子 では使用されません。 たとえば、 store_id > 2 AND region=="Northeast"は無効です。インデックス付きクエリ可能なフィールドでは>演算子のみが使用され、等価比較がないためです。

  • クエリに、インデックス付きのクエリ可能なフィールドが完全にありません。 たとえば、 region=="Northeastまたはtruepredicateは、インデックス付きクエリ可能なフィールドが含まれていないため無効です。

RQL 演算子を使用する場合、Flexible Sync にはいくつかの制限があります。 同期するデータを決定するクエリ サブスクリプションを書込む場合、サーバーはこれらのクエリ演算子をサポートしていません。 ただし、RQL 機能の全範囲を使用して、クライアント アプリケーション内の同期されたデータセットをクエリすることはできます。

演算子タイプ
サポートされていない演算子
集計演算子
@avg, @count, @max, @min, @sum
クエリサフィックス
DISTINCT, SORT, LIMIT

大文字と小文字を区別しないクエリ( [c] )は、インデックスを効果的に使用できません。 その結果、大文字と小文字を区別しないクエリはパフォーマンスの問題を引き起こす可能性があるため、推奨されません。

Flexible Sync は、配列フィールドの@countのみをサポートします。

Flexible Sync は、 IN演算子を使用するクエリ リストをサポートしています。

定数のリストをクエリして、クエリ可能なフィールドの値が含まれているかどうかを確認できます。

// Query a constant list for a queryable field value
"priority IN { 1, 2, 3 }"

クエリ可能なフィールドに配列値がある場合は、定数値が含まれているかどうかをクエリできます。

// Query an array-valued queryable field for a constant value
"'comedy' IN genres"

警告

Flexible Sync クエリでは、2 つのリストを相互に比較することはできません。 RQLこれはFlexible Sync クエリの外部では有効な 構文であることに注意してください。

// Invalid Flexible Sync query. Do not do this!
"{'comedy', 'horror', 'suspense'} IN genres"
// Another invalid Flexible Sync query. Do not do this!
"ANY {'comedy', 'horror', 'suspense'} != ANY genres"

Flexible Sync は、 埋め込みオブジェクトまたはリンク のプロパティに対するクエリをサポートしていません。 たとえば、 obj1.field == "foo"

サブスクリプションセット内の特定のクエリ サブスクライブのサイズ制限256 kBです。 この制限を超えると、 LimitsExceeded エラー が発生します。

クエリへのサブスクライブ」セクションで説明されている.subscribe() API を使用して複数のサブスクリプションを管理する場合、 サブスクリプション セット API を通じてサブスクリプションを手動で管理する場合、バッチ更新を実行するより効率が低くなります。 複数のサブスクリプション変更を行う際のパフォーマンスを向上させるには、「サブスクリプションの手動管理」セクションで説明されているsubscriptions.update API を使用します。

サブスクリプションセットのすべての書込みトランザクション (write transaction) にはパフォーマンス コストがかかります。 セッション中に Realm オブジェクトを複数更新する必要がある場合は、すべての変更が完了するまで編集されたオブジェクトをメモリ内に保持することを検討してください。 これにより、すべての変更ではなく、完全で更新されたオブジェクトのみが Realm に書き込まれるため、同期のパフォーマンスが向上します。

戻る

同期された Realm を開く