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 MongoDBfindOnefilter that selects the single document.relationsโ the relation input, with_idsandrelatedRelations.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
optionalisfalse, you cannot useremoveRelationโ there is no "empty" state. UseaddRelationwithreplace: trueinstead. - If
optionalistrue, 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:
While running:
After running โ the city is removed from livedCities:
For addMostLovedCity, setting an optional single relation:
And finally removeMostLovedCity erases the optional single relation:
Next stepsโ
- Find and findOne โ reading documents and their embedded relations back out