I'm trying to update an array using presave hooks available in mongoose. Im using this array for Audit Purposes and hence i wanted to enforce correct values using these middle wares
Here is my schema
const taskSchema = new mongoose.Schema({
id: { type: String, required: true },
status: { type: String, required: true },
code: { type: String, required: true }, // ENQUIRY
events:{
type:[{
status: {type: String, required: true},
date:{ type: Date, required: true}
}], required: false
},
assignedTo: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: false },
}, {timestamps:true});
The logic works great in save middleware hook.
taskSchema.pre('save', async function(next) {
try {
let event = {}
let now = Date.now();
event.status = this.status;
event.date = now;
this.events.push(event);
next();
} catch (error) {
console.log(error);
next(error);
}
});
Error when used in findOneAndUpdate hook
taskSchema.pre('findOneAndUpdate', async function(next) {
try {
let event={}
let now = Date.now();
event.status = this._update.status;
event.date = now;
this.events.push(event);
next();
} catch (error) {
console.log(error);
next(error);
}
});
I'm not sure what I'm missing here. Here is the error
TypeError: Cannot read property 'push' of undefined
I see that this.events is undefined.
How do I access that array to have it updated? I also should ignore whatever is sent in request.body.events
Thanks in advance.
Refer to the Types of Middleware, save
is document middleware and findOneAndUpdate
is query middleware. And in notes, it says that:
Query middleware differs from document middleware in a subtle but important way: in document middleware,
this
refers to the document being updated. In query middleware, mongoose doesn't necessarily have a reference to the document being updated, sothis
refers to the query object rather than the document being updated.
So in your findOneAndUpdate
pre, this.events
is undefined
.
In your case, using below code may solve the problem:
taskSchema.pre('findOneAndUpdate', async function(next) {
try {
let event={}
let now = Date.now();
event.status = this._update.status;
event.date = now;
this._update['$push'] = {events: event};
next();
} catch (error) {
console.log(error);
next(error);
}
});