Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

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

項目一覧

  • サブスクリプションを管理する
  • サブスクリプションを追加する
  • 初期サブスクリプションで Realm をブートストラップする
  • 既存のサブスクリプションセットへのサブスクリプションの追加
  • 複数のサブスクリプションのバッチ化
  • サブスクリプション オプション
  • 新しいクエリによるサブスクリプションの更新
  • サブスクリプションの削除
  • クエリによるサブスクリプションの削除
  • 名前を使用してサブスクリプションを削除
  • クラス名またはオブジェクトタイプのすべてのサブスクリプションを削除
  • すべてのサブスクリプションを削除
  • サブスクリプションの変更が同期されるまで待機する
  • サブスクリプション状態
  • Flexible Sync RQL の要件と制限
  • インデックス付きクエリ可能なフィールドのサブスクリプション要件
  • Flexible Sync でサポートされていないクエリ演算子
  • クエリをリストする
  • 埋め込みオブジェクトまたはリンクされたオブジェクト
  • クエリ サイズの制限

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

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

  • バックエンドで Flexible Sync を構成します。

  • アプリを初期化

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

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

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

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

注意

Flexible Sync の前提条件

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

注意

Realm .NET SDK バージョン要件

上記の要件に加えて、 Realm .NETバージョン10.9.0 を使用する必要があります 以上が.NETクライアントアプリケーションで Flexible Sync を使用できるようにします。

重要

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

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

ユーザーは次のアクションを実行できます。

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

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

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

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

  • 個別のサブスクライブまたはタイプのすべてのサブスクライブを削除

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

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

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

非対称オブジェクトのサブスクリプションは作成できません。このオブジェクトは App Services バックエンドにのみデータを送信するためです。

バージョン 11.6.1 での変更: Atlas Device Sync でサポートされている地理空間データ

Realm .NET バージョン 11.6.1 以降では、地理空間クエリのサブスクリプションを作成できます。 古いバージョンの SDK で地理空間クエリをサブスクライブしようとすると、書き込み補正によるサーバー エラーが発生します。

詳細については、「地理空間データのクエリ 」を参照してください。

Realm から読み取りまたは書込み (write) する前に、少なくとも 1 つのサブスクリプションが必要です。 初期化後にサブスクリプションを追加するのではなく、Flexible Sync を構成するときに 1 つ以上の初期サブスクリプションを作成する必要があります。

FlexibleSyncConfigurationを使用してRealmを開くと、初期サブスクリプションセットでRealmをブートストラップできます。 Realm の作成時に呼び出されるコールバックにpreferenceInitialSubscriptionsパラメータを設定します 次の例に示すように、Realm のブートストラップに使用するクエリを追加します。

var config = new FlexibleSyncConfiguration(app.CurrentUser)
{
PopulateInitialSubscriptions = (realm) =>
{
var myItems = realm.All<Item>().Where(n => n.OwnerId == myUserId);
realm.Subscriptions.Add(myItems);
}
};
// The process will complete when all the user's items have been downloaded.
var realm = await Realm.GetInstanceAsync(config);

SubscriptionSetを使用してRealmを初期化する必要があります。 その後に、追加のクエリを追加したり、既存のサブスクライブを更新したりする必要がある場合は、 Realm.Subscriptionsプロパティを使用してサブスクリプション セットにアクセスできます。

既存のサブスクライブセットにサブスクライブを追加するには、クエリを作成し、 IQueryable.SubscribeAsync()を呼び出します。

var query = realm.All<Team>().Where(t => t.Name == "MyTeam");
await query.SubscribeAsync();
// you can also pass a SubscriptionOptions object:
var query2 = realm.All<Team>().Where(t => t.Name == "DevelopmentTeam");
await query2.SubscribeAsync(
new SubscriptionOptions() { Name = "devTeamSubscription" });

SubscribeAsyncメソッドは、 SubscriptionSet.Update()を使用して更新ブロックを作成し、 SubscriptionSetSubscriptionSet.add()メソッドを呼び出すための省略形です。

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

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

realm.Subscriptions.Update(() =>
{
// Subscribe to all long running items, and name
// the subscription "longRunningItems"
var longRunningTasksQuery = realm.All<Item>()
.Where(t => t.ProgressMinutes > 120);
realm.Subscriptions.Add(longRunningTasksQuery,
new SubscriptionOptions() { Name = "longRunningItems" });
// Subscribe to all of Ben's Items
realm.Subscriptions.Add(realm.All<Item>()
.Where(t => t.Owner == "Ben"));
// Subscribe to all Teams, name the subscription
// 'teamsSubscription', and throw an error if
// this subscription name already exists.
realm.Subscriptions.Add(realm.All<Team>(),
new SubscriptionOptions()
{ Name = "teams", UpdateExisting = false });
});

サブスクリプションを追加するためのどちらの方法も、 SubscriptionOptionsオブジェクトを渡すためのオーバーロードを提供していることに注意してください。 SubscriptionOptionsには、サブスクライブの構成オプションが含まれています。

  • Name string フィールド

  • UpdateExistingブール値 フィールド。

