Search code examples
swiftrealm

Do I need to check for object existence when creating new Realm objects?


Using Realm, I noticed the app will crash if I try to save an object that its' ID already exists.

This causes my code look like this for every Realm Object type I want to create:

func fetchOrCreate(...) -> MyClass? {
   let existingObject = realm.object(ofType: MyClass.self, forPrimaryKey: MyClass.primaryKeyFor(...))
   let object = existingObject ?? MyClass(with: ...)
   return object
}

for any creation of an object. This seems like messy boilerplate. Is it really necessary to check for an existing object each time I create a new one?


Solution

  • Your question

    Do I really need to check every time I create an object if such object already exists

    Maybe? And the answer depends on what the expected outcome is along with how the models are structured. e.g. there has to be a way to determine what determines if an object is "the same" as another object, and that is done be an objects primary key.

    I believe what you're looking for is an Upsert. An Upsert either inserts an object if it doesn't exist, or updates an existing object if it does. Upserts require the model to have a primary key.

    Suppose there's a Person object

    class Person: Object {
       @Persisted(primaryKey: true) var _id = 0
       @Persisted var name = ""
    }
    

    then let's do an upsert

    //assume a person with _id 1234 exists, read it in
    let aPerson = realm.objects(Person.self).where { $0._id == 1234 }
    
    try! realm.write {
       //create a new person object but give it the same _id
       let p = Person(value: ["_id": 1234, name: "Jay"]
       realm.add(p, update: .modified)
    }
    

    Since the new person object has the same _id and we've specified .modified, Realm assumes it's the same person and updates that persons name to "Jay".

    However, if the _id of 1234 didn't already exist, a completely new person object would be created.

    Leaving off that .modified parameter will crash if an object with that _id exists - as mentioned in the question.

    You can read more about it here: Upsert an Object