Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

동기화 구독 관리 - Flutter SDK

이 페이지의 내용

  • 전제 조건
  • 백엔드 앱과 구독 정렬
  • 쿼리 구독
  • 쿼리 구독
  • 쿼리 구독이 동기화될 때까지 기다리기
  • 쿼리 구독 취소
  • 수동으로 구독 관리하기
  • 구독 가져오기
  • 구독 세트에 쿼리 추가
  • 새 쿼리로 구독 업데이트하기
  • 구독 제거
  • 구독 변경 사항이 Sync될 때까지 기다리기
  • 구독 상태
  • Flexible Sync RQL 요구 사항 및 제한 사항
  • 인덱싱된 쿼리 가능 필드 구독 요구 사항
  • Flexible Sync에서 지원되지 않는 쿼리 연산자
  • 목록 쿼리
  • 임베디드 또는 링크된 객체
  • 쿼리 크기 제한
  • 성능 고려 사항
  • API 효율성
  • 성능 향상을 위한 그룹 업데이트

Flexible Sync 기능이 포함된 Atlas Device Sync는 구독 및 권한을 사용하여 Atlas와 앱 간에 Realm Mobile Sync할 데이터를 결정합니다.

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

참고

Flexible Sync 전제 조건

앱에서 Flexible Sync를 사용하려면 MongoDB 5.0 이상을 실행 하는 비샤드형 Atlas cluster 가 필요합니다.

Flutter 애플리케이션에서 Flexible Sync를 사용하려면 다음을 수행하세요.

  1. Atlas App Services 백엔드에서 Flexible Sync 구성

  2. 앱 클라이언트 초기화

  3. 클라이언트에서 사용자 인증

  4. 클라이언트에서 동기화된 영역 열기

클라이언트 사이드 구독 쿼리는 백엔드 App Services 앱의 Device Sync 구성과 일치해야 합니다.

구독 쿼리는 다음 중 하나를 수행할 수 있습니다.

  • 유형의 모든 객체를 쿼리합니다. Realm.all()을사용하여 쿼리를 만듭니다.

  • 백엔드 앱의 쿼리 가능 필드와 일치하는 쿼리 객체입니다. Realm.query() 를 사용하여 쿼리 만들기 및 하나 이상의 쿼리 가능 필드를 포함하는 RQL 쿼리를 포함합니다. 쿼리할 수 없는 필드를 사용하여 구독을 생성하려고 하면 Realm SDK에서 오류가 발생합니다.

    • 쿼리 가능 필드 구성에 대해 자세히 알아보려면 App Services 문서에서 쿼리 가능 필드를 참조하세요.

    • Flexible Sync와 함께 Realm Query Language를 사용할 때의 제한 사항에 대해 자세히 알아보려면 Flexible Sync RQL 제한 사항 섹션을 참조하세요.

버전 1.6.0의 새로운 기능.

Flutter v1.6.0에는 쿼리 결과를 구독하거나 구독 취소하는 실험적 API가 추가되었습니다. 이러한 API는 수동으로 구독을 추가하고 제거하는 세부 사항을 추상화합니다.

모든 구독에는 인증된 사용자동기화된 Realm이 필요합니다.

성능 최적화 또는 비즈니스 로직상의 이유로 구독에 대한 더 많은 제어가 필요한 경우 subscriptions API를 사용하여 구독 세트를 수동으로 관리 할 수 있습니다. 자세한 내용은 이 페이지의 성능 고려 사항 섹션을 참조하세요.

subscribe() 메서드를 사용하여 쿼리의 을(를) 구독할 수 있습니다.RealmResults 메서드. SDK가 호출되면 수동으로 구독을 생성하는것과 유사하게 새 구독을 생성하고 MutableSubscriptionSet 에 추가합니다.

선택적으로 쿼리에 대해 고유한 구독 이름을 전달할 수 있습니다. 기존 구독과 동일한 이름으로 구독을 추가하면 SDK가 기존 구독을 덮어씁니다.

구독 이름을 전달하지 않으면 이름이 null(으)로 설정되고 구독 식별자는 쿼리 문자열을 기반으로 합니다. 이는 쿼리 문자열이 변경될 때마다 subscribe() 가 새 구독을 생성한다는 의미입니다.

쿼리를 구독하려면 다음 인수를 subscribe() 에 전달합니다.

  • RealmResults query: 필수입니다. Realm 쿼리 언어를 사용하여 생성할 수 있는 RealmResults 객체입니다.

  • String name: 선택 사항입니다. 참조할 수 있는 구독의 이름입니다.

  • bool update: 선택 사항입니다. true인 경우 기존 이름으로 구독을 추가하면 기존 쿼리가 새 쿼리로 대체됩니다. false인 경우 SDK는 중복 구독에 대해 예외를 발생시킵니다. 명명된 구독에만 사용하세요.

다음 예제에서는 두 개의 새로운 명명된 쿼리를 구독합니다.

final boatQuery = realm.all<Boat>();
final bigPlaneQuery = realm.query<Plane>("numSeats > 100");
final boatSubscription = await boatQuery.subscribe(name: "boats");
final planeSubscription =
await bigPlaneQuery.subscribe(name: "big-planes");

