Flexible Sync サブスクリプションの管理 - Java SDK
項目一覧
Overview
Flexible Sync は、サブスクリプションと権限を使用して、アプリと同期するデータを決定します。
SDK で Flexible Sync を使用するには、次の手順に従います。
クライアント プロジェクトでユーザーを認証します。
クエリ サブスクライブを追加、更新、削除して、クライアント デバイスに同期するデータを決定できます。
Tip
以下も参照してください。
このページでは、Flexible Sync のサブスクライブを管理する方法について詳しく説明します。
バックグラウンドで変更を同期する方法や同期セッションを一時停止する方法など、SDK と Atlas Device Sync の使用に関する一般的な情報については、「デバイス間で変更を同期する 」を参照してください。
Flexible Sync の権限の設定の詳細については、「 Flexible Sync のルールと権限 」を参照してください。
クエリ可能なフィールドのサブスクライブ
バックエンドで Flexible Sync を構成するときは、クライアント アプリケーションがクエリできるフィールドを指定します。 クライアント アプリケーションで、 subscriptions
API を使用して、クエリ可能なフィールドの特定のクエリへのサブスクリプションのセットを管理します。 Java SDKの Fluent インターフェースまたはRQLを使用してクエリを構築できます。
重要
Flexible SyncはRQLで利用可能なすべての演算子をサポートしていません。 詳細については、「 Flexible Sync RQL の制限」を参照してください。
ユーザーは次のアクションを実行できます。
サブスクライブを追加する
Reactション状態に対応
新しいクエリでサブスクライブを更新する
オブジェクトタイプの個々のサブスクライブまたはすべてのサブスクライブを削除
ユーザーが適切な権限を持つサブスクリプションに一致するデータは、クライアントとバックエンド アプリケーション間で同期されます。
サブスクライブには任意の string 名を指定できます。
Tip
サブスクリプション名を常に指定する
アプリケーションで複数のサブスクライブを使用する場合は、常にサブスクリプション名を指定します。 これにより、アプリ内の他の場所でサブスクライブを検索、更新、削除することが簡単になります。
サブスクリプションを作成すると、Realm は特定のオブジェクトタイプに対するクエリに一致するデータを検索します。 異なるオブジェクトタイプに対して複数のサブスクリプションセットを持つことができます。 同じオブジェクトタイプに対して複数のクエリを設定することもできます。
明示的な名前のサブスクリプションを作成できます。 次に、そのサブスクリプションを名前で検索して更新または削除できます。
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions(new SyncConfiguration.InitialFlexibleSyncSubscriptions() { public void configure(Realm realm, MutableSubscriptionSet subscriptions) { // add a subscription with a name subscriptions.add(Subscription.create("frogSubscription", realm.where(Frog.class) .equalTo("species", "spring peeper"))); } }) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); // later, you can look up this subscription by name Subscription subscription = realm.getSubscriptions().find("frogSubscription"); } });
val config = SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions { realm, subscriptions -> // add a subscription with a name subscriptions.add( Subscription.create( "frogSubscription", realm.where(Frog::class.java) .equalTo("species", "spring peeper") ) ) } .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm.") // later, you can look up this subscription by name val subscription = realm.subscriptions.find("frogSubscription") } })
クエリでサブスクリプションを検索することもできます。 サブスクライブの作成時に名前を省略する場合、これがサブスクライブを検索する唯一の方法です。
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions(new SyncConfiguration.InitialFlexibleSyncSubscriptions() { public void configure(Realm realm, MutableSubscriptionSet subscriptions) { // add a subscription without assigning a name subscriptions.add(Subscription.create( realm.where(Frog.class) .equalTo("species", "spring peeper"))); } }) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); // later, you can look up this subscription by query Subscription subscription = realm.getSubscriptions().find(realm.where(Frog.class) .equalTo("species", "spring peeper")); } });
val config = SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions { realm, subscriptions -> // add a subscription without assigning a name subscriptions.add( Subscription.create( realm.where(Frog::class.java) .equalTo("species", "spring peeper") ) ) } .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm.") // later, you can look up this subscription by query val subscription = realm.subscriptions.find( realm.where( Frog::class.java ).equalTo("species", "spring peeper") ) } })
注意
重複したサブスクライブ
サブスクリプション名は一意である必要があります。 既存のサブスクリプションと同じ名前のサブスクリプションを追加すると、エラーがスローされます。
サブスクリプションを明示的に名前付けせず、代わりに同じ名前のないクエリを複数回サブスクライブする場合、Realm はサブスクライブセットへのクエリを重複させません。
異なる名前で同じクエリを複数回サブスクライブする場合、Realm は両方のサブスクライブをサブスクリプションセットに永続化します。
サブスクリプションを追加する
サブスクリプション書込みブロック にサブスクライブを追加する。 新しいサブスクリプションはそれぞれ、クライアントの Realm サブスクリプションに追加します。
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions(new SyncConfiguration.InitialFlexibleSyncSubscriptions() { public void configure(Realm realm, MutableSubscriptionSet subscriptions) { subscriptions.add(Subscription.create("subscriptionName", realm.where(Frog.class) .equalTo("species", "spring peeper"))); } }) .build(); // instantiate a realm instance with the flexible sync configuration Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); } });
val config = SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions { realm, subscriptions -> subscriptions.add( Subscription.create( "subscriptionName", realm.where(Frog::class.java) .equalTo("species", "spring peeper") ) ) } .build() // instantiate a realm instance with the flexible sync configuration Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm.") } })
注意
オブジェクト リンク
リンクされたオブジェクトを表示するには、オブジェクトとそのリンクされたオブジェクトの両方をサブスクリプション セットに追加する必要があります。
結果に含まれていないオブジェクトにリンクする プロパティを持つオブジェクトがサブスクライブ結果に含まれている場合、リンクは null に表示されます。 そのプロパティの値が完全に null であるかどうか、また、リンク先のオブジェクトが存在してもクエリ サブスクリプションのビューの対象外であるかどうかを区別する方法はありません。
サブスクリプションの変更が同期されるまで待機する
サブスクリプション セットへの更新をローカルに書き込むことは、サブスクリプション変更の 1 つの要素のみです。 ローカル サブスクリプションの変更後、クライアントはサーバーと同期して、サブスクリプションの変更によるデータの更新を解決します。 これは、同期された Realm からデータを追加または削除することを意味します。 waitForInitial remoteData()ビルダ メソッドを使用して、Realm を開く前に、クライアントのサブスクリプション データがバックエンドに同期されるまで、アプリケーションを強制的にブロックします。
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions(new SyncConfiguration.InitialFlexibleSyncSubscriptions() { public void configure(Realm realm, MutableSubscriptionSet subscriptions) { subscriptions.add(Subscription.create("my subscription", realm.where(Frog.class) .equalTo("species", "poison dart"))); } }) .waitForInitialRemoteData(2112, TimeUnit.MILLISECONDS) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); } });
val config = SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions { realm, subscriptions -> subscriptions.add( Subscription.create( "my subscription", realm.where(Frog::class.java) .equalTo("species", "poison dart") ) ) } .waitForInitialRemoteData( 2112, TimeUnit.MILLISECONDS ) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm.") } })
SubscriptionSet.waitForSynchronization()を使用することもできます またはSubscriptionSet.waitForSynchronizationAsync()を使用すると、同期接続をインスタンス化した後にサブスクライブ同期が完了するまで実行を遅延させます。
SubscriptionSet.State 列挙
さらに、 SubscriptionSet.State列挙型を使用して、サブスクリプションセットの状態を監視することもできます。 サブスクリプション状態を使用して、次のことが可能です。
データのダウンロード中に進行状況インジケーターを表示
サブスクライブセットがスーパー秒数になるタイミングを調べる
SubscriptionSet.getState() を使用して、アプリケーションのサブスクリプション セットの状態にアクセスできます。
注意
サブスクリプション状態「完了」
サブスクリプションセットの状態「完了」は、「同期が実行された」または「すべてのドキュメントが同期された」を意味するものではありません。 「完了」とは、次の 2 つの処理が発生したことを意味します。
サブスクライブは、現在サーバーと同期されているアクティブなサブスクリプションセットになりました。
サブスクリプションがサーバーに送信されたときにサブスクリプションに一致したドキュメントは、現在、ローカルデバイス上にあります。 これには、現在サブスクリプションに一致しているすべてのドキュメントが必ずしも含まれるわけではないことに注意してください。
Realm SDK には、サブスクリプションに一致するすべてのドキュメントがデバイスに同期されているかどうかを確認する方法は提供されていません。
上書き
SUPERSEDED
は、別のスレッドがサブスクライブセットの別のインスタンスにサブスクリプションを書込むときに発生する可能性のあるSubscriptionSet.State
です。 状態がSUPERSEDED
になった場合は、サブスクライブセットの新しいインスタンスを取得した後に、サブスクライブセットに書き込む必要があります。
新しいクエリによるサブスクリプションの更新
SubscriptionSet.update()を使用してサブスクライブを更新できます。 この例ではMutableSubscriptionSet.addOrUpdate()を使用して、"my flowsubscript" という名前のサブスクライブのクエリを更新します。
realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { // to update a named subscription, create a replacement with // the same name and add it to the subscription set subscriptions.addOrUpdate( Subscription.create("my frog subscription", realm.where(Frog.class) .equalTo("name", "Benedict Cumberburger"))); } });
realm.subscriptions.update { subscriptions -> // to update a named subscription, create a replacement with // the same name and add it to the subscription set subscriptions.addOrUpdate( Subscription.create( "my frog subscription", realm.where(Frog::class.java) .equalTo( "name", "Benedict Cumberburger" ) ) ) }
名前なしで作成されたサブスクライブを更新することはできません。 ただし、クエリで名前のないサブスクリプションを検索してサブスクライブセットから削除し、更新されたクエリで新しいサブスクリプションを追加することはできます。
realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { // to update an unnamed subscription, remove it from the // subscription set, then add your new query to the set Subscription mySubscription = subscriptions.find(realm.where(Frog.class) .equalTo("species", "cane toad")); subscriptions.remove(mySubscription); subscriptions.addOrUpdate( Subscription.create( realm.where(Frog.class) .equalTo("species", "albino cane toad"))); } });
realm.subscriptions.update { subscriptions -> // to update an unnamed subscription, remove it from the // subscription set, then add your new query to the set val mySubscription = subscriptions.find( realm.where( Frog::class.java ).equalTo( "species", "cane toad" ) ) subscriptions.remove(mySubscription) subscriptions.addOrUpdate( Subscription.create( realm.where(Frog::class.java) .equalTo( "species", "albino cane toad" ) ) ) }
サブスクリプションの削除
サブスクリプションを削除するには、次の方法があります。
1 つのサブスクライブ クエリを削除
特定のオブジェクトタイプへのすべてのサブスクライブを削除
すべてのサブスクライブを削除
サブスクリプション クエリを削除すると、Realm はクライアント デバイスからクエリに一致した同期データを非同期に削除します。
1 つのサブスクリプションを削除
MutableSubscriptionSet.remove()を使用して、特定のサブスクライブ クエリを削除できます。 名前でサブスクライブを検索してから、返されたサブスクライブをremove()
に渡すか、サブスクリプション名をremove()
に直接渡すことができます。
realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { Subscription mySubscription = subscriptions.find("mySubscription"); subscriptions.remove(mySubscription); } });
realm.subscriptions.update { subscriptions -> val mySubscription = subscriptions.find("mySubscription") subscriptions.remove(mySubscription) }
オブジェクト タイプへのすべてのサブスクリプションを削除
特定のオブジェクトタイプへのすべてのサブスクライブを削除する場合は、 クラスをdeleteAll()メソッドに渡します。
realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { subscriptions.removeAll(Frog.class); } });
realm.subscriptions.update { subscriptions -> subscriptions.removeAll( Frog::class.java ) }
すべてのサブスクリプションを削除
サブスクリプションセットからすべてのサブスクライブを削除するには、引数なしでdeleteAll()を使用します。
警告
すべてのサブスクライブを削除し、新しいサブスクライブを追加しないと、 エラーが発生します。 柔軟な同期構成で開かれたRealmでは、サーバーと同期するために少なくとも 1 つのサブスクライブが必要です。
realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { subscriptions.removeAll(); } });
realm.subscriptions.update { subscriptions -> subscriptions.removeAll() }
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 エラー が発生します。