유연한 동기화 구독 관리 - Swift SDK
이 페이지의 내용
- 개요
- 구독
- 객체 유형 구독
- 권한
- 클라이언트 앱에서 구독 관리하기
- 해당 페이지의 예제에 대한 정보
- 쿼리 구독
- 쿼리 구독
- 구독 이름으로 쿼리 구독하기
- 쿼리 구독이 동기화될 때까지 기다리기
- 쿼리 구독 취소
- 액터가 제한된 쿼리 구독하기
- 수동으로 구독 관리하기
- 구독 추가
- 구독 변경 사항이 Sync될 때까지 기다리기
- 구독 세트 상태
- 새 쿼리로 구독 업데이트하기
- 구독 제거
- 성능 고려 사항
- API 효율성
- 성능 향상을 위한 그룹 업데이트
- Flexible Sync RQL 요구 사항 및 제한 사항
- 인덱싱된 쿼리 가능 필드 구독 요구 사항
- 유연한 동기화에서 지원되지 않는 쿼리 연산자
- 목록 쿼리
- 임베디드 또는 링크된 객체
- 쿼리 크기 제한
개요
버전 10.22.0의 새로운 기능.
Flexible Sync는 구독 및 권한을 사용하여 앱과 동기화할 데이터를 결정합니다.
iOS 클라이언트에서 유연한 동기화를 사용하려면 다음과 같이 하세요:
수동으로 구독을 추가, 업데이트 및 제거하여 클라이언트 기기에 동기화할 데이터를 결정할 수 있습니다. Realm Swift SDK 버전 10.43.0 이상에서는 수동으로 구독을 관리하는 대신, 또는 그에 추가하여 쿼리를 구독할 수 있습니다.
팁
Flexible Sync는 결합을 지원합니다.
구독
백엔드에서 Flexible Sync를 구성할 때 클라이언트 애플리케이션이 구독을 사용하여 쿼리할 수 있는 필드를 지정합니다.
각 구독은 특정 객체 유형에 대한 쿼리 가능 필드 에 대한 쿼리에 해당합니다. 자세한 내용은 Atlas App Services 문서에서 쿼리 가능 필드 를 참조하세요.
각 쿼리 구독에 대해 Realm은 쿼리와 일치하는 데이터를 찾습니다. 사용자가 적절한 권한을 가진 구독과 일치하는 데이터는 클라이언트와 백엔드 애플리케이션 간에 동기화됩니다.
Realm Swift SDK 쿼리 엔진으로 쿼리를 구성할 수 있습니다.
객체 유형 구독
구독 세트는 객체 유형을 기반으로 합니다. 여러 유형의 Realm 객체가 있는 경우 여러 개의 구독이 있을 수 있습니다. 동일한 객체 유형에 대해 여러 개의 구독을 가질 수도 있습니다.
그러나 앱에서 관계 또는 비대칭 객체를 사용하는 경우 다음 사항에 유의하세요:
객체 링크
링크된 객체를 보려면 객체와 해당 링크된 객체를 모두 구독 세트에 추가해야 합니다.
구독 결과에 결과에 포함되지 않은 객체에 연결되는 속성을 가진 객체가 포함된 경우 해당 링크는 nil로 표시됩니다. 해당 속성 값이 실제 nil인지, 아니면 링크된 객체가 존재하지만 쿼리 구독의 표시 영역에서 벗어난 것인지 구분할 방법이 없습니다.
비대칭 객체
앱에서 데이터 수집을 사용하여 비대칭 객체를 단방향으로 동기화하는 경우 해당 객체에 대한 구독을 만들 수 없습니다. 앱의 동일한 영역에 비대칭 객체와 그렇지 않은 객체가 있는 경우, 비대칭 객체에 대한 Flexible Sync 구독 쿼리를 추가할 수 있습니다.
권한
구독은 클라이언트 애플리케이션에 Sync할 데이터를 결정하는 권한과 함께 작동합니다. 클라이언트 애플리케이션은 구독과 일치하는 데이터의 하위 집합만 볼 수 있으며, 해당 구독은 동시에 로그인한 사용자의 권한과 일치해야 합니다.
이 페이지에서는 Flexible Sync에 대한 클라이언트 구독을 관리하는 방법에 대해 자세히 설명합니다. Flexible Sync에 대한 권한 설정에 대한 자세한 내용은 Flexible Sync 규칙 및 권한을 참조하세요.
클라이언트 앱에서 구독 관리하기
클라이언트 애플리케이션에서 쿼리 가능 필드의 특정 쿼리에 대한 구독을 추가, 업데이트 및 제거합니다. 이에 따라 클라이언트 장치에 동기화할 데이터가 결정됩니다.
다음을 수행할 수 있습니다.
선택 사항인 구독 이름을 사용하여 구독을 추가합니다:
Realm Swift SDK 버전 10.43.0 이상에서는
.subscribe()
을(를) 사용하여Results
쿼리를 구독할 수 있습니다. 이렇게 하면 자동으로 구독 세트에 구독이 추가됩니다.subscriptions
API를 사용하여 구독 세트에 수동으로 구독을 추가합니다. 성능 최적화 또는 비즈니스 로직상의 이유로 구독에 대한 더 많은 제어가 필요한 경우 이 API를 사용하세요. 자세한 내용은 성능 고려 사항을 참조하세요.
구독 상태에 React
새 쿼리로 구독 업데이트
객체 유형에 대한 개별 구독 또는 모든 구독 제거
해당 페이지의 예제에 대한 정보
이 페이지의 예제에서는 작업 목록 앱의 간단한 데이터 세트를 사용합니다. 두 가지 Realm 객체 유형은 Team
및 Task
입니다. Task
에는 taskName
, 담당자 이름 및 완료 플래그가 있습니다. 또한 작업을 마치는 데 걸린 시간(분)과 마감일도 표시됩니다. Team
에는 teamName
, 0개 이상의 Tasks
및 members
목록이 있습니다.
class Task: Object { true) var _id: ObjectId (primaryKey: var taskName: String var assignee: String? var completed: Bool var progressMinutes: Int var dueDate: Date } class Team: Object { true) var _id: ObjectId (primaryKey: var teamName: String var tasks: List<Task> var members: List<String> }
이 페이지의 예에서는 인증된 사용자와 유연한 동기화 구성이 있다고 가정합니다.
let app = App(id: APPID) do { let credentials = emailPasswordCredentials(app: app) let user = try await app.login(credentials: credentials) var flexSyncConfig = user.flexibleSyncConfiguration() flexSyncConfig.objectTypes = [Task.self, Team.self] do { // Open the synced realm and manage Flexible Sync subscriptions } catch { print("Failed to open realm: \(error.localizedDescription)") // handle error } } catch { fatalError("Login failed: \(error.localizedDescription)") }
쿼리 구독
버전 10.43.0의 새로운 기능.
구독 관리를 간소화하기 위해 Realm Swift SDK 버전 10.43.0에서는 쿼리의 Results
세트에서 구독 및 구독 취소하는 API를 추가했습니다. 이러한 API는 수동으로 구독을 추가하고 제거하는 세부 사항을 추상화합니다.
중요
.subscribe() API를 Preview 중입니다.
여기에 설명된 .subscribe()
및 .unsubscribe()
API는 현재 Preview 중입니다. 이러한 API는 향후 변경될 수 있습니다.
쿼리 구독
인증된 사용자와 Flexible Sync 구성 을 사용하면 동기화된 Realm을 열고 읽고 쓰고자 하는 객체에 대해 쿼리할 수 있습니다. .subscribe() 해당 쿼리에 추가하여 쿼리와 일치하는 객체에 대한 Flexible Sync 구독을 만듭니다.
let realm = try await Realm(configuration: flexSyncConfig) let results = try await realm.objects(Task.self) .where { $0.progressMinutes >= 60 }.subscribe() // Go on to work with subscribed results
이렇게 하면 수동으로 구독을 만드는것과 유사하게 명명되지 않은 구독이 생성되어 MutableSubscriptionSet
에 추가됩니다.
구독 이름으로 쿼리 구독하기
앱이 여러 구독과 함께 작동하거나 구독을 업데이트하려는 경우 쿼리를 구독할 때 이름을 추가할 수 있습니다.
나중에 이 이름을 사용하여 구독 쿼리를 업데이트 하거나, 이름으로 구독을 확인 하거나, 이름 으로 쿼리를 제거할 수 있습니다.
let realm = try await Realm(configuration: flexSyncConfig) let results = try await realm.objects(Team.self) .where { $0.teamName == "Developer Education" } .subscribe(name: "team_developer_education") // Go on to work with subscribed results
쿼리 구독이 동기화될 때까지 기다리기
쿼리의 Results
세트를 구독하는 경우 해당 세트는 동기화될 때까지 객체를 포함하지 않습니다. 앱에서 객체를 생성하는 경우 사용자가 작업하기 전에 동기화된 데이터를 다운로드할 필요가 없을 수 있습니다. 그러나 앱이 사용자가 작업하기 전에 서버의 데이터가 필요한 경우 구독이 waitForSync
을(를) 수행하도록 지정할 수 있습니다.
let realm = try await Realm(configuration: flexSyncConfig) let results = try await realm.objects(Team.self) .where { $0.members.contains("Bob Smith") } .subscribe( name: "bob_smith_teams", waitForSync: .onCreation) // After waiting for sync, the results set contains all the objects // that match the query - in our case, 1 print("The number of teams that have Bob Smith as a member is \(results.count)")
이 옵션은 RLMWaitForSyncMode
열거형을 사용하며 그 사례는 다음과 같습니다.
.onCreation: 앱이 구독을 생성할 때 일치하는 객체를 다운로드할 때까지 기다립니다. 그렇지 않으면 새 다운로드를 기다리지 않고 돌아갑니다. 구독을 처음 추가할 때 앱이 인터넷에 연결되어 있어야 합니다.
.always:
.subscribe()
실행 시 일치하는 객체를 다운로드할 때까지 기다립니다..subscribe()
이(가) 실행될 때 앱이 인터넷에 연결되어 있어야 합니다..never: 일치하는 객체를 다운로드하기 위해 기다리지 않습니다. 앱을 처음 실행할 때는 사용자가 인증하기 위해 인터넷 연결이 필요하지만 이후 실행 시 캐시된 자격 증명을 사용하여 오프라인으로 열 수 있습니다.
선택적으로 timeout
TimeInterval유형의 값을 지정할 수 있습니다.
쿼리 구독 취소
.unsubscribe() 메서드 를 사용하여 쿼리의 Results
세트에서 API:
let realm = try await Realm(configuration: flexSyncConfig) let results = try await realm.objects(Task.self).where { $0.completed == false }.subscribe() // Go on to work with subscribed results. // Later... results.unsubscribe()
이렇게 하면 수동으로 구독을 제거하는것과 유사하게 MutableSubscriptionSet
에서 구독이 제거됩니다.
겹치는 객체를 포함하는 다른 구독이 있는 경우, .unsubscribe()
를 호출한 후에도 Results
집합에 객체가 계속 포함될 수 있습니다.
.unsubscribe()
호출은 객체가 영역에서 제거될 때까지 기다리지 않습니다. .unsubscribe()
이(가) 서버와 동기화될 때까지 대기하는 API가 없습니다.
액터가 제한된 쿼리 구독하기
MainActor에서 액터(actor)에 국한된 쿼리를 구독할 수 있습니다:
let realm = try await Realm(configuration: flexSyncConfig, actor: MainActor.shared) let results = try await realm.objects(Team.self) .where { $0.teamName == "Developer Education" } .subscribe(name: "team_developer_education") // Go on to work with subscribed results
또는 다음과 같이 사용자 지정 액터에 대한 쿼리를 구독할 수 있습니다.
let realm = try await Realm(configuration: flexSyncConfig, actor: CustomGlobalActor.shared) let results = try await realm.objects(Team.self) .where { $0.teamName == "Developer Education" } .subscribe(name: "team_developer_education") // Go on to work with subscribed results
액터가 제한된 Realm에 대한 자세한 내용은 액터가 포함된 Realm 사용 - Swift SDK를 참조하세요.
수동으로 구독 관리하기
subscriptions
API를 사용하여 쿼리 가능 필드의 특정 쿼리에 대한 구독 세트를 수동으로 관리할 수 있습니다.
다음을 수행할 수 있습니다.
구독 추가
구독 상태에 React
새 쿼리로 구독 업데이트
객체 유형에 대한 개별 구독 또는 모든 구독 제거
사용자가 적절한 권한을 가진 구독과 일치하는 데이터는 기기와 백엔드 애플리케이션 사이에 동기화됩니다.
구독에 대한 선택적 문자열 이름을 지정할 수 있습니다.
구독을 생성하면 Realm은 특정 객체 유형에 대한 쿼리와 일치하는 데이터를 찾습니다. 서로 다른 객체 유형에 대해 여러 개의 구독 집합을 가질 수 있습니다. 동일한 객체 유형에 대해 여러 개의 쿼리를 가질 수도 있습니다.
예제
명시적인 이름으로 구독을 만들 수 있습니다. 그런 다음 해당 구독을 이름으로 검색하여 업데이트하거나 제거할 수 있습니다.
QuerySubscription<Task>(name: "long-running-completed") { $0.completed == true && $0.progressMinutes > 120 }
구독에 대해 name
을(를) 지정하지 않으면 쿼리 문자열로 구독을 검색할 수 있습니다.
QuerySubscription<Team> { $0.teamName == "Developer Education" }
참고
중복 구독
구독 이름은 고유해야 합니다. 기존 구독과 이름이 같은 구독을 추가하려고 하면 오류가 발생합니다.
구독에 명시적으로 이름을 지정하지 않고 이름이 지정되지 않은 동일한 쿼리를 두 번 이상 구독하면 Realm은 구독 세트에 대한 중복 쿼리를 유지하지 않습니다.
같은 쿼리를 다른 이름으로 두 번 이상 구독하면 Realm은 구독 세트에 대한 두 구독을 모두 유지합니다.
구독 추가
구독 업데이트 블록에서 구독을 추가합니다. 클라이언트의 Realm 구독에 각각 새 구독을 추가합니다.
팁
앱이 async/await
컨텍스트에서 Realm에 액세스하는 경우 코드를 @MainActor
(으)로 표시하여 스레드 관련 충돌을 방지합니다.
let realm = try await getRealmWithSingleSubscription() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func getRealmWithSingleSubscription() async throws -> Realm { let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions try await subscriptions.update { subscriptions.append( QuerySubscription<Team> { $0.teamName == "Developer Education" }) } return realm }
다양한 객체 유형의 구독을 포함하여 하나의 구독 업데이트 블록 내에 구독을 여러 개 추가할 수 있습니다.
let realm = try await getRealmWithMultipleSubscriptions() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func getRealmWithMultipleSubscriptions() async throws -> Realm { let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions try await subscriptions.update { subscriptions.append( QuerySubscription<Task>(name: "completed-tasks") { $0.completed == true }) subscriptions.append( QuerySubscription<Team> { $0.teamName == "Developer Education" }) } return realm }
초기 구독으로 Realm 부트스트랩
버전 10.28.0의 새로운 기능
영역에서 읽거나 영역에 쓰기를 하려면 먼저 구독이 하나 이상 있어야 합니다. flexibleSyncConfiguration() 을 사용하여 열 때 초기 구독 세트가 있는 Realm을 부트스트랩할 수 있습니다. 영역을 부트스트랩하는 데 사용할 구독 쿼리와 함께 initialSubscriptions
매개변수를 전달합니다.
var flexSyncConfig = user.flexibleSyncConfiguration(initialSubscriptions: { subs in subs.append( QuerySubscription<Team> { $0.teamName == "Developer Education" }) })
앱이 시작될 때마다 이 초기 구독을 다시 실행해야 하는 경우 추가 매개 변수 rerunOnOpen
을 전달할 수 있습니다. 이는 앱이 시작될 때마다 초기 구독을 다시 실행할지 여부를 나타내는 부울입니다. 동적 시간 범위 또는 구독에 대한 정적 변수를 다시 계산해야 하는 기타 쿼리를 다시 실행하려면 이 작업을 수행해야 할 수 있습니다.
이 예에서는 관련 없는 작업으로 인해 사용자가 부담을 느끼지 않도록 하기 위해 이전 7일과 다음 7일 이내에 마감되는 작업만 로드합니다. 마감일이 일주일 이상 지난 작업은 더 이상 관련이 없으며, 마감일이 다음 주보다 더 먼 작업도 관련이 없습니다. 여기에 rerunOnOpen
을 사용하면 쿼리는 앱이 시작될 때마다 원하는 날짜 범위를 기준으로 동기화할 관련 객체를 동적으로 다시 계산합니다.
// Set the date a week ago and the date a week from now, as those are the dates we'll use // in the Flexible Sync query. `rerunOnOpen` lets the app recalculate this query every // time the app opens. let secondsInAWeek: TimeInterval = 604800 let dateLastWeek = (Date.now - secondsInAWeek) let dateNextWeek = (Date.now + secondsInAWeek) var flexSyncConfig = user.flexibleSyncConfiguration(initialSubscriptions: { subs in subs.append( QuerySubscription<Task> { $0.dueDate > dateLastWeek && $0.dueDate < dateNextWeek }) }, rerunOnOpen: true)
특정 유형의 모든 객체 구독하기
주어진 쿼리와 일치하는 모든 객체를 동기화하는 것 외에도, 특정 유형에 속하는 모든 객체를 구독할 수 있습니다. 쿼리를 제공하지 않고 구독을 추가하기만 하면 됩니다.
예를 들어 특정 팀을 보고 싶지 않고 대신 모든 Team
객체를 구독하려는 경우 다음과 같이 하면 됩니다.
let realm = try await subscribeToObjectsOfAType() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func subscribeToObjectsOfAType() async throws -> Realm { let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions try await subscriptions.update { subscriptions.append(QuerySubscription<Team>(name: "all_teams")) } XCTAssertEqual(subscriptions.count, 1) // :remove return realm }
구독을 추가하기 전에 기존 구독이 있는지 확인
애플리케이션 흐름이 애플리케이션을 실행할 때마다 동일한 이름의 구독을 구독 세트에 추가하는 경우 이는 허용되지 않습니다. 이 경우 구독을 추가하기 전에 기존 구독에 대한 확인을 추가합니다.
let realm = try await checkAndAddSubscription() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func checkAndAddSubscription() async throws -> Realm { let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions let foundSubscription = subscriptions.first(named: "user_team") try await subscriptions.update { if foundSubscription != nil { foundSubscription!.updateQuery(toType: Team.self, where: { $0.teamName == "Developer Education" }) } else { subscriptions.append( QuerySubscription<Team>(name: "user_team") { $0.teamName == "Developer Education" }) } } return realm }
구독 변경 사항이 Sync될 때까지 기다리기
로컬에서 구독 세트를 업데이트하는 것은 구독 변경의 한 구성 요소일 뿐입니다. 로컬 구독이 변경되면 구독 변경으로 인한 데이터 업데이트를 해결하기 위해 영역이 서버와 동기화됩니다. 이로 인해 동기화 영역에서 데이터가 추가되거나 제거될 수 있습니다.
사전 비동기화/대기
애플리케이션에서 Swift의 비동기/대기 기능을 사용하지 않는 경우 onComplete
차단을 사용하여 서버와 동기화되는 구독 변경에 반응할 수 있습니다. 이 차단은 구독이 서버와 동기화된 후에 호출됩니다. 예를 들어 UI를 다시 작성하거나, 데이터 세트의 변경 사항에 따라 다른 조치를 수행하여 구독 상태 변경에 반응하려면 onComplete
에서 이러한 조치를 수행할 수 있습니다. 또한 동기화 중에 발생하는 선택적 오류를 처리할 수도 있습니다.
let subscriptions = realm.subscriptions subscriptions.update({ subscriptions.append( QuerySubscription<Task> { $0.assignee == "John Doe" }) }, onComplete: { error in // error is optional if error == nil { // Flexible Sync has updated data to match the subscription } else { // Handle the error } })
비동기/대기
애플리케이션에서 비동기/대기를 사용하는 경우 onComplete
차단이 필요하지 않습니다. 업데이트는 비동기적으로 실행되며 업데이트가 성공적으로 완료되지 않으면 오류가 발생합니다.
func changeSubscription() async throws { let subscriptions = realm.subscriptions try await subcriptions.update { subscriptions.remove { QuerySubscription<Task> { $0.assignee == "Joe Doe" } } } }
팁
앱이 async/await
컨텍스트에서 Realm에 액세스하는 경우 코드를 @MainActor
(으)로 표시하여 스레드 관련 충돌을 방지합니다.
구독 세트 상태
구독 세트의 현재 상태를 읽으려면 SubscriptionSet.state 속성을 사용하세요.
superseded
상태는 다른 스레드가 구독 세트의 다른 인스턴스에서 구독을 업데이트할 때 발생할 수 있는 SyncSubscriptionState 입니다. 상태가 superseded
이 되면 구독 세트의 새 인스턴스를 가져와야 업데이트할 수 있습니다.
참고
구독 상태 "완료"
구독 세트 상태 "완료" 는 "동기화가 완료됨" 또는 "모든 문서가 동기화됨" 을 의미하지 않습니다. "완료" 는 다음 두 가지를 의미합니다:
구독이 현재 서버와 동기화되고 있는 활성 구독 세트가
이제 구독이 서버로 전송될 때 구독과 일치했던 문서가 로컬 장치에 존재합니다. 여기에는 현재 구독과 일치하는 모든 문서가 반드시 포함되는 것은 아닙니다.
Realm SDK는 구독과 일치하는 모든 문서가 기기에 동기화되었는지 확인하는 방법을 제공하지 않습니다.
새 쿼리로 구독 업데이트하기
updateQuery
을(를) 사용하여 구독 쿼리를 업데이트할 수 있습니다. 이 예제에서는 쿼리와 일치하는 구독을 검색한 다음 새 쿼리로 업데이트합니다.
let realm = try await getRealmWithUpdatedSubscriptions() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func getRealmWithUpdatedSubscriptions() async throws -> Realm { let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions try await subscriptions.update { if let foundSubscription = subscriptions.first(ofType: Team.self, where: { $0.teamName == "Developer Education" }) { foundSubscription.updateQuery(toType: Team.self, where: { $0.teamName == "Documentation" }) } } return realm }
Atlas Search에서 이름으로 구독을 검색 할 수도 있습니다. 이 예제에서는 이름으로 구독 쿼리를 Atlas Search한 다음 새 쿼리로 업데이트합니다.
let realm = try await getRealmWithUpdatedSubscriptionName() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func getRealmWithUpdatedSubscriptionName() async throws -> Realm { let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions let foundSubscription = subscriptions.first(named: "user-team") try await subscriptions.update { foundSubscription?.updateQuery(toType: Team.self, where: { $0.teamName == "Documentation" }) } return realm }
구독 제거
구독을 제거하려면 다음과 같이 하세요:
단일 구독 쿼리 제거
특정 객체 유형에 대한 모든 구독을 제거합니다.
이름 없는 모든 구독 제거
모든 구독 삭제
구독 쿼리를 제거하면 Realm은 클라이언트 장치에서 쿼리와 일치하는 동기화된 데이터를 비동기적으로 제거합니다.
단일 구독 제거
remove
을(를) 사용하여 구독 업데이트 차단에서 특정 구독 쿼리를 제거할 수 있습니다. 쿼리를 이름으로 지정하거나 쿼리를 문자열로 사용하여 제거할 적절한 구독 쿼리를 찾습니다.
let realm = try await getRealmAfterRemovingSubscription() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func getRealmAfterRemovingSubscription() async throws -> Realm { let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions // Look for a specific subscription, and then remove it let foundSubscription = subscriptions.first(named: "docs-team") try await subscriptions.update { subscriptions.remove(foundSubscription!) } // Or remove a subscription that you know exists without querying for it try await subscriptions.update { subscriptions.remove(named: "existing-subscription") } return realm }
객체 유형에 대한 모든 구독 제거하기
특정 객체 유형에 대한 모든 구독을 제거하려면 업데이트 블록에서 ofType
과 함께 removeAll
메서드를 사용합니다.
let realm = try await getRealmAfterRemovingAllSubscriptionsToAnObjectType() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func getRealmAfterRemovingAllSubscriptionsToAnObjectType() async throws -> Realm { let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions try await subscriptions.update { subscriptions.removeAll(ofType: Team.self) } return realm }
이름 없는 모든 구독 제거
버전 10.43.0의 새로운 기능.
일시적이거나 동적으로 생성된 이름 없는 구독을 제거하고 이름이 지정된 구독은 그대로 두는 것이 좋습니다.
removeAll
메서드를 호출할 때 unnamedOnly
을(를) true
(으)로 설정하여 구독 세트에서 명명되지 않은 모든 구독을 제거할 수 있습니다.
let realm = try await Realm(configuration: flexSyncConfig) // Add 2 subscriptions, one named and one unnamed. let results = try await realm.objects(Team.self).where { $0.teamName == "Developer Education" }.subscribe(name: "team_developer_education") let results2 = try await realm.objects(Task.self).where { $0.completed == false }.subscribe() // Later, remove only the unnamed one let subscriptions = realm.subscriptions try await subscriptions.update { subscriptions.removeAll(unnamedOnly: true) }
모든 구독 제거
구독 세트에서 모든 구독을 제거하려면 구독 업데이트 차단에서 removeAll
메서드를 사용합니다.
중요
모든 구독을 제거하고 새 구독을 추가하지 않으면 오류가 발생합니다. Flexible Sync 구성으로 열린 Realm의 경우, 서버와 동기화하려면 하나 이상의 구독이 필요합니다.
let realm = try await getRealmAfterRemovingAllSubscriptions() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func getRealmAfterRemovingAllSubscriptions() async throws -> Realm { let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions try await subscriptions.update { subscriptions.removeAll() } return realm }
성능 고려 사항
API 효율성
쿼리 구독 섹션에 설명된 .subscribe()
및 .unsubscribe()
API를 사용하여 여러 개의 구독을 추가하는 것은 수동으로 구독을 관리할 때 배치 업데이트를 수행하는 것보다 효율성이 떨어집니다. 모든 .subscribe()
에서 Swift SDK는 새 업데이트 블록을 엽니다. 여러 개의 구독을 추가할 때 성능을 향상하려면 수동으로 구독 관리 섹션에 설명된 subscriptions.update
API를 사용합니다.
성능 향상을 위한 그룹 업데이트
구독 세트에 대한 모든 쓰기 트랜잭션에는 성능이 소모됩니다. 세션 중에 Realm 객체를 여러 번 업데이트해야 하는 경우 모든 변경이 완료될 때까지 편집한 객체를 메모리에 보관하는 것이 좋습니다. 이렇게 하면 모든 변경 사항 대신 완전하고 업데이트된 객체만 영역에 기록하므로 동기화 성능이 향상됩니다.
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는 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"
이 있습니다.
쿼리 크기 제한
구독 세트에 있는 특정 쿼리 구독의 크기 제한 은 256 KB 입니다. 이 제한을 초과하면 LimitsExceeded 오류가 발생합니다.