문서 메뉴

문서 홈애플리케이션 개발Atlas Device SDK

managed Flexible Sync 구독 - .NET SDK

이 페이지의 내용

  • 구독 관리
  • 구독 추가
  • 초기 구독으로 Realm 부트스트랩
  • 기존 구독 세트에 구독 추가
  • 여러 구독 일괄 처리
  • SubscriptionOptions
  • 새 쿼리로 구독 업데이트하기
  • 구독 제거
  • 쿼리로 구독 제거
  • 이름으로 구독 제거
  • 클래스 이름 또는 Realm 객체 유형의 모든 구독 제거
  • 모든 구독 제거
  • 구독 변경 사항이 Sync될 때까지 기다리기
  • 구독 상태
  • Flexible Sync RQL 요구 사항 및 제한 사항
  • 인덱싱된 쿼리 가능 필드 구독 요구 사항
  • 유연한 동기화에서 지원되지 않는 쿼리 연산자
  • 목록 쿼리
  • 임베디드 또는 링크된 객체

Flexible Sync는 구독 및 권한을 사용하여 앱과 동기화할 데이터를 결정합니다.

.NET 애플리케이션에서 Flexible Sync를 사용하려면 다음을 수행합니다.

쿼리 구독을 추가, 업데이트 및 제거하여 클라이언트 장치에 동기화할 데이터를 결정할 수 있습니다.

참고

Flexible Sync 전제 조건

참고

Realm .NET SDK 버전 요구 사항

위의 요구 사항 외에도 Realm .NET 버전 10 90 을 사용해야 합니다. . .NET 클라이언트 애플리케이션에서 Flexible Sync를 사용하려면 이상이어야 합니다.

중요

Flexible Sync는 Realm Query Language에서 사용할 수 있는 모든 연산자를 지원하지 않습니다. 자세한 내용은 Flexible Sync RQL 제한 사항 을 참조하세요.

백엔드에서 Flexible Sync를 구성할 때 클라이언트 애플리케이션이 쿼리할 수 있는 필드를 지정합니다. 클라이언트 애플리케이션에서 구독 API를 사용하여 쿼리 가능 필드에 대한 특정 쿼리에 대한 구독 세트를 관리합니다.

다음을 수행할 수 있습니다.

  • 모든 구독 목록 보기

  • 구독 추가

  • 구독 상태 확인

  • 새 쿼리로 구독 업데이트

  • 개별 구독 또는 특정 유형의 모든 구독을 제거합니다.

데이터가 구독과 일치하고 인증된 사용자에게 적절한 권한이 있는 경우 Atlas App Services는 백엔드 데이터를 클라이언트 앱과 동기화합니다.

구독에 문자열 이름을 지정할 수 있습니다. 구독에 이름을 지정하지 않으면 이름은 null로 설정됩니다.

구독을 만들면 App Services는 특정 Realm 객체 유형에 대한 쿼리와 일치하는 데이터를 찾습니다. Flexible Sync 구독에서는 여러 개의 서로 다른 Realm 객체 유형에 대한 구독 또는 동일한 Realm 객체 유형에 대한 여러 쿼리를 가질 수 있습니다.

비대칭 객체 는 App Services 백엔드에만 데이터를 전송하므로 이에 대한 구독을 만들 수 없습니다.

버전 11.6.1에서 변경됨: Atlas Device Sync에서 지원되는 지리 공간적 데이터

Realm .NET 버전 11.6.1 이상에서는 지리 공간적 쿼리에 대한 구독을 생성할 수 있습니다. 이전 버전의 SDK에서 지리 공간적 쿼리를 구독하려고 하면 보정용 쓰기와 함께 서버 오류가 발생합니다.

자세한 내용은 지리 공간적 데이터 쿼리를 참조하세요.

영역에서 읽거나 영역에 쓰려면 먼저 구독이 하나 이상 있어야 합니다. 초기화 후 구독을 추가하는 대신 Flexible Sync를 구성할 때 초기 구독을 하나 이상 생성해야 합니다.

FlexibleSyncConfiguration 으로 열 때 초기 구독 세트가 있는 Realm을 부트스트랩할 수 있습니다. 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.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() 를 사용하여 업데이트 블록을 만든 다음 SubscriptionSet 에서 SubscriptionSet.Add() 메서드를 호출하기 위한 약식입니다.

SubscribeAsync 를 사용하여 단일 쿼리를 추가할 수 있지만 SubscriptionSet.Update 블록 내에서만 여러 쿼리를 배치할 수 있습니다. 쿼리 업데이트를 수행하는 것은 서버에서 많은 비용이 드는 작업입니다. 업데이트를 최소화하도록 애플리케이션을 설계하는 것이 좋습니다. 사용자가 앱을 처음 실행할 때 단일 업데이트 블록에 모든 구독을 생성하고 구독 세트에 대한 후속 변경 사항을 배치하여 이를 수행할 수 있습니다.

아래 예에서는 세 개의 쿼리를 구독합니다.

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 문자열 필드

  • 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);
});

업데이트 차단 내에서 클래스 이름을 RemoveAll("ClassName") 메서드에 문자열로 전달하여 클래스의 명명되지 않은 모든 구독을 제거할 수 있습니다. RemoveAll() 메서드에는 선택적 두 번째 인수인 부울 removedName 이 있으며, 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>();
});

업데이트 차단 내에서 구독 세트에서 명명되지 않은 모든 구독을 제거할 수 있습니다. SubscriptionSet 에서 RemoveAll() 메서드를 호출합니다. RemoveAll() 메서드에는 선택적 부울 removedName 인수가 있으며, 이 인수는 true 로 설정된 경우 명명된 구독도 제거합니다. removedName 는 기본적으로 false로 설정됩니다.

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

