iosmongodbrealmmongodb-realm

Disable Realm Sync only for non-premium users


I'm creating an iOS application, where I intend to provide data sync across device feature, only to the premium users. I find Realm Sync as a good solution to keep the local on-device database and cloud MongoDB Atlas in sync. However, I don't want to sync the data of the non-premium users to the cloud database.

I'm enlisting a couple of ways that I can think of to prevent Realm Sync from triggering for non-premium users, but I'm not sure on what is the best way for this problem.

I'm looking for insights / recommended approach to this problem.

Edit

I've a few additional questions about handling two use cases differently - non-premium one by opening a local only Realm() and the premium one with Realm.asyncOpen().

  1. How to handle a use case when an existing user switches to a premium subscription? Should calling Realm.asyncOpen() suffice or do I need to do any special handling?
  2. I plan to sync all my User (custom document in a collection) records for all users (premium + non-premium). My guess is I should open a normal Realm for all my conent and synced Realm with just [User.self] object in the configuration.

Solution

  • This is super easy to do!

    When you only want to work with a local realm, connect to it with no config - like this

    let realm = try! Realm()
    let someObject = realm.results(SomeObject.self)
    

    or a config that maybe contains a local file name. All of the app data will only be read and written locally with no sync'ing.

    When you want to use MongoDB Realm Sync, connect to it like this

    let app = App(id: YOUR_REALM_APP_ID)
    // Log in...
    let user = app.currentUser
    let partitionValue = "some partition value"
    var configuration = user!.configuration(partitionValue: partitionValue)
    Realm.asyncOpen(configuration: configuration) { result in
        switch result {
        case .failure(let error):
            print("Failed to open realm: \(error.localizedDescription)")
            // handle error
        case .success(let realm):
            print("Successfully opened realm: \(realm)")
            // Use realm
        }
    }
    

    and then later with a config

    let config = user?.configuration(partitionValue: "some partition")
    let realm = try! Realm(configuration: config)
    

    EDIT

    Answering the two followup question:

    How to handle a use case when an existing user switches to a premium subscription? Should calling Realm.asyncOpen() suffice or do I need to do any special handling?

    Connecting to MongoDB Realm with the Sync'ding solution will add additional files and start syncing. If this is a new user that's 'premium', theres nothing else to do, other than (initially) ensure your objects are correctly structured with _id and partitionKey properties.

    If this user is upgrading from a non-premium local only to a premium that's sync'd you will need to copy your realm objects from the local only realm to a sync'd realm.

    There are several ways to to that; probably the simplist is to include code in your app then when upgrading, connects to a sync realm (using .async), then connects to your existing local realm and finally iterate over the objects to copy to the sync'd realm.

    Another option is to export the the realm objects as JSON and then write them to the server directly. The next time your app connects with .async, it will force a client reset and download and create the locally sync'd files. There are some tidbits of information that may help with this particular process in the Realm Legacy Migration Guide

    I plan to sync all my User (custom document in a collection) records for all users (premium + non-premium). My guess is I should open a normal Realm for all my conent and synced Realm with just [User.self] object in the configuration.

    Non-premium users don't sync so they are not really 'users' as such. You wouldn't need to store them or sync them so you really don't need any authentication or store any data on the server - it's just a locally run and used app so there isn't even a 'user' object to worry about. You will need to do that once they upgrade.