Миграция области с введением первичного ключа

В настоящее время моя база данных Realm содержит простой массив из MyData объектов:

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

Например, он может содержать

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

Я собираюсь переделать его так, чтобы сделать name уникальным, сохранив самый большой age:

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

Кроме того, я хочу сделать name первичным ключом, чтобы избежать дублирования в будущем.

Поэтому я изменил описание класса как

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

И теперь мне нужно предоставить блок миграции:

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
    }
})

Я не понимаю, что делать в блоке перечисления. В моем примере у меня есть пять «старых» объектов (без первичного ключа), и у меня будет три «новых» объекта (с первичным ключом), так как же мне выполнить это преобразование?


person Nick    schedule 19.12.2019    source источник


Ответы (2)


Вы только что пытались увеличить версию схемы и добавить свойство deleteRealmIfMigrationNeeded к true ?

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

РЕДАКТИРОВАТЬ:

Извините, это неправда, потому что вам нужно оставить только самых старых людей, поэтому попробуйте использовать delete метод объекта миграции области:

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_

person Geoffrey    schedule 20.12.2019
comment
deleteRealmIfMigrationNeeded в моем случае не вариант, потому что это приведет к повторному входу пользователя в систему и другим негативным пользовательским впечатлениям. - person Nick; 20.12.2019
comment
Да, извините, я редактирую свой ответ. Попробуйте использовать migration.delete и удалять только целевые объекты. - person Geoffrey; 20.12.2019

func realmConfiguration(schemaVersion: UInt64) {
       let config = Realm.Configuration(schemaVersion: schemaVersion,
                                        migrationBlock: { _, oldSchemaVersion in
                                            if oldSchemaVersion < schemaVersion {}
       })
       Realm.Configuration.defaultConfiguration = config
   }

вызовите эту функцию в appDelegate

//Bump the schemaVersion when ever you need migration
realmConfiguration(schemaVersion: 2)
person Suresh Mopidevi    schedule 20.12.2019
comment
Я понимаю общую схему миграции. Мой вопрос касается конкретного случая, когда я хочу перейти от массива структур без первичного ключа к массиву уникальных (с точки зрения первичного ключа) структур. - person Nick; 20.12.2019