realm-dart icon indicating copy to clipboard operation
realm-dart copied to clipboard

Support Realm.add(update:[bool])?

Open SApolinario opened this issue 2 years ago • 8 comments

Is there an easy way currently to update an object if it exists with the specified primary key when calling Realm.add?

SApolinario avatar Jun 03 '22 14:06 SApolinario

We are missing that functionality currently.

Instead of creating an object with a given primary key directly, you can do:

final o = realm.find<Item>(pk) ?? realm.write(() => realm.add(Item(pk));
realm.write(() {
  // update o
});

nielsenko avatar Jun 03 '22 14:06 nielsenko

Thanks for the reply. Let's say I'm pulling 100+ objects from my network API layer that returns API related entities. I need to then either insert or update existing local realm objects based on primary key. Just struggling with an efficient way to do that without having to map the data multiple times.

With Realm.add(update:[bool]) I could map once to a Realm object and realm will take care of either inserting or updating the object for me.

SApolinario avatar Jun 06 '22 15:06 SApolinario

I cannot give timelines, but we will have support for upserts eventually. That said, since you are consuming objects from a network API, the overhead of doing a find, potentially an add, and then an update is miniscule compared to the network call itself.

nielsenko avatar Jun 07 '22 06:06 nielsenko

We are missing that functionality currently.

Instead of creating an object with a given primary key directly, you can do:

final o = realm.find<Item>(pk) ?? realm.write(() => realm.add(Item(pk));
realm.write(() {
  // update o
});

This won't work unless all properties are optional.

Another alternative with a flow of API -> Local DB, is to delete all objects matching ids of the new payload, then insert. However this is flawed once there are relationships, where multiple models depend on another model. Deleting an entity of that latter model will remove all the references to it, and adding a fresh object won't set it back.

lukaspili avatar Jun 09 '22 01:06 lukaspili

You can make it work for non-optional properties, but I agree - it becomes ugly quickly. Something like:

final o = realm.find<Item>(pk) ?? realm.write(() => realm.add(Item(pk, nonOptional));
realm.write(() {
  o.nonOptional = nonOptional;
  // update rest of o
});

I cannot recommend deleting then inserting, for the reasons already given by @lukaspili, and also for how it interacts with sync.

Upserts are coming - I promise. Stay tuned.

nielsenko avatar Jun 09 '22 06:06 nielsenko

Thanks for the reply guys. Looking forward to seeing how this library evolves. Somewhat unrelated question so not sure anyone will answer but do. you guys tend to use your Realm objects as domain objects as well or do tend to separate those out? Otherwise I think this thread is safe to close. Thanks again.

SApolinario avatar Jun 10 '22 12:06 SApolinario

Thanks @nielsenko! Looking forward to it.

One more question regarding your example: is there a particular reason you're doing the find() outside of the transaction? Would it be ok to do it like this instead? (using a single write transaction to insert/update all items)

realm.write(() {
   final o = realm.find<Item>(pk) ?? realm.add(Item(pk));
   o.foo = 'bar';
});

lukaspili avatar Jun 10 '22 18:06 lukaspili

@lukaspili No. Your approach is better 👍

@SApolinario Regarding domain objects, I like to use realm objects directly.

nielsenko avatar Jun 10 '22 23:06 nielsenko

Resolved in 0.3.2+beta

nielsenko avatar Aug 17 '22 10:08 nielsenko