deleteOne
Deletion has the same problems as update โ removing a document may require touching many others. This tutorial covers deleting a simple document (a user) and deleting one with dependents (a country), plus the hardCascade option.
Delete a userโ
const deleteUserValidator = () => {
return object({
set: object({
_id: string(),
}),
get: object({
success: optional(enums([0, 1])),
}),
});
};
const deleteUser: ActFn = async (body) => {
const {
set: { _id },
get,
} = body.details;
return await users.deleteOne({
filter: { _id: new ObjectId(_id) },
});
};
coreApp.acts.setAct({
schema: "user",
actName: "deleteUser",
validator: deleteUserValidator(),
fn: deleteUser,
});
The user model's relations (from the previous tutorials):
{
livedCities: {
optional: false,
schemaName: "city",
type: "multiple",
sort: { field: "_id", order: "desc" },
relatedRelations: {
users: {
type: "multiple",
limit: 50,
sort: { field: "_id", order: "desc" },
},
},
},
country: {
optional: false,
schemaName: "country",
type: "single",
relatedRelations: {
users: {
type: "multiple",
limit: 50,
sort: { field: "_id", order: "desc" },
},
},
},
}
There are no relatedRelations pointing at user โ nothing embeds a user. That's why deleting a user is simple. But we still have to check its mainRelations: the user is embedded in the users list of the cities it lived in, and in the users list of its country. Lesan removes those embeddings, and if a list needs refilling (it has a limit and a slot opened up), it adds the next qualifying user automatically.
The full example is examples/document/09-1-deleteOne.ts.
The user schema, with all its relations:
Before deleting the user:
While deleting:
After deleting:
Delete a countryโ
Now the hard case. The country model defines no relations of its own โ but both city and user create relations with it:
const countryRelations = {};
const cityRelations = {
country: {
optional: false,
schemaName: "country",
type: "single" as RelationDataType,
relatedRelations: {
cities: {
type: "multiple" as RelationDataType,
limit: 50,
sort: { field: "_id", order: "desc" as RelationSortOrderType },
},
citiesByPopulation: {
type: "multiple" as RelationDataType,
limit: 50,
sort: { field: "population", order: "desc" as RelationSortOrderType },
},
capital: { type: "single" as RelationDataType },
},
},
};
const userRelations = {
livedCities: {
optional: false,
schemaName: "city",
type: "multiple",
sort: { field: "_id", order: "desc" },
relatedRelations: {
users: { type: "multiple", limit: 50, sort: { field: "_id", order: "desc" } },
},
},
country: {
optional: false,
schemaName: "country",
type: "single",
relatedRelations: {
users: { type: "multiple", limit: 50, sort: { field: "_id", order: "desc" } },
},
},
};
If we delete a country that still has cities or users referencing it, the data created based on that country becomes meaningless. Lesan refuses โ with a relatedRelations error listing every dependent document:
{
"body": {
"message": "please clear below relations status before deletion: [ ... dependent docs ... ]"
},
"success": false
}
We have two ways forward:
- Delete all dependent documents one by one.
- Set
hardCascade: trueondeleteOne:
const deleteCountry: ActFn = async (body) => {
const {
set: { _id },
get,
} = body.details;
return await countries.deleteOne({
filter: { _id: new ObjectId(_id) },
hardCascade: true,
});
};
hardCascade: true deletes the country and every dependent document, and the dependents of those dependents, recursively โ so cities and users referencing the country are deleted too. The full example is examples/document/09-2-deleteOne.ts.
Before deleting the country:
While deleting:
After deleting โ the country and its dependent cities and users are gone:
hardCascade deletes recursively and is irreversible. Use it only when you're sure the dependent documents should be removed with the parent.
Next stepsโ
- insertMany โ inserting many documents while keeping all relations embedded correctly
- Relations in Depth โ
limit,sort,excludes, and cascading deletes