업데이트 차단 내에서 구독 세트를 변경하는 것은 구독 변경의 일부일 뿐입니다. 로컬 구독이 변경되면 영역은 서버와 동기화되어 구독 변경으로 인한 데이터 업데이트를 해결합니다. 이는 동기화된 realm에서 데이터를 추가하거나 제거하는 것을 MEAN 수 있습니다.

SubscriptionSet.WaitForSynchronizationAsync() 메서드를 사용하여 서버가 이 구독 집합을 확인할 때까지 기다립니다. 서버가 변경 사항을 거부하면 SubscriptionSetState 는 오류 상태가 되며 예외가 발생합니다.

다음과 같은 경우 예외가 발생할 수 있습니다.

  • 지원되지 않는 쿼리가 구독되었습니다. 지원되지 않는 쿼리를 구독하면 동기화가 일시 중지됩니다. 동기화를 다시 시작하려면 지원되지 않는 쿼리를 제거하세요.

  • 구독과 일치하지 않는 객체를 추가하는 등 잘못된 작업을 수행하고 있습니다. 이렇게 하면 클라이언트 재설정 이 트리거됩니다. 즉, 영역에서 데이터가 지워지고 세트에 구독 없이 데이터의 새 복사본이 생성됩니다.

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 이 되면 구독 세트의 새 인스턴스를 가져와야 업데이트할 수 있습니다.

참고

구독 상태 "완료"

구독 세트 상태 "완료" 는 "동기화가 완료됨" 또는 "모든 문서가 동기화됨" 을 의미하지 않습니다. "완료" 는 다음 두 가지를 의미합니다:

  • 구독이 현재 서버와 동기화되고 있는 활성 구독 세트가

  • 이제 구독이 서버로 전송될 때 구독과 일치했던 문서가 로컬 장치에 존재합니다. 여기에는 현재 구독과 일치하는 모든 문서가 반드시 포함되는 것은 아닙니다.

Realm SDK는 구독과 일치하는 모든 문서가 기기에 동기화되었는지 확인하는 방법을 제공하지 않습니다.

앱에 인덱싱된 쿼리 가능 필드 를 추가하면 강력하게 분할된 데이터에 대한 간단한 쿼리의 성능을 향상시킬 수 있습니다. 예를 들어 user_id == $0, “641374b03725038381d2e1fb” 와 같이 쿼리가 데이터를 기기, 스토어 또는 사용자에 강력하게 매핑하는 앱은 인덱싱된 쿼리 가능 필드의 좋은 후보입니다. 그러나 인덱싱된 쿼리 가능 필드에는 쿼리 구독에 사용하기 위한 특정 요구 사항이 있습니다.

  • 인덱싱된 쿼리 가능 필드는 모든 구독 쿼리에서 사용해야 합니다. 쿼리에서 누락되어서는 안 됩니다.

  • 인덱싱된 쿼리 가능 필드는 구독 쿼리에서 상수에 대해 == 또는 IN 비교를 한 번 이상 사용해야 합니다. 예를 들어 user_id == $0, "641374b03725038381d2e1fb" 또는 store_id IN $0, {1,2,3}입니다.

인덱싱된 쿼리 가능 필드가 == 또는 IN을 사용하여 상수와 한 번 이상 직접 비교되는 경우, 선택적으로 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"AND 대신 OR을 사용하므로 유효하지않습니다. 마찬가지로 store_id == 1 AND active_promotions < 5 OR num_employees < 10AND가 전체 쿼리가 아니라 옆에 있는 용어에만 적용되므로 유효하지 않습니다.

  • 인덱싱된 쿼리 가능 필드가 동등 연산자에 사용되지 않는 경우.예를 들어 store_id > 2 AND region=="Northeast"> 연산자만 인덱싱된 쿼리 가능 필드에 사용하고 동등 비교는 없기 때문에 유효하지 않습니다.

  • 인덱싱된 쿼리 가능 필드가 쿼리에서 완전히 누락된 경우.예를 들어region=="Northeast 또는 truepredicate는 인덱싱된 쿼리 가능 필드를 포함하지 않으므로 유효하지 않습니다.

Flexible Sync는 RQL 연산자를 사용할 때 몇 가지 제한 사항이 있습니다. 동기화할 데이터를 결정하는 쿼리 구독 을 작성할 때 서버는 이러한 쿼리 연산자를 지원하지 않습니다. 그러나 전체 RQL 기능을 사용하여 클라이언트 애플리케이션에서 동기화된 데이터 세트를 쿼리할 수 있습니다.

연산자 유형
지원되지 않는 연산자
집계 연산자
@avg, @count, @max, @min, @sum
쿼리 접미사
DISTINCT, SORT, LIMIT

대소문자를 구분하지 않는 쿼리([c])은(는) 인덱스를 효과적으로 사용할 수 없습니다. 대소문자를 구분하지 않는 쿼리는 성능 문제를 일으킬 수 있으므로 사용하지 않는 것이 좋습니다.

유연한 동기화는 배열 필드에 대해 @count만 지원합니다.

유연한 동기화는 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"

경고

유연한 동기화 쿼리에서는 두 목록을 비교하는 것이 불가능합니다. 이 구문은 유연한 동기화 쿼리 외에는 유효한 Realm Query Language 구문이라는 점에 유의하세요.

// 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"

유연한 동기화는 포함된 객체 또는 링크의 속성에 대한 쿼리를 지원하지 않습니다. 예를 들어 obj1.field == "foo"이 있습니다.

← 동기화된 Realm에 쓰기 - .NET SDK