Understanding Primary Keys in Realm


#1

First of all let me apologize for my poor knowledge about databases in general, especially on simple concepts such as primary keys.

It is my understanding that in other databases the primary key is automatically incremented and created every time a new record is entered without you having to do anything and I think in Realm you need to manually assign the unique ID number at the creation time, I think. So, my question is…

What is the benefit of declaring your primary keys as recommended in the Realm page instead of using a standard String property or use the creation time as your unique key?

In other words, why would you use…

class Person: Object {
  @objc dynamic var personID = UUID().uuidString
  override static func primaryKey() -> String? {
    return "personID"
  }
}

instead of a standard String property

class Person: Object {
  @objc dynamic var personID:String
}

or simply use the creation date as your primary key.

class Person: Object {
  @objc dynamic var createdAt = NSDate()
}

Again, sorry if my question doesn’t make too much sense but I’m little confused as to what is the benefit of using the recommended method vs a String or the creation data as your primary key.

Thanks.


#2

The primary key is a unique identifier of that object. So

@objc dynamic var personID = UUID().uuidString

creates a unique identifier. However, this

@objc dynamic var personID:String

is not unique not does it actually assign a value to personID, it’s just telling personID that it will be a string and will throw an error if you then:

personID = 1234 //error Cannot assign value of type 'Int' to type 'String'

it also doesn’t guarantee uniqueness

person1.personID = "aaa"
person2.personID = "aaa"

is perfectly valid and you have two people with the same id.

and then this

class Person: Object {
  @objc dynamic var createdAt = NSDate()
}

doesn’t define the var createdAt as a primary key at all (perhaps you left out that code) but try this:

struct PersonClass {
    var personID = NSDate()
}

let a = PersonClass()
let b = PersonClass()

print(a.personID)
print(b.personID)

here’s the output

2019-03-27 20:25:32 +0000
2019-03-27 20:25:32 +0000

That’s pretty confusing! Under the hood, though, they are different values

print(a.personID.timeIntervalSince1970)
print(b.personID.timeIntervalSince1970)

results in

1553718434.234439
1553718434.239869

So while they are unique values, they may be hard to maintain and troubleshoot in the future.

Go with this method if possible:

UUID().uuidString

but you could use an auto-incrementing integer or a number of other solutions. Just whatever it is, ensure it generates unique values and is easy to maintain

my .02


#3

@jay It started to make sense but there’s still one thing that I don’t fully understand and was probably what caused my confusion. When you use the recommended method and you create a new object, do you have to always provide a unique key at the creation of the object or the unique key will be automatically assigned since it was declared with UUID().uuidString?

For instance, do I need to provide my own unique key at the creating time or it is optional and the key will automatically be generated if one is not provided?

Will this generate a unique key?
var nathan = Person()

Or I need to manually provide it, like so?

var nathan = Person()
Nathan.personID =  “fas4211daghaf”

#4

@objc dynamic var personID = UUID().uuidString creates a unique identifier

Yes, but it doesn’t create a primary key. You need to override the class primary key for that.


#5

@freeubi Yes, thanks for pointing that out - the override code was included in the original question so I assumed it was a given.

@fsdolphin The unique key will be generated for that object when it’s instantiated so you do not need to do anything else. So the code in the initial question is best practice for this use case.

class Person: Object {
  @objc dynamic var personID = UUID().uuidString
  override static func primaryKey() -> String? {
    return "personID"
  }
}

There are cases where you may, for example, want incremental primary keys but it’s probably not needed. See the docs: Models.


#6

Got it, thank you all for your help.