Linking Objects v/s Embedded Objects

Hi,

Sorry if this is not related but its the closest thing i could find.
We are working on trying to move some functions in our realm app onto the MongoDB functions.
But we are running into errors when trying to setup objects that have realm relationships.

export const BoardColumn = {
	name: "BoardColumn",
	primaryKey: "_id",
	properties: {
		_id: "objectId",
		_partition: "string",
		order: "int",
		zones: "BoardZone[]"
	}
};

export const BoardZone = {
	name: "BoardZone",
	primaryKey: "_id",
	properties: {
		_id: "objectId",
		_partition: "string",
		name: "string",
		order: "int",
		cards: "BoardCard[]",
		settings: "BoardSettings",
		singleFavourite: "bool?",
		singleBrainstorm: "bool?",
		linkages: { type: "list", objectType: "BoardZoneLink" },
		deleted: { type: "bool", default: false }
	}
};

We have these two objects for example, BoardColumn has a list of BoardZone objects in a 1:M realm relationships. We don’t have any issues creating BoardZones and adding them to the BoardColumns zone field in our React Native app, but trying to do it in a mongodb function is proving difficult. Have attempted to add the objects to the filed as the objects themselves, just saving the ObjectIDs of the BoardZone objects, as well as trying to use the DBRef object as the error we are receiving is this:

could not convert foreign key link array element value to Realm link payload for path { table: \"BoardColumn\", fullPath: \"zones.0\" }: could not encode field, found a sub-document but it was not a valid DBRef: document was not a valid DBRef: DBrefs only contain 2-3 elements in the reference document (found 8)

No matter what I try I can’t seem to set them, does anyone have any idea how we can set these objects in a MongoDB function?

Thanks, Mitchell

Hey @Mitchell_Flaherty , so you are coming across the difference between a linking object and an embedded object. Linking objects are “foreign key links” so in mongodb it would result in the following:

Board Zone collection:

[
 { _id: "zone1", _partition: "abc", name: "1" }
 { _id: "zone2", _partition: "abc", name: "2" }
 { _id: "zone3", _partition: "abc", name: "3"}
]

Board Column collection:
[ { _id: "board1", _partition: "abc", order: 1, zones: ["zone1", "zone2] } ]

So here, the zones field is just a list of primitives that have the _id value in the associated Board Zone objects. In your schema, this is how things are setup.

Embedded objects are different in that they are objects that are completely owned by the parent object and thus embedded within the same exact document. This is helpful if you dont actually need / want a Board Zone collection and your documents in mongodb will just look like this instead:

{
    _id: "board1", 
    _partition: "abc", 
    order: 1, 
    zones: [
       {name: "zone1", cards: [], settings: null, singleBrainstorm: true, ...},
       {name: "zone2", cards: [], settings: null, singleBrainstorm: true, ...},
       ...,
    ]
}

Let me know if that makes sense. The error above suggests that you are using linking objects but trying to insert things to MongoDB as if they are embedded objects.

I would recommendd using embedded objects unless linking objects are necessary. If that is the case, you will likely want to perform your insert as follows:

await db.BoardZoneLink.insertMany(...)
await db. BoardSettings.insertMany(...)
await db. BoardCard.insertMany(...)
await db. BoardZone.insertMany(...) // with links to the primary keys of the objects above 
await db. BoardColumn.insertOne(...) // with link to the primary keys of the BoardZones inserted above 

As you can see, using embedded objects is a much more common pattern in MongoDB. I would recommend reading through this blog post if you are interested: MongoDB Schema Design Best Practices | MongoDB

1 Like

Hey @Tyler_Kaye,
Yeah it seems I’m attempting to do it like the objects are embedded objects instead of Realm Links. We looked into Embedded objects and changed to using them where we could, but due to Realm Sync being our main database, It would have had to have been a considerable rewrite to move everything over to use Embedded objects, so we kept the old implementation when migrating over for the larger more integral parts of the app as we did not have the time before the cut-off.

Let me know if that makes sense. The error above suggests that you are using linking objects but trying to insert things to MongoDB as if they are embedded objects.

The explanation does make sense and thanks for taking the time to go over that for me.

Just to confirm, so I just have to do it like this:

let Zone1 = await db.BoardZone.insertOne(...) //Insert and then return the object
let Zone2 = await db.BoardZone.insertOne(...)
let Column  = await db. BoardColumn.insertOne(..., [Zone1._id, Zone2._id])

Sending the oid’s of the inserted BoardZone objects and setting the BoardColumn.zones field equal to an array of the created BoardZone objects? and follow the same with all the other objects which use the Realm Relationships?

G’Day, @Mitchell_Flaherty ,

I have separated this post to a new topic, as this was different from the offline Realm Relationships discussion.

Please continue to use this thread for more questions/discussions around linking/embedded objects in functions.

Cheers, :performing_arts:

1 Like

Yes, that is the gist. However, I should let you know that insertOne() does not return the entire object that was inserted but just an object with a field called insertedId. If you use insertMany() it returns a list of ids called insertedIds. See here for more about the API of MongoDB: https://www.mongodb.com/docs/manual/reference/method/db.collection.insertOne/#insert-a-document-without-specifying-an-_id-field

Also, you could just know your _ids outright by passing them into the objects you are creating:

let zoneOneID = new BSON.ObjectId();
let zoneTwoID = new BSON.ObjectId();
let col1ID = new BSON.ObjectId();

await db.BoardZone.insertOne({_id: zoneOneID, ...})
await db.BoardZone.insertOne({_id: zoneTwoID, ...})
await db. BoardColumn.insertOne({_id: col1ID, zones: [zoneOneID, zoneTwoID]})

Its obviously not ideal, but it is how linking objects / foreign key links work in MongoDB (and most other DB’s) because the objects you are using are totally independent and exist on their own and the _id is what is linking them together.

Hope that this is helpful,
Tyler

2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.