Realm Migration — Renaming a class and migrating nested objects
A few days ago, I opened an old project to update its architecture.
I intended to rename my Realm classes and also update some class’ attributes (for example, instead of storing a list of objects in a Realm object, I only wanted to store the object ID in the child object).
Usually, to rename a class the only thing we have to do is “Cmd + Maj + A”, and then “Rename”, but in the case of Realm, it’s a little bit more complex as we have to do a migration to avoid user datas losts.
For this article, I’ll take this example:
we have two classes (User and Sport) and here is the Realm objects structure before the migration:
Every sport has an ID, a name and a list of User, and every user has an ID, a first name, a last name and a Sport object.
Here is the Realm objects structure that I want at the end of the migration:
So, instead of storing a Sport object for a user, I intend to save only the ID of the sport. And for the Sport object, I don’t want to save the list of users anymore.
Also, I wanted to rename both classes and prefix them by R (R for Realm), because I intend to reuse the old classes name in my current code, for my UI objects.
Before starting the migration, I created the new classes (R classes) in my project and I removed the old ones (then, I also updated the application to be able to compile my project).
Let’s start the migration now!
To complete the migration and reach my goals, there are two steps:
- Rename both Realm classes in the database
- Don’t forget to migrate the user’s data!
Renaming a class
When I’m doing a class migration, I can create the new object (RSport for the Sport object for example), and then, I can remove the old object.
So, the truth is that we are not renaming a class, but we are creating a new class from the new object. Then, we migrate the user’s data and at the end, we remove the old object.
I’m going to explain the different steps:
- Lines 2 to 4: We recover the old object information (in this case, the ID and the sport’s name)
- Line 6: We ask the migration object to create the new R object (RSport)
- Lines 7 and 8: We associate the old object’s values to the new object to keep all user’s information
- Line 10: We remove the old object (Sport), as we don’t need it anymore
We’ve done the “renaming” of the first Realm object (Sport to RSport).
Now, let’s get the migration started, with a more complex object (this object contains another Realm object in it, so it’s a little bit different)
Migrate a complex Realm object included in another Realm object
Like the Sport object, we’re gonna start to create the new object (renaming the class), before starting to migrate all the attributes.
Again, like the Sport object, we loop on all old objects of the database, we get all the datas, we create new objects, we copy the data and then, we remove the old object as we don’t need it anymore.
Well done, but if we stop here, we loose the user’s sport…
The problem: how to get the id of the Sport object inside the User object that we want to migrate?
If we try to do it like all others attributes, we do this:
We get an object of type Any:
We can’t cast the object to the Sport type, as this class doesn’t exist anymore (remember, we deleted it before starting the migration process). Also, we can’t cast it to RSport type, because this class is not equivalent to the Sport type.
(But we can still see all information; that’s a good start!)
The only type in which we can still cast the object, it’s a type that the application still has. As we are working with Realm, and that all Realm objects inherit from the object “Object”, we can cast our object to the “Object” type:
We haven’t made progress here, as we didn’t have access to the ID of the Sport object yet.
If we try to do like the previous attribute, the compilator returns an error:
Use the value(forKey:) function, that allows us to get the ID value of the old Sport object:
So, we finally have:
Like this, you can access an object contained inside another object when you do a Realm migration. By the way, here, it was a simple example, but you can also apply this solution to object inside object inside object, etc.
If you have any other solution to handle this kind of case, or if you have questions/comments, feel free to comment this post, I’ll answer you with great pleasure!
Thanks for reading,