I have a authentication system where the user need to validate their email after creating an account, then the status of the account would change from Pending to Active.
I want to implement a feature that if a user does not validate their email within a time frame, the account will be deleted. I was able to get the delete part done by setting an expire field in the Schema:
const userSchema = new mongoose.Schema<IUser>(
{
email: {
type: String,
required: true,
},
status: {
type: String,
default: "Pending",
required: true,
},
expiresAt: {
type: Date,
default: () => Date.now() 30 * 1000,
expires: 30
}
},
{
timestamps: true
}
However, the expire counter seem to be still counting even I purposely deleted the expiresAt
field, and the document still get deleted.
const user = await User.findById(tokenId).exec();
user.status = 'Active';
user.expiresAt = undefined;
const updatedUser = await user.save();
I wonder is there a way to stop or remove the TTL feature entirely after validation?
CodePudding user response:
This is actually a feature provide by the mongoose
schema, You are not actually deleting the expiresAt
value, the mongoose
schema ignored that input as it does not match the type.
By looking at mongoose
source code we can see this:
doc: { status: "Active", expiredAt: undefined }
const keys = Object.keys(obj);
let i = keys.length;
while (i--) {
key = keys[i];
val = obj[key];
if (obj[key] === void 0) {
delete obj[key];
continue;
}
}
The expressions obj[key] === void 0
means if obj[key] === undefined
like in your case, basically mongoose
removes this value from the update body.
What you want to do is just use an operator like $unset
:
db.collection.updateOne({ _id: user._id}, {$set: {status: "Active"}, $unset: {expiresAt: ""}})