UpdateExistingが true の場合、既存の名前でサブスクライブを追加すると、既存のクエリが新しいクエリに置き換えられます。 これはデフォルトの動作です。 ただし、 UpdateExistingを false に設定し、名前付きサブスクリプションを別のクエリに置き換えようとすると、Realm は例外をスローします。

Realm では、名前付きかどうかにかかわらず、常に重複するサブスクリプションは無視されます。

重要

リンクされたオブジェクトのサブスクライブ

リンクされたオブジェクトを表示するには、オブジェクトとそのリンクされたオブジェクトの両方をサブスクリプション セットに追加する必要があります。

サブスクライブ結果に、結果に含まれていないオブジェクトにリンクする プロパティを持つオブジェクトが含まれている場合、リンクは nil に表示されます。 そのプロパティの値が正しく nil であるかどうか、また、リンク先のオブジェクトが存在してもクエリ サブスクリプションのビューの対象外であるかどうかを区別する方法はありません。

新しいクエリを使用して 名前付きサブスクライブ を更新できます。 サブスクライブのクエリを更新するには、新しいクエリと、更新するサブスクリプションの名前を指定してサブスクライブ オプションをSubscriptionSet.Add()メソッドに渡します。 新しいサブスクライブを追加するのと同様に、 SubscriptionSet.Update()メソッドを呼び出して更新ブロック内でサブスクライブを更新する必要があります。

注意

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

次の例では、長時間実行されているタスクは、130 分以上かかったタスクであるように再定義されています。

realm.Subscriptions.Update(() =>
{
var updatedLongRunningTasksQuery = realm.All<Item>()
.Where(t => t.Status == "completed" && t.ProgressMinutes > 130);
realm.Subscriptions.Add(updatedLongRunningTasksQuery,
new SubscriptionOptions() { Name = "longRunningTasks" });
});

注意

SubscriptionOptions.UpdateExistingフィールドが false に設定されているサブスクライブを更新しようとすると、例外がスローされます。

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

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

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

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

  • 特定のタイプのすべてのサブスクライブを削除する

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

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

更新ブロック内では、クエリによって特定のサブスクリプションを削除できます。 クエリをSubscriptionSetRemove()メソッドに渡します。

次の例では、「Ben」という名前の所有者を持つタスクへのサブスクライブがサブスクリプションセットから削除されています。

realm.Subscriptions.Update(() =>
{
// remove a subscription by it's query
var query = realm.All<Item>().Where(i => i.Owner == "Ben");
realm.Subscriptions.Remove(query);
});

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

realm.Subscriptions.Update(() =>
{
// remove a named subscription
var subscriptionName = "longRunningItemsSubscription";
realm.Subscriptions.Remove(subscriptionName);
});

更新ブロック内では、クラス名を string としてRemoveAll("ClassName")メソッドに渡すことで、クラスの名前のないすべてのサブスクリプションを削除できます。 RemoveAll()メソッドには、ブール値であるremovedNameである任意の 2 つ目の引数があります。これにより、 trueに設定されている場合は、名前付きサブスクリプションも削除されます。 removedNameはデフォルトで false に設定されています。

あるいは、 RemoveAll()を使用して、オブジェクトタイプの名前のないサブスクリプションをすべて削除することもできます。 RemoveAll<Type>()メソッドには任意のブール値removedName引数があり、 trueに設定されている場合は名前付きサブスクリプションも削除されます。 removedName引数はデフォルトで false に設定されています。

realm.Subscriptions.Update(() =>
{
// remove all subscriptions of the "Team" Class Name
realm.Subscriptions.RemoveAll("Team");
// Alernatively, remove all subscriptions of the "Team" object type
realm.Subscriptions.RemoveAll<Team>();
});

更新ブロック内で、サブスクリプションセットから名前のないすべてのサブスクリプションを削除できます。 SubscriptionSetRemoveAll()メソッドを呼び出します。 RemoveAll()メソッドには任意のブール値removedName引数があります。これがtrueに設定されている場合は、名前付きサブスクリプションも削除されます。 removedNameはデフォルトで false に設定されています。

realm.Subscriptions.Update(() =>
{
// remove all subscriptions, including named subscriptions
realm.Subscriptions.RemoveAll(true);
});

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

SubscriptionSet.WaitForSynchronizationAsync()メソッドを使用して、サーバーがこのサブスクライブのセットを確認するのを待機します。 サーバーが変更を拒否した場合、 SubscriptionSetStateはエラー状態になり、例外がスローされます。

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

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

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

try
{
await realm.Subscriptions.WaitForSynchronizationAsync();
}
catch (SubscriptionException ex)
{
// do something in response to the exception or log it
Console.WriteLine($@"The subscription set's state is Error and synchronization is paused: {ex.Message}");
}

サブスクリプションセットの現在の状態を読み取るには、 SubscriptionSet.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 エラー が発生します。

戻る

同期された Realm への書き込み - .NET SDK