구독 이름 지정

특히 애플리케이션에서 여러 구독을 사용하는 경우 항상 구독 이름을 지정하는 것이 좋습니다. 이렇게 하면 구독을 더 쉽게 찾고 관리할 수 있습니다.

쿼리 결과를 구독하면 동기화된 데이터가 다운로드될 때까지 결과에 객체가 포함되지 않습니다. 동기화된 객체의 다운로드가 완료될 때까지 기다려야 하는 경우 waitForSyncMode 를 구성합니다. 옵션.

이 예시에서는 기본 동작인 firstTime 옵션을 사용합니다. firstTime 동작이 있는 구독은 구독이 처음 생성될 때 동기화가 완료될 때까지만 기다립니다.

final bigPlaneQuery = realm.query<Plane>("numSeats > 100");
final planeSubscription = await bigPlaneQuery.subscribe(
name: "firstTimeSync",
waitForSyncMode: WaitForSyncMode.firstTime,
);

지원되는 다른 waitForSyncMode 옵션은 다음과 같습니다.

  • always: 앱이 실행될 때마다 일치하는 객체를 다운로드할 때까지 기다립니다. 앱을 실행할 때마다 인터넷에 연결되어 있어야 합니다.

  • never: 일치하는 객체를 다운로드하기 위해 기다리지 마세요. 앱을 처음 실행할 때는 사용자가 인증하기 위해 인터넷 연결이 필요하지만, 이후 실행 시 캐시된 자격 증명을 사용하여 오프라인에서 열 수 있습니다.

선택적으로 cancelToken 을 지정할 수 있습니다. 동기화 다운로드가 실행되는 시간을 제한합니다:

final bigPlaneQuery = realm.query<Plane>("numSeats > 200");
final planeSubscription = await bigPlaneQuery.subscribe(
name: "alwaysWaitSync",
waitForSyncMode: WaitForSyncMode.always,
cancellationToken: TimeoutCancellationToken(Duration(seconds: 5)),
);

구독을 취소하지 않는 한 구독은 사용자 세션 전반에 걸쳐 유지됩니다. unsubscribe()를사용하여 쿼리 결과의 구독을 취소할 수 있습니다.

이렇게 하면 수동으로 구독을 제거하는 것과 유사하게 활성 구독 목록에서 구독이 제거됩니다. 겹치는 객체가 포함된 다른 구독이 있는 경우 unsubscribe() 를 호출한 후에도 결과 목록에 여전히 객체가 포함될 수 있습니다.

쿼리에서 unsubscribe() 를 호출하면 SDK는 unsubscribe() 을(를) 호출한 쿼리와 정확히 일치하는 쿼리가 있는 모든 구독을 제거합니다. 이 메서드는 제거된 구독과 일치하는 객체가 영역에서 삭제되기 전에 반환됩니다. 동기화는 새 구독 세트를 기반으로 백그라운드에서 계속됩니다.

planeQuery.unsubscribe();
trainQuery.unsubscribe();

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

구독으로 다음을 수행할 수 있습니다:

  • 모든 구독 목록 보기

  • 구독 추가

  • 구독 상태 확인

  • 새 쿼리로 구독 업데이트

  • 구독 제거

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

구독 세트는 더 이상 코드에 구독을 포함하지 않더라도 세션 전반에 걸쳐 유지됩니다. 구독 정보는 동기화된 영역의 데이터베이스 파일에 저장됩니다. 일치하는 데이터 동기화 시도를 중지하려면 구독을 명시적으로 제거해야 합니다.

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

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

Flexible Sync를 사용하는 경우 SubscriptionSet 에 액세스할 수 Realm.subscriptions 있습니다. 속성을 통해 구독 컬렉션입니다.

아래 예와 같이 이 구독 세트를 사용하여 이 구독 목록에 쿼리를 추가하고 기존 구독을 업데이트할 수 있습니다.

final subscriptions = realm.subscriptions;

업데이트 차단 내에서 설정된 구독에 대해 모든 변형을 수행해야 합니다. 업데이트 차단을 만들려면 SubscriptionSet.update()를 호출합니다.

업데이트 블록 콜백 함수에는 MutableSubscriptionSet() 객체를 인수로 사용합니다. SubscriptionSet 에서 메서드를 수정하여 구독에 쿼리를 추가할 수 있습니다.

중요

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

MutableSubscriptionSet.add() 메서드는 세 개의 인수를 사용합니다.

  • RealmResults query: 필수입니다. Realm Query Language 쿼리를 사용하여 생성할 수 있는 RealmResults 객체입니다.

  • String name: 선택 사항입니다. 참조할 수 있는 구독의 이름입니다.

  • bool update: 선택 사항입니다. true인 경우 기존 이름으로 구독을 추가하면 기존 쿼리가 새 쿼리로 대체됩니다. 명명된 구독에만 사용하세요.

참고

중복 구독

