Search code examples
iosswiftrealmrealm-migration

Realm migration introducing primary key


Currently, my Realm database contains a plain array of MyData objects:

class MyData: Object {
    @objc dynamic var name = ""
    @objc dynamic var age = 0
}

For instance, it may contain

[
    ["Alice", 12],
    ["Bob", 13],
    ["Alice", 22],
    ["Carolina", 13],
    ["Bob", 20]
]

I am going to rework it so that to make name unique keeping the biggest age:

[
    ["Alice", 22],
    ["Bob", 20],
    ["Carolina", 13]
]

also, I want to make name a primary key to avoid duplication in future.

So I changed class description as

class MyData: Object {
    @objc dynamic var name = ""
    @objc dynamic var age = 0
    override static func primaryKey() -> String? {
        return "name"
    }
}

And now I need to provide a migration block:

let config = Realm.Configuration(
    schemaVersion: 1,
    migrationBlock: { migration, oldSchemaVersion in
        switch oldSchemaVersion {
        case 0:
           migration.enumerateObjects(ofType: MyData.className()) { (oldObject, newObject) in
            // how to do it?
        }
        default:
            break
    }
})

I do not understand what to do in enumeration block. In my example, I have five "old" objects (without primary key), and I will have three "new" objects (with primary key), so how do I do this transformation?


Solution

  • Did you just try to increment schema version and add property deleteRealmIfMigrationNeeded to true ?

    Realm.Configuration.defaultConfiguration = Realm.Configuration(
        schemaVersion: 2,
        migrationBlock: { migration, oldSchemaVersion in },
        deleteRealmIfMigrationNeeded: true
    )
    

    EDIT:

    Sorry, it's not true because you need to keep only oldest people so try use delete method of realm migration object:

    let config = Realm.Configuration(
    schemaVersion: 1,
    migrationBlock: { migration, oldSchemaVersion in
        switch oldSchemaVersion {
        case 0:
           var objects: [String: Any] = []
           migration.enumerateObjects(ofType: MyData.className()) { 
           (oldObject, newObject) in
               if let age = oldObject["age"] as? Int, age > objects[oldObject["name"]] {
                   migration.delete(oldObject["name"])
                   objects[oldObject["name"]] = oldObject
               } else {
                   migration.delete(oldObject)
               }
    
           }
        default:
            break
        }
    })
    

    https://realm.io/docs/swift/latest/api/Classes/Migration.html#/s:FC10RealmSwift9Migration6deleteFCS_13DynamicObjectT_