Sequelize: Can't do update on column UpdatedAt - node.js

I've an express apps that use Sequelize as ORM. Basically, columns createdAt and updatedAt auto-generated by Sequelize.
Every time I do update data in a row except column updatedAt, the column updatedAt will be updated based on current datetime.
But when I'm trying to update the column updatedAt, it didn't update the value of column updatedAt.
I've several way based on docs and another issue in so, like:
value.set('createdAt', new Date());
value.save().then(value1 => {
console.log('UpdatedAt has been updated');
next();
}
)
and
Token.update(
{
updatedAt: new Date
},
{
where: {
token_id: token
}
}
).then(value1 => {
console.log('Token UpdatedAt has been updated');
}
)
But non of both work.
Anyone know why? and how to fix that. Thankyou.

The short and simple way for this is :
Token.changed('updatedAt', true); // <--- This will update the updatedAt field

Related

Sequelize: Increment and updated_at in same method

Using Sequelize is there a way to increment a value and also update the updated_at column in the same call? I would assume there is a way to do this as using the increment method is updating the table so the updated_at column should be updated at the same time, without having to waste a second call only to update the updated_at column.
await account.increment(
["balance"],
{
by: updateAmount,
},
{ transaction: transaction }
);
await account.update(
{
updated_at: new Date()
},
{ transaction: transaction }
);
The docs dont seem to mention it
No. As the docs say increment is a convenience method. If you need to do more then incrementing then you have to use the update method.

mongodb update two array values based on array unique id's

this is my mongodb document. i want to update comment and likerName field at one query based on comments.user and likerName.likerId. i have done so far this
Tutorial.updateMany(
{
"comments.user":userid
},
{
$set:{'comments.$[].profilepic':image}
}
).then(data=>{
// res.send(data);
}).catch(err=>{
console.log(err);
})
it updates very well comment field. but i also want to update likerName field same like this.
do u mean?
{
$or:[{"comments.user":userid},{"likerName.likerId":userid}]
},

Sequelize automatically adds colums

[Model].findOne({}) throws unknown colum error, but i dont have that column in my model, but it adds the colum modifieddate and updatedat and somecolum while fineOne runs
You have to add timestamp:false in the options where you are defining the model.
For example:
var Bar = sequelize.define('Bar', { }, {
timestamps: false,
})
For reference check this Sequelize model definition

Sequelize: Storing dates in JSON columns and comparing them to dates in where clauses

I am using PostgreSQL and sequelize. I have a model column "checkedAt" for storing multiple dates. I want to be able to compare the different dates from the column data.
The issue with this is that the dates are stored as strings since it is not a Date but a JSON DataType.
Here is how I defined the model
const Notification = sequelize.define("Notification", {
checkedAt: {
type: DataTypes.JSON,
defaultValue: {
bySomeJob: new Date(),
bySomeOtherJob: new Date()
}
}
});
how I try to query with no success
const someDate = new Date();
await db.Notification.findAll({
where: {
checkedAt: {
bySomeJob: {
$lte: someDate
}
}
}
});
I've used this method before for integers and booleans but not with a date.
I found this function to turn strings into date format
sequelize.fn('date', sequelize.col('checkedAt'))
But not sure if and how could it be used for a property of the column.
I expect to be able to query the model by comparing a Date object to a transformed value from the property of a JSON object column.
If you need to associate multiple dates to a notification, then you may be better off creating a new model used specifically for storing checkedAt dates, and creating an association between notifications and checkedAt dates. Something like Notification.hasMany(Dates);
This way when you query for notifications you can include the Dates table, and then be specific about what dates to include from that table, like with using $lte, which is what you were trying.
It might look something like this
await db.Notification.findAll({
include: [
{
model: db.Date,
where: {
checkedAt: {
bySomeJob: {
$lte: someDate
}
}
}
}
]
});

Does Mongoose upsert operation update/renew default schema values?

Mongoose Schema:
new Schema({
...
createDate: { type: Date, default: Date.now },
updateDate: { type: Date, default: Date.now }
});
Upsert operation:
const upsertDoc = {
...
}
Model.update({ key: 123 }, upsertDoc, { upsert: true })
when I upsert with update or findOneAndUpdate the default schema values createDate and updateDate are always renewed no matter document is inserted or updated. It's same when I use $set (in which of course I don't pass dates).
I don't seem to find anything to tell if it's an expected behavior. I expect dates to be added only on insert and not update, unless explicitly set.
If you are looking for "proof" of the expected behavior, then look no further than the source code itself. Particularly within the schema.js main definition:
updates.$setOnInsert = {};
updates.$setOnInsert[createdAt] = now;
}
return updates;
};
this.methods.initializeTimestamps = function() {
if (createdAt && !this.get(createdAt)) {
this.set(createdAt, new Date());
}
if (updatedAt && !this.get(updatedAt)) {
this.set(updatedAt, new Date());
}
return this;
};
this.pre('findOneAndUpdate', _setTimestampsOnUpdate);
this.pre('update', _setTimestampsOnUpdate);
this.pre('updateOne', _setTimestampsOnUpdate);
this.pre('updateMany', _setTimestampsOnUpdate);
}
function _setTimestampsOnUpdate(next) {
var overwrite = this.options.overwrite;
this.update({}, genUpdates(this.getUpdate(), overwrite), {
overwrite: overwrite
});
applyTimestampsToChildren(this);
next();
}
So there you can see all the 'pre' middleware handlers being registered for each of the "update" method variants and to the same functional code. These all essentially modify the $set operator in any "update" you issue to include the updatedAt field, or whatever name you mapped to that key in the schema options.
The actual statement sent with "upsert" actions uses $setOnInsert for the createdAt field or mapped option name ( see the top of the listing ). This action only applies when an "upsert" actually occurs, so documents that exist and are merely matches for any of the "update" methods are never actually touched by this value.
Those operators are part of how MongoDB works and not really to do with mongoose, but the code shown here shows how mongoose "adjusts" your "update" actions in order to include these additional operations.
For reference the whole main function in schema.js which works out what to apply currently begins at Line #798 for the genUpdates() function as called in the bottom part of the listing shown here yet the top part is the last few lines of that function where the keys of $setOnInsert get defined.
So in summary, YES every "update" action is intentional that the updatedAt mapped field has the current Date value assigned, and also that the "updates" are modified to include the $setOnInsert action which only applies when a new document is created as the result of an "upsert" action for the createdAt mapped field.
Well, I'd always recommend to use the provided and recommended way to manage createdAt and updatedAt by mongoose. Simply by passing timeStamp: true as schema options.
This is always a best practice and lets you not to be worried about such behaviors.
I use it and I never see a problem with timestamps using update or findOneAndUpdate.
Here is how you use it
new Schema({
... //Your schema
},{ timestamps: true})

Resources