Enable only createdAt time stamp and ignore updatedAt timestamp in Sequelize - mysql

I am trying to create some records into table with only the createdAt column filled. I want the updatedAt column to not exist how ever when i create a model it automatically generates the createdAt and updatedAt timestamps.
I tried to use timestamps : false but the createdAt column contains empty values.
const MyTable = sequelize.define(
'my_table',
{
id: {
type: DataTypes.INTEGER(11),allowNull: false,
primaryKey: true,autoIncrement: true,
},
person_name: {type: DataTypes.STRING(255),allowNull: false},
created: {type: DataTypes.DATE,allowNull: true},
},
{
tableName: 'my_table',
timestamps: false,
createdAt: 'created',
},
);
Is it possible to fix this issue in the model itself without doing any change in the query ?

According to the documentation on Init, you'll wanna leave the timestamps feature turned on, but configure your model to not use updatedAt.
Here's an edited version of the options object in your sample code that should give you what you are looking for:
{
tableName: 'my_table',
updatedAt: false,
}
NB: The docs say "Timestamps must be true", which might indicate why it wasn't working the way it is in the sample you provided.
Cheers!

Related

Why MYSQL column values gets modified/deleted issue?

I am building a React Nativeapp with MYSQL as the dabase and I am using SequelizeORM on Node.js. The problem is that I have a table called Like and there is a column field called userId and I simply store the ID of the users there. But the userId field gets cleared randomly. Like when I am restarting the database, or when there is an error and I need to restart the database or I am restarting the Android Emulator.
Here is how it looks:
CreateLikeModel.init({
id:{
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
userId:{
type: DataTypes.STRING,
allowNull: true
},
food_Name:{
type: DataTypes.STRING,
allowNull: false
},
food_id:{
type: DataTypes.INTEGER,
allowNull: false
}
},
And this is part of the function that saves the user Id when the user carry's out a like functionality:
const user = await CreateCustomer.findOne({where: {id: req.user.id}});
const likeObj ={
user_Id: user?.dataValues?.id?.toString(),
food_Name: food?.dataValues?.food_Name,
food_id: food.dataValues.id as number
}
//check if this user has liked this food
const checkUser = checkLike.find((single)=> single?.dataValues.userId ==
user.dataValues.id);
if(checkUser){
const getLike = await CreateLikeModel.findOne({where: {food_Name:
food.dataValues.food_Name, userId: user?.dataValues.id}});
await getLike?.destroy();//delete the like from the record if the user already liked;
return res.status(200).json('unliked');
}
await CreateLikeModel.create({...likeObj});
return res.status(200).json('liked');
And I connected to the database like this:
sequelizeDB.sync({alter: true}).then(()=>{
console.log('connected to datatbase')
})
I tried the save the userId as a string because it was a number before. Initially, when I used number, it usually reset the userId values to 0.
It still didn't solve the problem.
This was not happening before when I was using user_name instead of userId. What could be causing the issue? For now, I usually manually input the values back in the database when they get deleted.
Inside of likeObj, which you are using as the creation attributes for your like object, you have your User ID field as snake case user_Id, which in your model, I see it in camelCase userId.
I suspect this is the root of why it isn't populating the data correctly, however keep in mind that .sync({ alter: true }) can be a destructive operation, as state in the Sequelize documentation.

Sequelize - Enable paranoid: true on query level while its false on the defined Model

So lets say I have a Sequelize model defined with paranoid defaulting to "false":
const Country = sequelize.define('Country', {
name: {
type: DataTypes.STRING,
defaultValue: '',
},
code: {
type: DataTypes.STRING,
defaultValue: '',
},
currency: {
type: DataTypes.STRING,
defaultValue: '',
},
languages: {
type: DataTypes.STRING,
defaultValue: '',
},
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE,
deletedAt: DataTypes.DATE
});
Now when I invoke Model.destroy() on any records of Country table, the records would be hard deleted. Enabling paranoid: true on the Model definition would result in soft deletes.
I wanted to achieve the opposite of this. Where, the paranoid flag on model definition is set to false and we need to explicitly define a flag on the Model.destroy() method to soft-delete an entry and by default all records would be hard deleted.
I tried to sift through the documentation in order to find something but couldn't. Would appreciate any help I can get in case I missed something or if there's a workaround.
Why I need to do this? Some background
I joined a project with about 100+ defined models (even more) on which the paranoid flag is not defined and is false by default. Thankfully, the createdAt, updatedAt and deletedAt timestamps are defined explicitly. But any call to the Model.destroy() function results in a hard delete.
I need to introduce the functionality of a soft delete without changing any model definitions (because that would result in unintended consequences). Again, thankfully, the Model.destroy() method is wrapped in a function which is used in the entire codebase.
I was thinking of introducing an optional flag on this wrapper function which would indicate whether the delete needs to be soft or hard. So the default functionality would be hard delete unless explicitly specified to be a soft delete.
Worst case solution I can think of is that in case soft delete is required, then replace the destroy method with a raw query where I update the deletedAt timestamp manually. But hoping to find cleaner solutions than this :)
The simplest solution would be to use force: false option in case of soft-delete and force: true in case of hard-delete:
async function wrappedDestroy(item, isSoftDelete) {
await item.destroy({ force: !isSoftDelete })
}
Of course, you need to turn on paranoid: true in the model because it also affects all findAll/findOne queries as well (I suppose you wish to hide all soft-deleted records from findAll/findOne by default).

How to update custom sequelize timestamp field?

The timestamp field in sequelize model is defined like this (note: it has to be called last_scraped):
last_scraped: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
},
MySQL query looks like this:
INSERT INTO `businesses` (`site`,`name`,`business_type`,`address`,`price`,`url`,`last_scraped`) VALUES (?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE `name`=VALUES(`name`), `price`=VALUES(`price`), `url`=VALUES(`url`), `site`=VALUES(`site`), `address`=VALUES(`address`);
On first insert, last_scraped field is populated, but the problem is that it is not changing on update.
How can I fix this? Is there any way to do it without using createdAt and updatedAt?
Try this
last_scraped: {
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'),
},

Not store updatedAt with sequelize model

When I store models in my MySQL DB, they are immutable. As a result I can see the need for the createdAt column in my tables, but I don't need the redundant updatedAt column. Can I configure sequelize not to store updatedAt time and then can I drop the column from my table?
Looking at the documentation regarding your situation
If you want sequelize to handle timestamps, but only want some of them, or want your timestamps to be called something else, you can override each column individually:
const Foo = sequelize.define('foo', { /* bla */ }, {
// don't forget to enable timestamps!
timestamps: true,
// I don't want createdAt
createdAt: false,
// I want updatedAt to actually be called updateTimestamp
updatedAt: 'updateTimestamp',
// And deletedAt to be called destroyTime (remember to enable paranoid for this to work)
deletedAt: 'destroyTime',
paranoid: true
})
So in the above example, just set timestamps to be true but then createdAt to be false
Found my own answer at http://docs.sequelizejs.com/manual/tutorial/models-definition.html#configuration, I should use updatedAt: false in my model definition.

How to get create() return auto-increment primary key after creation in sails.js?

I have a model, Case.js:
...
attributes: {
id: {
type: 'integer',
unique: true,
primaryKey: true,
columnName: 'pid' //an auto-increment primary key, generated by MySQL
},
...
}
And I want to get this id after creation:
Case.create({...}).then(function(aCase){
console.log(aCase.id);
})
The creation succeeded, but the output I got is undefined.
I tried setting autoPK to false, and deleting "unique" and "primaryKey" entry, but the result didn't change.
Please tell me how to make create() return this id.
I've worked it out myself. The problem lies in my model Case.js.
In sails.js, if you want a primary key (usually id) created by MySQL with auto-increment to be returned after create(), your model should look like this:
module.exports = {
...
autoPK: false,
attributes: {
id: {
type: 'integer',
unique: true,
primaryKey: true,
autoIncrement: true,
},
...
}
}
Pay attention to "autoIncrement" attribute, it is necessary in my case, and probably in every auto-increment primary key.
I'm looking at the Sails.js documentation for creating a new entry in a database. The method is indicated as
Something.create(values).exec(function (err, records) {
});
In your case, you should have
Case.create({...}).exec(function(err, aCase){
console.log(aCase.id);
})