同期サブスクリプションの管理 - Node.js SDK
項目一覧
- 前提条件
- クエリにサブスクライブ
- クエリにサブスクライブ
- サブスクリプション名なしのクエリへのサブスクライブ
- クエリ サブスクリプションが同期するまで待機する
- クエリからのサブスクライブの解除
- サブスクリプションの手動管理
- すべてのサブスクリプションを取得する
- サブスクリプションを追加する
- 初期サブスクリプションの設定
- サブスクリプションのステータスを確認
- サブスクリプション状態「完了」
- 新しいクエリによるサブスクリプションの更新
- サブスクリプションの削除
- クエリによるサブスクリプションの削除
- 名前を使用してサブスクリプションを削除
- 参照によるサブスクリプションの削除
- オブジェクト タイプへのすべてのサブスクリプションを削除
- すべての名前のないサブスクリプションを削除
- すべてのサブスクリプションを削除
- パフォーマンスに関する考慮事項
- API 効率
- パフォーマンス向上のためのグループ更新
- Flexible Sync RQL の要件と制限
- インデックス付きクエリ可能なフィールドのサブスクリプション要件
- Flexible Sync でサポートされていないクエリ演算子
- クエリをリストする
- 埋め込みオブジェクトまたはリンクされたオブジェクト
- クエリ サイズの制限
Flexible Sync は、サブスクリプションと権限を使用して、アプリと同期するデータを決定します。 Flexible Sync が有効になっているRealmから読み取りまたは書込みを行う前に、少なくとも 1 つのサブスクリプションが必要です。 このページでは、これらのサブスクライブを管理する方法について詳しく説明します。
クエリ サブスクリプションを追加、更新、削除して、クライアント デバイスに同期するデータを制御できます。 Realm Node.js SDK v12.0.0 以降では、サブスクリプションを手動で管理するだけでなく、 の代わりに、または クエリをサブスクライブできます。
Data Ingestおよび非対称オブジェクトのサブスクリプションは作成できません。これらはアプリのバックエンドにのみデータを送信するためです。
重要
Flexible Sync クエリの制限
Flexible Sync サブスクライブは、 RQL クエリ演算子のサブセットのみをサポートします。 どの演算子がサポートされていないかについては、「 Flexible Sync RQLの制限 」のドキュメントを参照してください。
前提条件
Node.js SDK で Atlas Device Sync を使用する前に、次の要件を満たしている必要があります。
要件に加えて、Node.js クライアントで Flexible Sync を使用するには以下を設定する必要があります。
クエリにサブスクライブ
バージョン 12.0.0 の新機能。
Realm Node.js v12.0.0 adds experimental APIs that subscribe to and unsubscribe from a query's results. これらの API では、サブスクリプションの手動追加と削除の詳細は抽象化されます。
すべてのサブスクライブでは、認証されたユーザーとFlexible Sync レルムが必要です。
バージョン 12.3.0 での変更: Atlas Device Sync でサポートされている地理空間データ
Realm Node.js SDK v12.3.0以降では、地理空間クエリのサブスクリプションを作成できます。 古いバージョンの SDK で地理空間クエリをサブスクライブしようとすると、書き込み補正によるサーバー エラーが発生します。
詳細については、「地理空間データのクエリ 」を参照してください。
クエリにサブスクライブ
サブスクリプションに名前を付けることをお勧めします。 これにより、サブスクライブを見つけて管理しやすくなります。 サブスクリプション名は一意である必要があります。 既存のサブスクリプションと同じ名前のサブスクリプションを追加しようとすると、エラーがスローされます。
クエリをサブスクライブするには、次の手順に従います。
読み取りおよび書込みを対象とするオブジェクトのクエリ。
クエリ結果に対して
subscribe()
を呼び出して、クエリに一致するオブジェクトの同期サブスクリプションを作成します。name
プロパティを含むSubscriptionOptions
オブジェクトをsubscribe()
に渡します。
const subOptions = { name: "All completed tasks", }; const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe(subOptions); const completedTasksSubscription = realm.subscriptions.findByName( "All completed tasks" ); // ...work with the subscribed results list or modify the subscription
const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe({ name: "All completed tasks" }); const completedTasksSubscription = realm.subscriptions.findByName( "All completed tasks" ); // ...work with the subscribed results list or modify the subscription
サブスクリプション名なしのクエリへのサブスクライブ
ほとんどの場合、サブスクライブに名前を付ける必要があります。 含めない場合、名前は null に設定されます。
名前なしのクエリ サブスクライブでfiltered()
を使用する場合、サブスクリプション識別子はfiltered
クエリに基づきます。 つまり、クエリstringが変更されるたびに、subscribe()
は新しいサブスクリプションを作成します。
const config = { schema: [Task], sync: { user: app.currentUser, flexible: true, }, }; const realm = await Realm.open(config); const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe(); // ...work with the subscribed results list
const config: Realm.Configuration = { schema: [Task], sync: { user: app.currentUser!, flexible: true, }, }; const realm = await Realm.open(config); const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe(); // ...work with the subscribed results list
クエリ サブスクリプションが同期するまで待機する
クエリの結果をサブスクライブする場合、同期されたデータがダウンロードされるまで、その結果にはオブジェクトが含まれません。 同期されたオブジェクトのダウンロードが完了するまで待機する必要がある場合は、 waitForSync
を使用します。 サブスクリプションとダウンロードのを処理する方法によって異なる動作を指定できます。
この例では、デフォルトの動作であるFirstTime
オプションを使用しています。 FirstTime
動作のサブスクライブは、サブスクリプションが最初に作成されたときにのみ同期が完了することを待機します。
import { WaitForSync } from "realm"; // Get tasks that have a status of "in progress". const completedTasks = realm .objects(Task) .filtered("status == 'completed'"); // Only waits for sync to finish on the initial sync. await completedTasks.subscribe({ behavior: WaitForSync.FirstTime, name: "First time sync only", });
サポートされているその他のWaitForSync
オプションは次のとおりです。
Always
: アプリを起動するたびに一致するオブジェクトをダウンロードするまで待機します。 アプリは起動時にインターネットに接続する必要があります。Never
: 一致するオブジェクトがダウンロードされるのを待たない。 アプリは、アプリが初めて起動するときにユーザーが認証するためにインターネット接続を必要としますが、キャッシュされた認証情報を使用して以降の起動ではオフラインで開くことができます。
オプションで、同期ダウンロードの実行時間を制限するには、 timeout
の値を指定します。
import { WaitForSync } from "realm"; // Get tasks that have a status of "in progress". const completedTasks = realm .objects(Task) .filtered("status == 'completed'"); // Add subscription with timeout // If timeout expires before sync is completed, currently-downloaded // objects are returned and sync download continues in the background. const taskSubscription = await completedTasks.subscribe({ behavior: WaitForSync.Always, timeout: 500, });
クエリからのサブスクライブの解除
unsubscribe()
を使用して、クエリの結果からサブスクライブを解除できます。
import { WaitForSync } from "realm"; // Get tasks that have a status of "in progress". const completedTasks = realm .objects(Task) .filtered("status == 'completed'"); // Only waits for sync to finish on the initial sync. await completedTasks.subscribe({ behavior: WaitForSync.FirstTime, name: "First time sync only", }); // Unsubscribe completedTasks.unsubscribe();
これにより、サブスクリプションを手動で削除するのと同様に、アクティブなサブスクリプションのリストからサブスクリプションが削除されます。
重複するオブジェクトを含む別のサブスクリプションが存在する場合、 unsubscribe()
を呼び出した後も結果リストにはオブジェクトが含まれることがあります。
unsubscribe()
を呼び出すと、関連付けられているサブスクライブが削除されます。 サブスクリプションは名前で削除されます。 名前がない場合、 unsubscribe()
は、 unsubscribe()
を呼び出したクエリと完全に一致するクエリをすべて削除します。
unsubscribe()
メソッドは、削除されたサブスクリプションに一致するオブジェクトが Realm から削除される前にを返します。 新しいサブスクライブセットに基づいて、同期はバックグラウンドで続行されます。
サブスクリプションの手動管理
サブスクリプションAPI を使用して、クエリ可能なフィールドの特定のクエリへのサブスクリプションのセットを手動で管理できます。
ユーザーは次のアクションを実行できます。
すべてのサブスクライブの一覧を取得する
サブスクライブを追加する
サブスクリプション状態の確認
新しいクエリでサブスクライブを更新する
個別のサブスクライブまたはタイプのすべてのサブスクライブを削除
データがサブスクリプションに一致し、適切な権限がある場合、デバイスとバックエンド アプリケーション間で同期されます。
サブスクリプションを作成すると、Realm は特定のオブジェクトタイプに対するクエリに一致するデータを検索します。 複数の異なるオブジェクトタイプのサブスクライブを持つことができます。 同じオブジェクトタイプに対して複数のクエリを設定することもできます。
重要
オブジェクト リンク
リンクされたオブジェクトを表示するには、オブジェクトとそのリンクされたオブジェクトの両方をサブスクリプション セットに追加する必要があります。
結果に含まれていないオブジェクトにリンクする プロパティを持つオブジェクトがサブスクライブ結果に含まれている場合、リンクは null に表示されます。 そのプロパティの値が完全に null であるかどうか、また、リンク先のオブジェクトが存在してもクエリ サブスクリプションのビューの対象外であるかどうかを区別する方法はありません。
すべてのサブスクリプションを取得する
柔軟に同期された Realm を使用する場合、 Realm.subscriptionsを通じてサブスクリプションのコレクションであるSubscriptionSet
にアクセスできます。 プロパティ。
// get the SubscriptionSet for the realm const subscriptions = realm.subscriptions;
サブスクリプションを追加する
サブスクリプションは、 Realm クエリの結果に基づいています。
次の例では、 completed
とprogressMinutes
が App Services App でクエリ可能なフィールドとして設定されています。 クライアント コードでは、フィルタリングされたクエリを作成し、その結果をサブスクライブします。
完了したタスク
120 時間以上かかったタスクを完了しました
progressMinutes
const tasks = realm.objects("Task"); const longRunningTasks = tasks.filtered( 'status == "completed" && progressMinutes > 120' ); await realm.subscriptions.update((mutableSubs) => { mutableSubs.add(longRunningTasks, { name: "longRunningTasksSubscription", }); mutableSubs.add(realm.objects("Team"), { name: "teamsSubscription", }); });
初期サブスクリプションの設定
Flexible Sync レルムからの読み取りまたは書込みを行う前に、少なくとも 1 つのサブスクリプションが必要です。 Realm を開くときに初期サブスクリプションを追加できます。
初期サブスクリプションを設定するには、Realm のSyncConfigurationにinitialSubscriptions
フィールドを含めます。 initialSubscriptions
オブジェクト内に、クエリをサブスクライブするコールバックにupdate
フィールド セットを追加します。
const config = { schema: [Task], sync: { user: app.currentUser, flexible: true, initialSubscriptions: { update: (subs, realm) => { subs.add(realm.objects(Task).filtered("status == 'in progress'"), { name: "In progress tasks", }); }, rerunOnOpen: true, }, }, }; const realm = await Realm.open(config);
const config: Realm.Configuration = { schema: [Task], sync: { user: app.currentUser!, flexible: true, initialSubscriptions: { update: (subs, realm) => { subs.add(realm.objects(Task).filtered("status == 'in progress'"), { name: "In progress tasks", }); }, rerunOnOpen: true, }, }, }; const realm = await Realm.open(config);
デフォルトでは、初期サブスクリプションは、Realm が初めて開かれたときにのみ作成されます。 アプリを起動するたびにアプリがこの初期サブスクリプションを再実行する必要がある場合は、 rerunOnOpen
をtrue
に設定できます。 動的時間範囲やサブスクライブの静的変数の再計算が必要なその他のクエリを再実行するには、この操作が必要になる場合があります。
サブスクリプションのステータスを確認
サブスクリプション状態をチェックして、サーバーがサブスクリプションを確認し、デバイスがデータをローカルにダウンロードしているかどうかを確認できます。
サブスクリプション状態を使用して、次のことが可能です。
Trigger error handling
トランザクションが保留中か完了したかを表示する
サブスクリプションセットがスーパー秒されているときを見つけ、サブスクリプションの変更を書き込むにはサブスクリプションセットの新しいインスタンスを取得する必要があります
注意
サブスクリプション状態「完了」
サブスクリプションセットの状態「完了」は、「同期が実行された」または「すべてのドキュメントが同期された」を意味するものではありません。 「完了」とは、次の 2 つの処理が発生したことを意味します。
サブスクライブは、現在サーバーと同期されているアクティブなサブスクリプションセットになりました。
サブスクリプションがサーバーに送信されたときにサブスクリプションに一致したドキュメントは、現在、ローカルデバイス上にあります。 これには、現在サブスクリプションに一致しているすべてのドキュメントが必ずしも含まれるわけではないことに注意してください。
Realm SDK には、サブスクリプションに一致するすべてのドキュメントがデバイスに同期されているかどうかを確認する方法は提供されていません。
バージョン 12.0.0 の新機能。
Node.js v 12.0.0 サブスクリプションのステータスを取得するために使用できるSubscriptionSetState 列挙型を追加しました。
サブスクリプション状態「完了」
サブスクリプションセットの状態「完了」は、「同期が実行された」または「すべてのドキュメントが同期された」を意味するものではありません。 「完了」とは、次の 2 つの処理が発生したことを意味します。
サブスクライブは、現在サーバーと同期されているアクティブなサブスクリプションセットになりました。
サブスクリプションがサーバーに送信されたときにサブスクリプションに一致したドキュメントは、現在、ローカルデバイス上にあります。 これには、現在サブスクリプションに一致しているすべてのドキュメントが必ずしも含まれるわけではないことに注意してください。
Realm SDK には、サブスクリプションに一致するすべてのドキュメントがデバイスに同期されているかどうかを確認する方法は提供されていません。
新しいクエリによるサブスクリプションの更新
新しいクエリを使用して 名前付きサブスクライブ を更新できます。 サブスクライブのクエリを更新するには、新しいクエリと、更新するサブスクリプションの名前を指定してサブスクライブ オプションをMutableSubscriptionSet.add()
メソッドに渡します。 新しいサブスクリプションを追加するのと同様に、トランザクション内でsubscriptions.update()
を呼び出してサブスクリプションを更新する必要があります。
次の例では、長時間実行タスクは 180 分以上かかったタスクであるように再定義されています。
realm.subscriptions.update((mutableSubs) => { mutableSubs.add( tasks.filtered('status == "completed" && progressMinutes > 180'), { name: "longRunningTasksSubscription", } ); });
注意
SubscriptionOptions.throwOnUpdate
フィールドが true に設定されているサブスクライブを更新しようとすると、例外がスローされます。
サブスクリプションの削除
サブスクリプションは、次の方法で削除できます。
特定のクエリを使用して単一のサブスクライブを削除
特定の名前の単一のサブスクライブを削除
特定のオブジェクトモデルへのすべてのサブスクライブを削除
名前のないサブスクライブをすべて削除します
すべてのサブスクライブを削除
サブスクリプション クエリを削除すると、サーバーはクライアント デバイスから同期されたデータも削除します。
クエリによるサブスクリプションの削除
サブスクリプションセットでトランザクションを実行し、クエリによって特定のサブスクリプションを削除できます。 トランザクション内のMutableSubscriptionSet
の排除()メソッドにクエリを渡します。
次の例では、「Ben」という名前の所有者を持つタスクへのサブスクライブがサブスクリプションセットから削除されています。
realm.subscriptions.update((mutableSubs) => { // remove a subscription with a specific query mutableSubs.remove(tasks.filtered('owner == "Ben"')); });
名前を使用してサブスクリプションを削除
名前で特定のサブスクリプションを削除するには、サブスクリプションセットに対してトランザクションを実行します。 トランザクション内で、 MutableSubscriptionSet
のdeleteByName()メソッドに名前を渡します。
realm.subscriptions.update((mutableSubs) => { // remove a subscription with a specific name mutableSubs.removeByName("longRunningTasksSubscription"); });
参照によるサブスクリプションの削除
サブスクリプションへの参照がある場合は、そのサブスクライブを削除できます。 これを行うには、サブスクリプション セットで トランザクション を実行します。 トランザクション内で、参照変数をMutableSubscriptionSet
の排除サブスクリプションメソッドに渡します。
let subscriptionReference; realm.subscriptions.update((mutableSubs) => { subscriptionReference = mutableSubs.add(realm.objects("Task")); }); // later.. realm.subscriptions.removeSubscription(subscriptionReference);
オブジェクト タイプへのすべてのサブスクリプションを削除
特定のオブジェクトタイプのすべてのサブスクリプションを削除するには、サブスクリプションセットで トランザクション を実行します。 トランザクション内で、オブジェクトタイプを string としてMutableSubscriptionSet
のdeleteByObjectTypeメソッドに渡します。
realm.subscriptions.update((mutableSubs) => { mutableSubs.removeByObjectType("Team"); });
すべての名前のないサブスクリプションを削除
バージョン v12.0.0 の新機能。
一時的な、または動的に生成される名前のないサブスクリプションは削除するが、名前付きサブスクリプションはその場で残すしたい場合があります。
mutableSubs
で.removeUnnamed()
を呼び出すと、サブスクライブセットから名前のないすべてのサブスクライブを削除できます。 .removeUnnamed()
は、削除された名前のないサブスクライブの数を返します。
// Remove unnamed subscriptions. let numberRemovedSubscriptions = 0; await realm.subscriptions.update((mutableSubs) => { numberRemovedSubscriptions = mutableSubs.removeUnnamed(); });
すべてのサブスクリプションを削除
サブスクリプションセットからすべてのサブスクライブを削除するには、サブスクリプションセットで トランザクション を実行します。 トランザクション内のMutableSubscriptionSet
でdeleteAll()を呼び出す
realm.subscriptions.update((mutableSubs) => { mutableSubs.removeAll(); });
パフォーマンスに関する考慮事項
API 効率
「クエリへのサブスクライブ」セクションで説明されているsubscribe()
とunsubscribe()
API を使用して複数のサブスクリプションを管理する場合、サブスクリプションを手動で管理する場合にバッチ更新を実行する場合より効率が低くなります。
複数のサブスクライブ変更を行う際のパフォーマンスを向上させるには、 subscriptions
API を使用して 1 回のトランザクションですべてのサブスクライブを更新します。 方法については、「サブスクリプションの手動管理 」を参照してください。
パフォーマンス向上のためのグループ更新
サブスクリプションセットのすべての書込みトランザクション (write transaction) にはパフォーマンス コストがかかります。 セッション中に Realm オブジェクトを複数更新する必要がある場合は、すべての変更が完了するまで編集されたオブジェクトをメモリ内に保持することを検討してください。 これにより、すべての変更ではなく、完全で更新されたオブジェクトのみが Realm に書き込まれるため、同期のパフォーマンスが向上します。
Flexible Sync RQL の要件と制限
インデックス付きクエリ可能なフィールドのサブスクリプション要件
インデックス付きのクエリ可能なフィールドをアプリに追加すると、厳密にパーティション化されたデータに対する単純なクエリのパフォーマンスが向上します。 たとえば、クエリがデバイス、ストア、またはユーザーにデータを厳密にマッピングするアプリ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
は、インデックス付きクエリ可能なフィールドが含まれていないため無効です。
Flexible Sync でサポートされていないクエリ演算子
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 エラー が発生します。