-
Type: Improvement
-
Resolution: Incomplete
-
Priority: Minor - P4
-
None
-
Affects Version/s: None
-
Component/s: None
Problem
Hi, I will try to expose the improvements with a practical example.
Domain example
I will obfuscate my own domain and will use an imaginary one for privacy reasons.
We will have a FlightTrip entity containing a list of embedded FlightTripLeg. FlightTripLeg also contains a relationship with a list of Airport (many to one relationship) and an embedded list of "TripCustomConfiguration".
const FLIGHT_TRIP_SCHEMA: Realm.ObjectSchema = { name: "FlightTrip", primaryKey: "_id", properties: { _id: { type: "objectId", default: () => new Realm.BSON.ObjectID(), }, legs: { type: "list", objectType: "FlightTripLeg" }, owner: "string", createdAt: "date", updatedAt: "date", }, }
const FLIGHT_TRIP_LEG_SCHEMA: Realm.ObjectSchema = { name: "FlightTripLeg", embedded: true, properties: { _id: { type: "objectId", default: () => new Realm.BSON.ObjectId(), }, name: "string", departureDate: "date", arrivalDate: "date", airports: { type: "list", objectType: "Airport" }, customConfigurations: { type: "list", objectType: "TripCustomConfiguration" }, }, };
const AIRPORT_SCHEMA: Realm.ObjectSchema = { name: "Airport", primaryKey: "_id", properties: { _id: { type: "objectId", default: () => new Realm.BSON.ObjectId(), }, name: "string", createdAt: "date", updatedAt: "date", }, }
const TRIP_CUSTOM_CONFIGURATION_SCHEMA: Realm.ObjectSchema = { name: "TripCustomConfiguration", embedded: true, properties: { _id: { type: "objectId", default: () => new Realm.BSON.ObjectId(), }, service: "string", price: "int" }, }
Duplication problem
The ideal way to duplicate a FlightTrip would be the following, but at the moment it just creates a new FlightTrip with an empty legs list (so I suppose this is a problem with embedded objects).
function duplicateFlightTrip(flightTripId: Realm.BSON.ObjectId) { const flightTrip = realm.objectForPrimaryKey( FLIGHT_TRIP_SCHEMA.name, flightTripId ); realm.write(() => { realm.create(FLIGHT_TRIP_SCHEMA.name, { ...flightTrip, // This is a shallow copy, so we are reusing the same flightTrip.legs embedded list _id: new Realm.BSON.ObjectId(), }); }); }
> Why not using flightTrip.toJSON()? Because converting to JSON would also affect the relationships and in this case we have a relationship with airport. Using toJSON() would fail saying that the airport entities are already created (same primary key).
Workaround
Remapping all the embedded objects does indeed work as expected, it creates a duplicate FlightTrip with all the embedded objects and relations!!!
function duplicateFlightTrip(flightTripId: Realm.BSON.ObjectId) { const flightTrip = realm.objectForPrimaryKey( FLIGHT_TRIP_SCHEMA.name, flightTripId ); realm.write(() => { realm.create(FLIGHT_TRIP_SCHEMA.name, { ...flightTrip, _id: new Realm.BSON.ObjectId(), legs: flightTrip.legs.map((leg) => { return { ...leg, customConfigurations: leg.customConfigurations( (customConfiguration) => customConfiguration ), }; }), }); }); }
Upsert
Imagine we want to make some modifications to our flight trip and save all of them when the user presses SAVE button, we cannot use the strategy where we update everything at the moment when the user changes its value.
To do this, we need first to create a copy of the realm entity so that we can save modifications over the time (we cannot modify a live entity outside of a realm transaction) and finally upserting the entity to save all the modifications.
In this case we have to do the same as the last case + remap also the Airport relationship, not only the embedded objects
const flightTripCopy = { ...flightTrip, _id: new Realm.BSON.ObjectId(), legs: flightTrip.legs.map((leg) => { return { ...leg, airports: leg.airports((airport) => airport), customConfigurations: leg.customConfigurations( (customConfiguration) => customConfiguration ), }; }), }; // Make modifications function save() { realm.write(() => { realm.create( FLIGHT_TRIP_SCHEMA.name, flightTripCopy, Realm.UpdateMode.Modified ); }); }
> Why preserving the relation objects when doing an upsert? You can upsert the relations too!
The answer to this is a bit complex, imagine that you are using Flexible Sync and the actual user does not have the permissions to write to airport collection, if he tries to also upsert the relations a sync error will happen. It seems that maintaining the original relation objects relam is capable of knowing that they don't need to be upserted.
Solution
Maybe adding something to the API like flightTrip.unmanaged() that returns a copy of the object remapping its embedded objects and relationships while also preserving the original objects inside the relationship?
Alternatives
Improve the docs
How important is this improvement for you?
Would be a major improvement
Feature would mainly be used with
Atlas Device Sync