Search code examples
nosqlforeign-keysrealmrelational-databasedatabase-normalization

Realm relationships vs embedded objects


I'm used to SQL and don't understand Realm's internals too good. After checking the usual recommmendations for using Realm, I've seen that database normalization is usually discouraged, as well as creating a RealmObject with the sole purpose of linking items (like a cross-reference table to associate foreign keys).

To summarize, I don't want to use too many RealmObject classes. An example of two RealmObject with many-to-many relationships is below:

class Actor : RealmObject {
    var _id: ObjectId = ObjectId()
    var name: String = ""
    var age: Int? = null
    var movies: RealmList<Movie> = realmListOf<Movie>()
}
class Movie : RealmObject {
    var _id: ObjectId = ObjectId()
    var name: String = ""
    var actors: RealmList<Actor> = realmListOf<Actors>()
    var roles: List<String> = listOf<String>() // each actor's roles
}

How can I store just the reference to another RealmObject?

RealmList is the default way of writing "to-many" relationships, but I don't need to update contents on change; a list with references to another RealmObject would be enough.

How can I do this? I can't store the ObjectId of another RealmObject as I would in a relational database with foreign keys.


Solution

  • Realm is designed to easily handle very large datasets and working with objects by reference allows the object graph to easily be navigated in multiple directions and is very memory friendly (and fast)

    Implementing foreign keys can be done, but why? Let Realm do the heavy lifting by handling that for you.

    The question asks the following:

    How can I store just the reference to another RealmObject

    The answer is to simply add a property that references another object - given your two objects (pseudo code and stripped down for length)

    class Actor : RealmObject {
        var bestMovie: Movie
    }
    class Movie : RealmObject {
        var mainActor: Actor
    }
    

    In the above, the Actor has a single bestMovie and a movie has a single mainActor. This is a one-to-one relationship and answers the question as to how to store a reference to another Realm object.

    A few other interesting notes

    I've seen that database normalization is usually discouraged

    I would say that's not accurate. Denormalizaton/Normalization is very use case dependent and highly subjective. This is a tricky subject as Realm is an object database and not a relational database like SQL. There are no rows, columns and tables; every object is discreet and is stored as NoSQL document on the back end (Atlas). So I don't feel spending a lot of time normalizing (UNF, 1NF) etc is time well spent. Let Realm create and handle references.

    creating a RealmObject with the sole purpose of linking items

    Why not? If the use case calls for it then it can be done. If you really want to implement SQL style foreign keys, that's one way to do it. However, it's likely not needed and leveraging the built in "by reference" functionality will not only be more performant but will also be easier to support, expand and far less code.

    RealmList is the default way of writing "to-many" relationships,

    You could also use a RealmList to have a one-to-one relationship, as long as the child object implements LinkingObjects to create the backlink. Then the relationships are automatically generated.

    but I don't need to update contents on change; a list with references to another RealmObject would be enough.

    I am not really clear on the second part of the statement - "update contents on change" - A List is a reference engine and allows navigating to the related objects from the parent object, and inversely if LinkingObjects are used - it's not directly related to updating the objects; either the parent or child.