Controlling Realm Flexible Sync Subscription based on User Settings

Please what is the best way to control flexible sync for a particular Realm Object based on User Settings in Realm Swift.

I have subscription setup for a Realm Object and want to add a query based on a flag on the client side.

subscriptions.append(
							QuerySubscription<TransactionObject>(name: RealmSyncSubscription.transactions.rawValue) {
								$0.ownerId == user.id
							}
						)

The subscription in the code above shows the query that determines if a TransactionObject should be synced or not but now I want users to be able to turn on/off syncing of this particular object alone with a flag and I’m not sure the best way to achieve this.

The initial approach I took is add a new property to the user object I used to setup RLMUser with custom data. The problem is trying to refresh the user custom data when the new property changes to set new flexible sync rule.

subscriptions.append(
				QuerySubscription<TransactionObject>(name: RealmSyncSubscription.transactions.rawValue) { object in
								// refresh custom data
								var syncingEnabled = false
								user.refreshCustomData { result in
									switch result {
									case .success(let customData):
										syncingEnabled = customData["syncingEnabled"]
										return
									
									case .failure(let failure):
										return
									}
								}
								
								return object.ownerId == user.id && syncingEnabled ⚠️ // Cannot convert value of type 'Bool' to expected argument type 'Query<Bool>'
							}
						)

The first problem I have is that user.refreshCustomData { } is asynchronous and don’t know if that would affect the performance of the app or the functionality of the subscription since the refresh would have to complete before returning whether the property is true or false.

Secondly, I’m not sure how to construct a valid Query for the subscription since this property is not part of the TransactionObject which I’m trying to setup subscription for so I get the error: “Cannot convert value of type ‘Bool’ to expected argument type ‘Query’”

Synced realms do not have a concept of “not syncing” a specific object. If you want the users to be able to “turn off Sync” for a specific object type, you would need to manage that particular object type with a non-synced realm. So your app logic would be something like “if customerSyncsTransaction, open a synced realm for that object type, else open a non-synced realm for that object type.” There are docs here on using configuration.objectTypes to manage the object types you’re using with a realm.

So with this in mind, the Flexible Sync query subscription would not need to care about the custom user data. It would be something you would check before determining whether to open a synced realm or a non-synced realm.

This gets more complex because the Swift SDK does not currently have an API that supports copying data between a Flexible synced realm and non-synced realm. So if you’d want to make existing transactions sync or not-sync as the user enables or disables this setting, you’d need to write your own logic to iterate over and copy those transactions between the synced and the non-synced realm.

1 Like

Okay, thanks for the explanation for the synced realm and non-synced realm.

What I mean by not syncing is just checking against a value that the subscription query doesn’t satisfy, similar to how I compare if an object’s ownerId matches the id of the currently logged in user to sync specific user’s data with their device.

The approach of copying data from one realm to another seems like a complex solution for the feature schedule as at this time.

Could you please suggest a way to write a query for the subscription based on an external boolean value that’s not a property of the object type? Basically I’m trying to work my way around the error: “Cannot convert value of type ‘Bool’ to expected argument type ‘Query’.

Thank you for your time.

The query is specific to the object type so I don’t believe you can query against a field that is not in the object from within the query. A better approach would be to check the external object field’s value before adding the query and then add or don’t add the query based on the value you’re checking. i.e. if customData[“syncingEnabled”] then append a subscription for the Transaction Object, else break or return or do something else instead.

1 Like

That makes a lot of sense. Thank you.