Milan Kamilya
Milan Kamilya

Reputation: 2298

Realm: nested update issue for many to one relation

I am using Realm notification block for updating messages in a page.

let messageResult = realm.Object(MessageRealm.self)
notificationTokenMessage = messageResult.addNotificationBlock{ [weak self] (changes: RealmCollectionChange) in {
   switch changes {
      case .initial(_),
           .update(_, _, _, _):
          self?.tableView.reloadData()
      default:
          break
    }
  }
}

In MessageRealm class, there is a property, name author. An author is basically a UserRealm object.

Class MessageRealm extends Object {  
  dynamic var _id: String? = nil
  dynamic var body: String? = nil
  dynamic var author: UserRealm? = nil
  override class func primaryKey() -> String? { return "_id" }
}

Class UserRealm extends Object {  
  dynamic var _id: String? = nil
  dynamic var fullName: String? = nil
  dynamic var status: String? = nil // 'online' or 'offline'
  override class func primaryKey() -> String? { return "_id" }
}

When a new message is received from socket, the message page is updated as it gets notifications from Realm. But, when user update notification is received from socket, the Realm updates the message page. I don't want to update message page for an update in author object.

Probable Solutions:

Class MessageRealm extends Object {  
  dynamic var _id: String? = nil
  dynamic var body: String? = nil
  dynamic var author: UserRealm? = LinkingObjects(fromType: UserRealm.self, property: "messages")
  override class func primaryKey() -> String? { return "_id" }
}

Class UserRealm extends Object {  
  dynamic var _id: String? = nil
  dynamic var fullName: String? = nil
  dynamic var status: String? = nil // 'online' or 'offline'
  let messages = List<MessageRealm>()
  override class func primaryKey() -> String? { return "_id" }
}
  1. We can solve it using LinkingObjects. But, this inverse relation needs a direct relation to map. Am I right? So, need to have a property of List of Messages in User. And from MessageRealm I have to link to User. But this will be complicated to maintain.

  2. Store author's id in MessageRealm as a foreign key like a traditional database.

What do you suggest?

How can we do normalization in Realm to avoid update issue?

Is there any convention or best practices to manage a bigger database? (I am aware of Tim's answer https://stackoverflow.com/a/31594548/2666902 )

Upvotes: 0

Views: 169

Answers (1)

David Pasztor
David Pasztor

Reputation: 54805

In my opinion, the best solution would be keeping the author property as a one-to-one relationship from MessageRealm to UserRealm, since a single message can only have one author and creating an inverse relationship in UserRealm.

class MessageRealm: Object {  
    dynamic var _id: String? = nil
    dynamic var body: String? = nil
    dynamic var author: UserRealm? = nil
    override class func primaryKey() -> String? { return "_id" }
}

class UserRealm: Object {  
    dynamic var _id: String? = nil
    dynamic var fullName: String? = nil
    let messages = LinkingObjects(fromType: MessageRealm.self, property: "author")
    override class func primaryKey() -> String? { return "_id" }
}

This way, you only need to keep the author property of your messages updated and the messages property of UserRealm will automatically keep in sync, so any time you try to access it, you will see all MessageRealm objects, where the author equals the specific user.

Upvotes: 0

Related Questions