Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

Flexible Sync サブスクリプションの管理 - Java SDK

項目一覧

  • Overview
  • クエリ可能なフィールドのサブスクライブ
  • サブスクリプションを追加する
  • サブスクリプションの変更が同期されるまで待機する
  • 新しいクエリによるサブスクリプションの更新
  • サブスクリプションの削除
  • Flexible Sync RQL の要件と制限
  • インデックス付きクエリ可能なフィールドのサブスクリプション要件
  • Flexible Sync でサポートされていないクエリ演算子
  • クエリをリストする
  • 埋め込みオブジェクトまたはリンクされたオブジェクト
  • クエリ サイズの制限

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

SDK で Flexible Sync を使用するには、次の手順に従います。

  • バックエンドでの Flexible Sync の構成

  • アプリを初期化

  • クライアント プロジェクトでユーザーを認証します。

  • Flexible Sync 構成で同期された Realm を開きます

  • クライアント アプリケーションにサブスクライブを追加する

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

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() {
@Override
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() {
@Override
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() {
@Override
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() {
@Override
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() {
@Override
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() {
@Override
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() {
@Override
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() {
@Override
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.getState() を使用して、アプリケーションのサブスクリプション セットの状態にアクセスできます。

注意

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

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

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

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

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

SUPERSEDED は、別のスレッドがサブスクライブセットの別のインスタンスにサブスクリプションを書込むときに発生する可能性のあるSubscriptionSet.Stateです。 状態がSUPERSEDEDになった場合は、サブスクライブセットの新しいインスタンスを取得した後に、サブスクライブセットに書き込む必要があります。

SubscriptionSet.update()を使用してサブスクライブを更新できます。 この例ではMutableSubscriptionSet.addOrUpdate()を使用して、"my flowsubscript" という名前のサブスクライブのクエリを更新します。

realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() {
@Override
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() {
@Override
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 はクライアント デバイスからクエリに一致した同期データを非同期に削除します。

MutableSubscriptionSet.remove()を使用して、特定のサブスクライブ クエリを削除できます。 名前でサブスクライブを検索してから、返されたサブスクライブをremove()に渡すか、サブスクリプション名をremove()に直接渡すことができます。

realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() {
@Override
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() {
@Override
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() {
@Override
public void update(MutableSubscriptionSet subscriptions) {
subscriptions.removeAll();
}
});
realm.subscriptions.update { subscriptions -> subscriptions.removeAll() }

インデックス付きのクエリ可能なフィールドをアプリに追加すると、厳密にパーティション化されたデータに対する単純なクエリのパフォーマンスが向上します。 たとえば、クエリがデバイス、ストア、またはユーザーにデータを厳密にマッピングするアプリ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 エラー が発生します。

戻る

同期された Realm の構成とオープン