managed 동기화 구독 - Node.js SDK
이 페이지의 내용
- 전제 조건
- 쿼리 구독
- 쿼리 구독
- 구독 이름 없이 쿼리 구독하기
- 쿼리 구독이 동기화될 때까지 기다리기
- 쿼리 구독 취소
- 수동으로 구독 관리하기
- 모든 구독 가져오기
- 구독 추가
- 초기 구독 설정
- 구독 상태 확인
- 구독 상태 "완료"
- 새 쿼리로 구독 업데이트하기
- 구독 제거
- 쿼리로 구독 제거
- 이름으로 구독 제거
- 참조로 구독 제거
- 객체 유형에 대한 모든 구독 제거하기
- 이름 없는 모든 구독 제거
- 모든 구독 제거
- 성능 고려 사항
- API 효율성
- 성능 향상을 위한 그룹 업데이트
- Flexible Sync RQL 요구 사항 및 제한 사항
- 인덱싱된 쿼리 가능 필드 구독 요구 사항
- Flexible Sync에서 지원되지 않는 쿼리 연산자
- 목록 쿼리
- 임베디드 또는 링크된 객체
- 쿼리 크기 제한
Flexible Sync는 구독 및 권한을 사용하여 앱과 동기화할 데이터를 결정합니다. Flexible Sync가 활성화된 영역에서 읽기 또는 쓰기 (write)를 하려면 먼저 구독이 하나 이상 있어야 합니다. 이 페이지에서는 이러한 구독을 managed 방법에 대해 자세히 설명합니다.
쿼리 구독을 추가, 업데이트 및 제거하여 클라이언트 기기에 동기화할 데이터를 제어할 수 있습니다. Realm Node.js SDK v12.0.0 이상에서는 수동으로 구독을 관리하는 대신 또는 추가로 쿼리를 구독할 수 있습니다.
데이터 수집 및 비대칭 객체 는 앱의 백엔드 로만 데이터를 전송하므로 구독을 만들 수 없습니다.
중요
Flexible Sync 쿼리 제한 사항
Flexible Sync 구독은 RQL 쿼리 연산자의 하위 집합만 지원합니다. 지원되지 않는 연산자에 대한 자세한 내용은 Flexible Sync RQL 제한 사항 문서 를 참조하세요.
전제 조건
Node.js SDK와 함께 Atlas Device Sync를 사용하려면 먼저 다음 요구 사항을 충족해야 합니다.
MongoDB 5.0 이상을실행 하는 비샤드형 Atlas cluster .
Realm JavaScript 버전 10.12.0 또는 그 이후 버전.
Node.js 클라이언트에서 Flexible Sync를 사용하려면 요구 사항 외에도 다음을 설정해야 합니다.
쿼리 구독
버전 12.0.0의 새로운 기능.
Realm Node.js v12.0.0에는 쿼리 결과를 구독하거나 구독 취소하는 실험적 API가 추가되었습니다. 이러한 API는 수동으로 구독을 추가하고 제거하는 세부 사항을 추상화합니다.
모든 구독에 인증된 사용자와 Flexible Sync 영역이 필요합니다.
버전 12.3.0에서 변경됨: Atlas Device Sync에서 지원되는 지리 공간적 데이터
Realm Node.js SDK v12.3.0 이상에서는 지리 공간적 쿼리에 대한 구독을 생성할 수 있습니다. 이전 버전의 SDK에서 지리 공간적 쿼리를 구독하려고 하면 보정용 쓰기와 함께 서버 오류가 발생합니다.
자세한 내용은 지리 공간적 데이터 쿼리를 참조하세요.
쿼리 구독
구독에 이름을 지정하는 것이 좋습니다. 이렇게 하면 구독을 더 쉽게 찾고 관리할 수 있습니다. 구독 이름은 고유해야 합니다. 기존 구독과 동일한 이름으로 구독을 추가하려고 하면 오류가 발생합니다.
쿼리를 구독하려면 다음과 같이 하세요:
읽고 쓰고자 하는 객체를 쿼리합니다.
쿼리 결과에서
subscribe()
를 호출하여 쿼리와 일치하는 객체에 대한 동기화 구독을 만듭니다.SubscriptionOptions
객체에name
속성을 포함시켜subscribe()
함수에 전달합니다.
const subOptions = { name: "All completed tasks", }; const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe(subOptions); const completedTasksSubscription = realm.subscriptions.findByName( "All completed tasks" ); // ...work with the subscribed results list or modify the subscription
const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe({ name: "All completed tasks" }); const completedTasksSubscription = realm.subscriptions.findByName( "All completed tasks" ); // ...work with the subscribed results list or modify the subscription
구독 이름 없이 쿼리 구독하기
대부분의 경우 구독에 이름을 지정해야 합니다. 그렇지 않으면 이름은 null로 설정됩니다.
이름이 지정되지 않은 쿼리 구독에 filtered()
를 사용하는 경우 구독 식별자는 filtered
쿼리를 기반으로 합니다. 이는 쿼리 문자열이 변경될 때마다 subscribe()
가 새 구독을 생성한다는 의미입니다.
const config = { schema: [Task], sync: { user: app.currentUser, flexible: true, }, }; const realm = await Realm.open(config); const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe(); // ...work with the subscribed results list
const config: Realm.Configuration = { schema: [Task], sync: { user: app.currentUser!, flexible: true, }, }; const realm = await Realm.open(config); const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe(); // ...work with the subscribed results list
쿼리 구독이 동기화될 때까지 기다리기
쿼리 결과를 구독하는 경우 동기화된 데이터가 다운로드될 때까지 결과에는 객체가 포함되지 않습니다. 동기화된 객체의 다운로드가 완료될 때까지 기다려야 하는 경우 waitForSync
을 사용합니다. 구독에 대한 다양한 동작과 다운로드 위팅을 처리하는 방법을 지정할 수 있습니다.
이 예시에서는 기본 동작인 FirstTime
옵션을 사용합니다. FirstTime
동작이 있는 구독은 구독이 처음 생성될 때 동기화가 완료될 때까지만 기다립니다.
import { WaitForSync } from "realm"; // Get tasks that have a status of "in progress". const completedTasks = realm .objects(Task) .filtered("status == 'completed'"); // Only waits for sync to finish on the initial sync. await completedTasks.subscribe({ behavior: WaitForSync.FirstTime, name: "First time sync only", });
지원되는 다른 WaitForSync
옵션은 다음과 같습니다.
Always
: 앱이 실행될 때마다 일치하는 객체를 다운로드할 때까지 기다립니다. 앱을 실행할 때마다 인터넷에 연결되어 있어야 합니다.Never
: 일치하는 객체를 다운로드하기 위해 기다리지 마세요. 앱을 처음 실행할 때는 사용자가 인증하기 위해 인터넷 연결이 필요하지만, 이후 실행 시 캐시된 자격 증명을 사용하여 오프라인으로 열 수 있습니다.
선택적으로 timeout
값을 지정하여 동기화 다운로드가 실행되는 시간을 제한할 수 있습니다.
import { WaitForSync } from "realm"; // Get tasks that have a status of "in progress". const completedTasks = realm .objects(Task) .filtered("status == 'completed'"); // Add subscription with timeout // If timeout expires before sync is completed, currently-downloaded // objects are returned and sync download continues in the background. const taskSubscription = await completedTasks.subscribe({ behavior: WaitForSync.Always, timeout: 500, });
쿼리 구독 취소
unsubscribe()
을(를) 사용하여 쿼리 결과의 구독을 취소할 수 있습니다.
import { WaitForSync } from "realm"; // Get tasks that have a status of "in progress". const completedTasks = realm .objects(Task) .filtered("status == 'completed'"); // Only waits for sync to finish on the initial sync. await completedTasks.subscribe({ behavior: WaitForSync.FirstTime, name: "First time sync only", }); // Unsubscribe completedTasks.unsubscribe();
이렇게 하면 수동으로 구독을 제거하는 것과 유사하게 활성 구독 목록에서 구독이 제거됩니다.
겹치는 객체가 포함된 다른 구독이 있는 경우 unsubscribe()
을(를) 호출한 후에도 결과 목록에 여전히 객체가 포함될 수 있습니다.
unsubscribe()
을(를) 호출하면 연결된 구독이 제거됩니다. 구독은 이름으로 제거됩니다. 이름이 없으면 unsubscribe()
은(는) unsubscribe()
을(를) 호출한 쿼리와 정확히 일치하는 쿼리를 모두 제거합니다.
제거된 구독과 일치하는 객체가 영역에서 삭제되기 전에 unsubscribe()
메서드가 반환됩니다. 동기화는 새 구독 세트를 기반으로 백그라운드에서 계속됩니다.
수동으로 구독 관리하기
구독 API 를 사용하여 쿼리 쿼리 가능 필드 의 특정 쿼리에 대한 구독 설정하다 를 수동으로 관리 있습니다.
다음을 수행할 수 있습니다.
모든 구독 목록 보기
구독 추가
구독 상태 확인
새 쿼리로 구독 업데이트
개별 구독 또는 특정 유형의 모든 구독을 제거합니다.
데이터가 구독과 일치하고 적절한 권한이 있으면 기기와 백엔드 애플리케이션 간에 동기화됩니다.
구독을 생성하면 Realm은 특정 객체 유형에 대한 쿼리와 일치하는 데이터를 찾습니다. 여러 가지 다른 객체 유형에 대한 구독을 가질 수 있습니다. 동일한 객체 유형에 대해 여러 개의 쿼리를 가질 수도 있습니다.
중요
객체 링크
링크된 객체를 보려면 객체와 해당 링크된 객체를 모두 구독 세트에 추가해야 합니다.
구독 결과에 결과에 포함되지 않은 객체에 연결되는 속성이 있는 객체가 포함된 경우 해당 링크는 null로 표시됩니다. 해당 속성 값이 실제 null인지, 아니면 링크된 객체가 존재하지만 쿼리 구독의 표시 영역에서 벗어난 것인지 구분할 방법이 없습니다.
모든 구독 가져오기
유연한 동기화 Realm을 사용하는 경우 realm.subscriptions 메서드 를 통해 구독 컬렉션 SubscriptionSet
에 액세스할 수 있습니다. 속성.
// get the SubscriptionSet for the realm const subscriptions = realm.subscriptions;
구독 추가
다음 예시에서는 completed
및 progressMinutes
이(가) App Services App에서 쿼리 가능한 필드로 설정되어 있습니다. 클라이언트 코드에서 필터링된 쿼리를 생성한 다음 그 결과를 구독합니다.
완료된 작업
120 이상 걸린 완료된 작업
progressMinutes
const tasks = realm.objects("Task"); const longRunningTasks = tasks.filtered( 'status == "completed" && progressMinutes > 120' ); await realm.subscriptions.update((mutableSubs) => { mutableSubs.add(longRunningTasks, { name: "longRunningTasksSubscription", }); mutableSubs.add(realm.objects("Team"), { name: "teamsSubscription", }); });
초기 구독 설정
Flexible Sync 영역에서 읽거나 쓰려면 먼저 구독이 하나 이상 있어야 합니다. 영역을 열 때 초기 구독을 추가할 수 있습니다.
초기 구독을 설정하려면 Realm의 SyncConfiguration 에 initialSubscriptions
필드를 포함하세요. initialSubscriptions
객체 내에서 쿼리를 구독하는 콜백에 update
필드 세트를 추가합니다.
const config = { schema: [Task], sync: { user: app.currentUser, flexible: true, initialSubscriptions: { update: (subs, realm) => { subs.add(realm.objects(Task).filtered("status == 'in progress'"), { name: "In progress tasks", }); }, rerunOnOpen: true, }, }, }; const realm = await Realm.open(config);
const config: Realm.Configuration = { schema: [Task], sync: { user: app.currentUser!, flexible: true, initialSubscriptions: { update: (subs, realm) => { subs.add(realm.objects(Task).filtered("status == 'in progress'"), { name: "In progress tasks", }); }, rerunOnOpen: true, }, }, }; const realm = await Realm.open(config);
기본적으로 초기 구독은 영역이 처음 열릴 때만 생성됩니다. 앱이 시작될 때마다 이 초기 구독을 다시 실행해야 하는 경우 rerunOnOpen
을(를) true
(으)로 설정할 수 있습니다. 동적 시간 범위 또는 구독에 대한 정적 변수를 다시 계산해야 하는 기타 쿼리를 다시 실행하려면 이 작업을 수행해야 할 수 있습니다.
구독 상태 확인
구독 상태 를 확인하여 서버 가 구독 을 승인했는지, 장치가 로컬로 데이터를 다운로드했는지 확인할 수 있습니다.
구독 상태를 사용하여 다음을 수행할 수 있습니다.
Trigger error handling
트랜잭션이 보류 중인지 또는 완료되었는지 표시
구독 세트 대체 시기를 확인하고 구독 변경 사항을 작성하려면 해당 구독 세트의 새 인스턴스를 가져와야 합니다
참고
구독 상태 "완료"
구독 세트 상태 "완료" 는 "동기화가 완료됨" 또는 "모든 문서가 동기화됨" 을 의미하지 않습니다. "완료" 는 다음 두 가지를 의미합니다:
구독이 현재 서버와 동기화되고 있는 활성 구독 세트가
이제 구독이 서버로 전송될 때 구독과 일치했던 문서가 로컬 장치에 존재합니다. 여기에는 현재 구독과 일치하는 모든 문서가 반드시 포함되는 것은 아닙니다.
Realm SDK는 구독과 일치하는 모든 문서가 기기에 동기화되었는지 확인하는 방법을 제공하지 않습니다.
버전 12.0.0의 새로운 기능.
Node.js v12.0.0 구독 상태를 가져오는 데 사용할 수 있는 SubscriptionSetState 열거형 을 추가했습니다.
구독 상태 "완료"
구독 세트 상태 "완료" 는 "동기화가 완료됨" 또는 "모든 문서가 동기화됨" 을 의미하지 않습니다. "완료" 는 다음 두 가지를 의미합니다:
구독이 현재 서버와 동기화되고 있는 활성 구독 세트가
이제 구독이 서버로 전송될 때 구독과 일치했던 문서가 로컬 장치에 존재합니다. 여기에는 현재 구독과 일치하는 모든 문서가 반드시 포함되는 것은 아닙니다.
Realm SDK는 구독과 일치하는 모든 문서가 기기에 동기화되었는지 확인하는 방법을 제공하지 않습니다.
새 쿼리로 구독 업데이트하기
새 쿼리로 이름이 지정된 구독을 업데이트할 수 있습니다. 구독 쿼리를 업데이트하려면 업데이트하려는 구독 이름과 함께 새 쿼리와 구독 옵션을 MutableSubscriptionSet.add()
메서드에 전달합니다. 새 구독을 추가하는 것과 마찬가지로 subscriptions.update()
를 호출하여 트랜잭션 내에서 구독을 업데이트해야 합니다.
다음 예에서는 장기 실행 작업을 180분 이상 소요된 모든 작업으로 재정의합니다.
realm.subscriptions.update((mutableSubs) => { mutableSubs.add( tasks.filtered('status == "completed" && progressMinutes > 180'), { name: "longRunningTasksSubscription", } ); });
참고
SubscriptionOptions.throwOnUpdate
필드가 true로 설정된 구독을 업데이트하려고 하면 예외가 발생합니다.
구독 제거
여러 가지 방법으로 구독을 제거할 수 있습니다.
특정 쿼리로 단일 구독 제거
특정 이름으로 단일 구독 제거
특정 객체 모델에 대한 모든 구독 제거
이름 없는 모든 구독 제거
모든 구독 삭제
구독 쿼리를 제거하면 서버는 클라이언트 장치에서 동기화된 데이터도 제거합니다.
쿼리로 구독 제거
구독 설정하다 에서 트랜잭션 을 실행하여 쿼리 를 통해 특정 구독 을 제거 할 수 있습니다. 트랜잭션 내에서 MutableSubscriptionSet
의 제거 () 메서드에 쿼리 를 전달합니다.
다음 예제에서는 소유자가 'Ben'인 작업에 대한 구독이 구독 세트에서 제거됩니다.
realm.subscriptions.update((mutableSubs) => { // remove a subscription with a specific query mutableSubs.remove(tasks.filtered('owner == "Ben"')); });
이름으로 구독 제거
이름으로 특정 구독 을 제거 하려면 구독 설정하다 에서 트랜잭션 을 실행합니다. 트랜잭션 내에서 MutableSubscriptionSet
의 removeByName() 메서드에 이름을 전달합니다.
realm.subscriptions.update((mutableSubs) => { // remove a subscription with a specific name mutableSubs.removeByName("longRunningTasksSubscription"); });
참조로 구독 제거
구독에 대한 참조가 있는 경우 해당 구독을 제거할 수 있습니다. 이렇게 하려면 구독 세트에서 트랜잭션을 실행합니다. 트랜잭션 내에서 MutableSubscriptionSet
의 removeSubscription 메서드에 참조 변수를 전달합니다.
let subscriptionReference; realm.subscriptions.update((mutableSubs) => { subscriptionReference = mutableSubs.add(realm.objects("Task")); }); // later.. realm.subscriptions.removeSubscription(subscriptionReference);
객체 유형에 대한 모든 구독 제거하기
특정 객체 유형에 대한 모든 구독을 제거 하려면 구독 설정하다 에서 트랜잭션 을 실행합니다. 트랜잭션 내에서 string 의 removeByObjectType 메서드에 객체 유형을 로 MutableSubscriptionSet
전달합니다.
realm.subscriptions.update((mutableSubs) => { mutableSubs.removeByObjectType("Team"); });
이름 없는 모든 구독 제거
버전 v12.0.0의 새로운 기능.
일시적이거나 동적으로 생성된 이름 없는 구독을 제거하고 이름이 지정된 구독은 그대로 두는 것이 좋습니다.
mutableSubs
에서 .removeUnnamed()
을(를) 호출하여 구독 세트에서 명명되지 않은 모든 구독을 제거할 수 있습니다. .removeUnnamed()
은(는) 제거된 명명되지 않은 구독 수를 반환합니다.
// Remove unnamed subscriptions. let numberRemovedSubscriptions = 0; await realm.subscriptions.update((mutableSubs) => { numberRemovedSubscriptions = mutableSubs.removeUnnamed(); });
모든 구독 제거
구독 세트에서 모든 구독을 제거 하려면 구독 설정하다 에서 트랜잭션 을 실행 설정하다. 트랜잭션 내의 MutableSubscriptionSet
에서 removeAll() 을 호출합니다.
realm.subscriptions.update((mutableSubs) => { mutableSubs.removeAll(); });
성능 고려 사항
API 효율성
쿼리 구독 섹션에 설명된 subscribe()
및 unsubscribe()
API를 사용하여 여러 구독을 관리하는 것은 수동으로 구독을 관리할 때 배치 업데이트를 수행하는 것보다 효율성이 떨어집니다.
구독을 여러 번 변경할 때 성능을 향상하려면 subscriptions
API를 사용하여 단일 트랜잭션으로 모든 구독을 업데이트합니다. 방법을 알아보려면 수동으로 구독 관리하기를 참조하세요.
성능 향상을 위한 그룹 업데이트
구독 세트에 대한 모든 쓰기 트랜잭션(write transaction)에는 성능이 소모됩니다. 세션 중에 영역 객체를 여러 번 업데이트해야 하는 경우 모든 변경이 완료될 때까지 편집한 객체를 메모리에 보관하는 것이 좋습니다. 이렇게 하면 모든 변경 사항 대신 완전하고 업데이트된 객체만 영역에 기록하므로 동기화 성능이 향상됩니다.
Flexible Sync RQL 요구 사항 및 제한 사항
인덱싱된 쿼리 가능 필드 구독 요구 사항
앱에 인덱싱된 쿼리 가능 필드 를 추가하면 강력하게 분할된 데이터에 대한 간단한 쿼리의 성능을 향상시킬 수 있습니다. 예를 들어 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 < 10
는AND
가 전체 쿼리가 아니라 옆에 있는 용어에만 적용되므로 유효하지 않습니다.인덱싱된 쿼리 가능 필드가 동등 연산자에 사용되지 않는 경우.예를 들어
store_id > 2 AND region=="Northeast"
는>
연산자만 인덱싱된 쿼리 가능 필드에 사용하고 동등 비교는 없기 때문에 유효하지 않습니다.인덱싱된 쿼리 가능 필드가 쿼리에서 완전히 누락된 경우.예를 들어
region=="Northeast
또는truepredicate
는 인덱싱된 쿼리 가능 필드를 포함하지 않으므로 유효하지 않습니다.
Flexible Sync에서 지원되지 않는 쿼리 연산자
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 오류가 발생합니다.