Reputation: 2729
Let's say I have 4 models like so:
┌────────────┐ ┌────────────┐
│ User │ │ Goal │
├────────────┤ 1 ├────────────┤ 1
│ _id │◄──┐ │ _id │◄──┐
└────────────┘ └──┤ ref_user │ │
1..*└────────────┘ │
│
┌───────────┐ ┌───────────────┐ │
│ Date │ │ Data │ │
├───────────┤ 1 ├───────────────┤ │
│ _id: date │◄─┐ │ _id │ │
└───────────┘ └──┤ ref_date │ │
1 │ ref_goal ├──┘
└───────────────┘ *
I created a pre remove
when deleting a data it automatically removes the date associated.
DataSchema.pre('remove', async function (next) {
try {
await DateModel.findByIdAndRemove(this.ref_date);
console.log("Date removed");
next();
} catch (err) {
console.log(err);
next(err);
}
});
The issue I am facing is that when I remove a goal, I want all the Data associated to be deleted (it works) BUT I want the DataModel.remove to triggers its pre remove
and remove its Date.
In a logical perspective, when removing data on the pre remove
hook in Goal, this also should trigger the pre remove
in Data since Data data are removed. Why when removing a data from another pre remove
hook it doesn't trigger its pre remove
?
From Goal, I can retreive an array of Data, but I don't think that looping through the array and removing one by one the date is a good practrice.
Is there a way to triggeres the pre remove from Data, from the pre remove from Goal ? Or a way to remove all the Date from an array of Data ?
ps: in the futur, I want the same thing again when deleting a user (deleting all its goals that deletes all the data and the date).
Edit :
As requested, he is my goal pre-remove hook
GoalSchema.pre('remove', async function (next) {
try {
await DataModel.deleteMany({ 'ref_goal': this._id });
console.log("Data removed");
next();
} catch (err) {
console.log(err);
next(err);
}
});
I tried deleteMany
, remove
, etc. but none seems to trigger the Data
pre-remove hook
Env:
"express": "^4.17.1",
"mongoose": "^5.12.2",
Upvotes: 3
Views: 360
Reputation: 10460
There are two issues with your current code:
You're registering a remove
hook on your data
schema:
DataSchema.pre('remove', ...)
while you're goal
's remove
hook's callback triggers a deleteMany
middleware:
await DataModel.deleteMany(...)
hence data
's remove
hook is not triggered.
Now, you mention that you tried other functions, such as remove
, which takes us to the second issue:
You're registering remove
hooks on documents (that's the default), while executing functions on models.
See this note on the docs:
Note: If you specify
schema.pre('remove')
, Mongoose will register this middleware fordoc.remove()
by default. If you want to your middleware to run onQuery.remove()
useschema.pre('remove', { query: true, document: false }, fn)
.
Of relevance is also this explanation:
You can pass options to
Schema.pre()
andSchema.post()
to switch whether Mongoose calls yourremove()
hook forDocument.remove()
orModel.remove()
. Note here that you need to set bothdocument
andquery
properties in the passed object:
// Only document middleware schema.pre('remove', { document: true, query: false }, function() { console.log('Removing doc!'); }); // Only query middleware. This will get called when you do `Model.remove()` // but not `doc.remove()`. schema.pre('remove', { query: true, document: false }, function() { console.log('Removing!'); });
I think the following should work:
const onRemoveData = async function (next) {
try {
let removed = [this];
if (this instanceof mongoose.Query) {
removed = await this.model.find(this.getQuery());
}
removed.forEach(function(doc) {
await DateModel.findByIdAndRemove(doc.ref_date);
console.log("Date removed");
});
next();
} catch (err) {
console.log(err);
next(err);
}
}
DataSchema.pre(['remove', 'deleteMany'], { document: true, query: false}, onRemoveData);
DataSchema.pre(['remove', 'deleteMany'], { document: false, query: true}, onRemoveData);
Upvotes: 1