New article – Migrating Your iOS App's Synced Realm Schema in Production

In a recent post, I demonstrated how to migrate your Realm data when you upgraded your iOS app with a new schema. But, that only handled the data in your local, standalone Realm database. What if you’re using MongoDB Realm Sync to replicate your local Realm data with other instances of your mobile app and with MongoDB Atlas?

I’ve just released a follow-on post — Migrating Your iOS App’s Synced Realm Schema in Production — that steps through how to migrate a synced Realm schema.

I start with the original RChat app. I then extend the iOS app and backend Realm schema to add a new feature that allows chat messages to be tagged as high priority. The next (and perhaps surprisingly more complicated from a Realm perspective) upgrade is to make the author attribute of the existing ChatMessage object non-optional.

Hey Andrew.

Now that I have an app in production, of course I needed these, so thanks for your work here.

I ran into an issue while attempting to add new properties today. I noticed that you had written this:

Unlike with standalone realms, we don’t need to signal to the Realm SDK that we’ve updated the schema by providing a schema version.

I added two new properties to the schema in the backend Realm app and to the schema in my client.

When attempting to run the new version over the top of the old version, I’m getting this error:

It seems from this error that migration is required. I also tried to add

.environment(\.realmConfiguration, Realm.Configuration(schemaVersion: 1))

to the ContentView(), but that didn’t seem to help either.

I didn’t make any destructive changes so I didn’t go through the more complicated tail end of your post, but I’m hoping to see what I may be doing wrong that is requiring a migration here.

Maybe there is a nuance that might be helpful to add to the post for future readers as well.

Hi @Kurt_Libby1

When I first worked on this post, I also needed to provide a new schema version. If I recall correctly, I needed to move to realm-cocoa 10.13.0. What version are you using?

If you are on 10.13+ and still need to provide a schema version, I believe that you need to add it to the environment for every view that opens a synced realm (e.g., via @ObservedResults rather than just once for ContnentView.

Thanks @Andrew_Morgan,

I was below 10.13 so I updated to current (10.15.1).

The app loads and runs fine, but when I try to write to a Realm, it throws that error. My assumption is that I will need to provide a new schema version.

Can you update your post to indicate why you may or may not need to provide a schema version bump on the client?

Also, I’m using a user realm and a hunt realm, so all over the place I’m passing in different environments depending on what is needed in each view. 68 places in total.

For the syntax, I tried to add schema version like this:

app.currentUser!.configuration(schemaVersion: 1, partitionValue: "somePartition")

but that doesn’t work. I’m not sure how to add the schema version to the environment.

How should that be formatted?

Thanks again.

You can use this syntax to specify the version number in the view that’s working with the Realm:

ObservedResults(ChatMessage.self,
                     configuration: Realm.Configuration(schemaVersion: schemaVersion),
                     sortDescriptor: SortDescriptor(keyPath: "timestamp", ascending: true)) var chats

It would be good to understand why you’re being forced to provide a schema version for an additive change. If you’re able to provide a sample before and after project that has this behaviour, then I can try to reproduce and see whether there’s something that needs to be fixed.

I have to modifications to the schema is all. Both additions were optional bools added to Object

On the backend I added:

"hidden": {
  "bsonType": "bool"
}

to an object with

@Persisted var hidden: Bool?

in the client.

I also added

"visible": {
  "bsonType": "bool"
}

to a different object with

@Persisted var visible: Bool?

in the client.

If it helps to go deeper I could make some time to share my screen with you tomorrow or this weekend. Just let me know.

@Andrew_Morgan – If it helps, I’ve noticed that the app is also crashing when I dismiss the sheet that has ObservedResults that include one of the models that have a new prop. So dismissing the ObservedResults is causing the crash that says that a migration is needed.

Loading the results is fine. Dismissing them causes the crash.

@Andrew_Morgan

Wanted to give an update here.

I added

configuration: Realm.Configuration(schemaVersion: 1)

to all of the ObservedResults for the two types that have added fields.

I’m now searching through the docs and StackOverflow to see what I’m doing wrong, but I can’t figure it out. Everything just says that additive changes will work and the term ‘migration’ is so over crowded with the cloud>mongo shift that I don’t think I’ll be able to find it.

Should I open a support request?

Hi @Kurt_Libby1 sorry for the delay.

Are you able to create a sharable example of where this is happening? If I can reproduce an issue and cant find a solution, then I can work it with engineering.

I threw this together this morning. Original schema didn’t have a state value in the Address object. Added it and it throws the error when dismissing the details sheet.

Thanks Kurt, I can reproduce the issue.

I added a couple of changes to allow me to experiment and created a repo for it to share with the engineering team (https://github.com/ClusterDB/migrate-issue).

I’ll let you know when I hear anything

1 Like

Hi Kurt,

I think that I’ve found the issue with the mini-app you shared. When a view invokes a SwiftUI Sheet view, that view doesn’t inherit the environment (vs. when you embed a view within a view).

The fix is to add the Realm config to the Sheet’s environment.

Take a look at this branch (it works for me): https://github.com/ClusterDB/migrate-issue/tree/fix-sheets

1 Like

IT WORKS!

I added the realm configuration on any .sheet and/or .fullScreenCover that has a View in it and now it doesn’t crash.

No idea if this is actually fixed and how it should work or if this is a workaround, but thank you Andrew!
:clap:t3::clap:t3::clap:t3:

Good to hear that it works! The key is that Sheets don’t inherit the environment from the view that presents them (unlike embedding a view within a view). SwiftUI is great at hiding complexity, but it can sometimes mal mask what’s really going on.