Skip to main content

The removeRelation Function

removeRelation is the inverse of addRelation โ€” it undoes links between documents, cleaning up both sides. This tutorial covers removing a many-to-many link, then removing an optional single relation.

Remove a many-to-many relationโ€‹

Removing cities from a user's livedCities list:

const removeLivedCitiesValidator = () => {
return object({
set: object({
_id: objectIdValidation,
livedCities: array(objectIdValidation),
}),
get: coreApp.schemas.selectStruct("user", 1),
});
};

const removeLivedCities: ActFn = async (body) => {
const { livedCities, _id } = body.details.set;
const obIdLivedCities = livedCities.map((lc: string) => new ObjectId(lc));

return await users.removeRelation({
filters: { _id: new ObjectId(_id) },
projection: body.details.get,
relations: {
livedCities: {
_ids: obIdLivedCities,
relatedRelations: {
users: true,
},
},
},
});
};

coreApp.acts.setAct({
schema: "user",
actName: "removeLivedCities",
validator: removeLivedCitiesValidator(),
fn: removeLivedCities,
});

removeRelation takes the same object as addRelation, minus the replace key:

  • filters โ€” a MongoDB findOne filter that selects the single document.
  • relations โ€” the relation input, with _ids and relatedRelations.
  • projection โ€” shapes the written data.

The act receives the user id and an array of city ids. The cities are removed from the user's livedCities, and the user is removed from each city's users list. (For the internal steps, see the steps to add a country to a user โ€” here there is no document to add, only removal and refilling of limited lists.)

Remove an optional single relationโ€‹

For a single relation there's a catch:

  • If optional is false, you cannot use removeRelation โ€” there is no "empty" state. Use addRelation with replace: true instead.
  • If optional is true, you can remove the relation entirely, along with its related relations.

Let's give the user an optional mostLovedCity:

const users = coreApp.odm.newModel("user", userPure, {
livedCities: {
optional: false,
schemaName: "city",
type: "multiple",
sort: { field: "_id", order: "desc" },
relatedRelations: {
users: {
type: "multiple",
limit: 5,
sort: { field: "_id", order: "desc" },
},
},
},

mostLovedCity: {
optional: true,
schemaName: "city",
type: "single",
relatedRelations: {
lovedByUser: {
type: "multiple",
limit: 5,
sort: { field: "_id", order: "desc" },
},
},
},

country: {
optional: false,
schemaName: "country",
type: "single",
relatedRelations: {
users: {
type: "multiple",
limit: 5,
sort: { field: "_id", order: "desc" },
},
},
},
});

On the city side, lovedByUser keeps the last five users who chose it. First, set the relation (note replace: true, since it's a single relation):

const addMostLovedCity: ActFn = async (body) => {
const { lovedCity, _id } = body.details.set;

return await users.addRelation({
filters: { _id: new ObjectId(_id) },
projection: body.details.get,
relations: {
mostLovedCity: {
_ids: new ObjectId(lovedCity),
relatedRelations: {
lovedByUser: true,
},
},
},
replace: true,
});
};

Then remove it:

const removeMostLovedCity: ActFn = async (body) => {
const { lovedCity, _id } = body.details.set;

return await users.removeRelation({
filters: { _id: new ObjectId(_id) },
projection: body.details.get,
relations: {
mostLovedCity: {
_ids: new ObjectId(lovedCity),
relatedRelations: {
lovedByUser: true,
},
},
},
});
};

The user's mostLovedCity field is cleared (if it matches the given id), and the user is removed from that city's lovedByUser list.

Run the codeโ€‹

The complete runnable examples are examples/document/05-2-remove-relation-fn-1.ts (many-to-many) and examples/document/05-2-remove-relation-fn-2.ts (optional single) in the Lesan repository. Run them and explore main โ†’ user โ†’ removeLivedCities / removeMostLovedCity in the playground.

Before running removeLivedCities:

removeLivedCities act in the playground, before running

While running:

removeLivedCities act in the playground, executing

After running โ€” the city is removed from livedCities:

removeLivedCities act in the playground, after running

For addMostLovedCity, setting an optional single relation:

addMostLovedCity act in the playground, before running

addMostLovedCity act in the playground, executing

addMostLovedCity act in the playground, after running

And finally removeMostLovedCity erases the optional single relation:

removeMostLovedCity act in the playground, executing

removeMostLovedCity act in the playground, after running

Next stepsโ€‹

  • Find and findOne โ€” reading documents and their embedded relations back out