I have this schema and fields like basicSalary
can be edited by admin through dashboard UI, the pre save hook works fine to calculate fields, followed by pre updateOne hook to update the doc when it's edited by admin
const salariesSchema = mongoose.Schema({
employeeId: {
type: mongoose.Schema.Types.ObjectId,
ref: "employee",
required: true,
},
month: { type: String, required: true },
year: { type: String, required: true },
basicSalary: { type: Number, default: 0, required: true },
accomodation: { type: Number, default: 0 },
transportation: { type: Number, default: 0 },
bonus: { type: Number, default: 0 },
SSC: { type: Number, default: 0 },
incomeTax: { type: Number, default: 0 },
medicalInsurance: { type: Number, default: 0 },
loan: { type: Number, default: 0, default: null },
totalEarnings: { type: Number },
totalDeductions: { type: Number },
netSalary: { type: Number },
});
salariesSchema.pre("save", function (next) {
this.SSC = this.basicSalary * 0.07;
this.totalEarnings =
this.basicSalary + this.accomodation + this.transportation + this.bonus;
this.totalDeductions =
this.incomeTax + this.medicalInsurance + this.loan + this.SSC;
this.netSalary = this.totalEarnings - this.totalDeductions;
next();
});
salariesSchema.pre("updateOne", function (next) {
this.SSC = this.basicSalary * 0.07;
this.totalEarnings =
this.basicSalary + this.accomodation + this.transportation + this.bonus;
this.totalDeductions =
this.incomeTax + this.medicalInsurance + this.loan + this.SSC;
this.netSalary = this.totalEarnings - this.totalDeductions;
next();
});
routes > salary..js
const Salary = require("../models/Salary");
const editSalary = async (req, res) => {
try {
const salary = Salary.findById(req.body._id);
await salary.updateOne({ $set: req.body });
res.status(200).json("salary has been updated successfully");
} catch (err) {
console.log(err);
res.status(400).json(err);
}
};
if admin for example increased basicSalary
by 50, totalEarnings
and netSalary
values should also be updated by 50 based on the calculations in pre updateOne
hook, but that doesn't work, what's wrong here ?
it turned out that i can't access fields directly by using this.fieldName
, i solved it by using this.get("fieldName")
converted into a number, and using this.set
( see documentation ) instead of return fieldName = expression
let me know if you have a better way to do it
salariesSchema.pre("updateOne", function (next) {
this.set({ SSC: Number(this.get("basicSalary")) * 0.07 });
this.set({
totalDeductions:
Number(this.get("incomeTax")) +
Number(this.get("medicalInsurance")) +
Number(this.get("loan")) +
Number(this.get("SSC")),
});
this.set({
totalEarnings:
Number(this.get("basicSalary")) +
Number(this.get("accomodation")) +
Number(this.get("transportation")) +
Number(this.get("bonus")),
});
this.set({
netSalary:
Number(this.get("totalEarnings")) - Number(this.get("totalDeductions")),
});
next();
});