동일한 쿼리로 이름이 없는 중복 구독을 추가하면 Realm에서 자동으로 제거합니다.동일한 이름 의 구독을 추가하는 것은 불가능 합니다. . 따라서 두 경우 모두 중복 구독은 무시됩니다.

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

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

final planeQuery = realm.all<Plane>();
final longTrainQuery = realm.query<Train>("numCars >= 5");
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.add(planeQuery, name: "planes");
mutableSubscriptions.add(longTrainQuery,
name: 'long-trains', update: true);
});
await realm.subscriptions.waitForSynchronization();

새 쿼리로 명명된 구독을 업데이트할 수 있습니다. 구독 쿼리를 업데이트하려면 SubscriptionSet.update() 을(를) 사용하여 업데이트 블록을 엽니다. 업데이트 블록의 콜백 함수에서 다음 인수를 MutableSubscriptionSet.add() 에 전달합니다.

  • 새 쿼리

  • 업데이트하려는 구독의 이름

  • update: true

이름이 지정되지 않은 구독은 업데이트할 수 없습니다. 또는 이름이 지정되지 않은 구독을 삭제 하고 원하는 쿼리를 사용하여 새 구독을 만들 수 있습니다.

다음 예에서는 장거리 열차를 10량 이상의 차량으로 구성된 모든 열차로 재정의합니다.

final longerTrainQuery = realm.query<Train>("numCars > 10");
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.add(longerTrainQuery,
name: 'long-trains', update: true);
});

구독 세트에서 구독을 제거하려면 다음을 수행합니다.

  • 지정된 쿼리로 단일 구독 제거

  • 지정된 이름의 단일 구독 제거

  • 구독 참고를 사용하여 단일 구독 제거

  • Realm 객체 유형에 대한 모든 구독 제거

  • 모든 구독 삭제

구독 쿼리를 제거하면 서버는 클라이언트 장치에서 동기화된 데이터도 제거합니다.

업데이트 차단 내에서 쿼리를 통해 특정 구독을 제거할 수 있습니다. SubscriptionSet.update() 로 업데이트 블록을 엽니다. SubscriptionMutableSubscriptionSet.removeByQuery()에 전달합니다.

다음 예제에서는 모든 Plane 객체에 대한 구독이 제거됩니다.

realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.removeByQuery(realm.all<Plane>());
});

업데이트 차단 내에서 특정 구독을 이름으로 제거할 수 있습니다. 이름을 MutableSubscriptionSet.removeByName()

realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.removeByName('long-trains');
});

구독에 대한 참조가 있는 경우 구독 을 제거할 수 있습니다. 객체. 구독 업데이트 블록 내에서 Subscription 참조를 MutableSubscriptionSet.remove()로 전달합니다.

final sub = realm.subscriptions[0];
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.remove(sub);
});

특정 Realm 객체 유형에 대한 모든 구독을 제거할 수 있습니다. 구독 업데이트 블록 내에서 MutableSubscriptionSet.removeByType()을 호출합니다.

realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.removeByType<Train>();
});

구독 업데이트 블록 내에서 MutableSubscriptionSet.clear()로 설정된 구독에서 명명되지 않은 모든 구독을 제거할 수 있습니다.

realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) {
mutableSubscriptions.clear();
});

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

Realm.subscriptions.waitForSynchronization() 사용 서버가 이 구독 집합을 확인할 때까지 기다립니다. 서버가 변경 사항을 거부하고 예외가 발생하는 경우.

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

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

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

await realm.subscriptions.waitForSynchronization();

Realm.subscriptions.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])은(는) 인덱스를 효과적으로 사용할 수 없습니다. 대소문자를 구분하지 않는 쿼리는 성능 문제를 일으킬 수 있으므로 사용하지 않는 것이 좋습니다.

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 쿼리에서는 두 목록을 비교하는 것이 불가능합니다. 이 구문은 Flexible Sync 쿼리 외에는 유효한 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"

Flexible Sync는 내장된 객체 또는 링크의 속성에 대한 쿼리를 지원하지 않습니다. 예시: obj1.field == "foo"

구독 설정하다 에 있는 특정 쿼리 구독 의 크기 제한256 KB 입니다. 이 제한을 초과하면 LimitsExceeded 오류가 발생합니다.

쿼리 구독 섹션에 설명된 .subscribe() API를 사용하여 여러 구독을 관리하는 것은 구독 세트 API를 통해 구독을 수동으로 관리할 때 배치 업데이트를 수행하는 것보다 효율성이 떨어집니다. 구독을 여러 번 변경할 때 성능을 향상하려면 수동으로 구독 관리 섹션에 설명된 subscriptions.update API를 사용하세요.

구독 세트에 대한 모든 쓰기 트랜잭션(write transaction)에는 성능이 소모됩니다. 세션 중에 영역 객체를 여러 번 업데이트해야 하는 경우 모든 변경이 완료될 때까지 편집한 객체를 메모리에 보관하는 것이 좋습니다. 이렇게 하면 모든 변경 사항 대신 완전하고 업데이트된 객체만 영역에 기록하므로 동기화 성능이 향상됩니다.

돌아가기

동기화 Realm 열기