Sequelize. Specifying the onUpdate parameter does not work when defining an association - node.js

I have 2 models:
const Item = sequelize.define('items', {
id: {type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true},
itemPosition: {type: DataTypes.INTEGER, allowNull: false},
title: {type: DataTypes.STRING, unique: true, allowNull: false}
}, {
timestamps: false
})
const ItemRow = sequelize.define('itemRows', {
id: {type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true},
rowPosition: {type: DataTypes.INTEGER, allowNull: false},
serialNumber: {type: DataTypes.INTEGER},
softwareName: {type: DataTypes.STRING, allowNull: false},
linkText: {type: DataTypes.STRING},
link: {type: DataTypes.TEXT},
softwareVersion: {type: DataTypes.STRING}
}, {
timestamps: false
})
Next, I create a one-to-many relationship:
Item.hasMany(ItemRow, {
foreignKey: {
name: 'itemId',
allowNull: false
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
hooks: true
})
ItemRow.belongsTo(Item)
Result:
Update Rule: No Action
Deletion Rule: Cascade
Result in Microsoft SQL Server Management Studio
I tried to repeat the example from the documentation on setting up a foreign key with onUpdate and onDelete parameters. Same problem

Related

How to disable createdAt field in a Sequelize model?

I need an updatedAt field, but not a createdAt field.
So, I wrote this model:
const Vote = sequelize.define('Vote', {
createdAt: false,
updatedAt: { type: DataTypes.DATE, allowNull: false },
type: { type: DataTypes.INTEGER, allowNull: true },
userId: { type: DataTypes.INTEGER, allowNull: false },
postId: { type: DataTypes.INTEGER, allowNull: false }
});
However, when I try to find a row, Sequelize includes createdAt for some reason. I've also tried just removing the createdAt: false, but it makes no difference.
Do I just have to manually filter out createdAt in all my queries?
Shouldn't this be controlled by my model?
Thanks!
Ok, so you can disable createdAt while keeping updatedAt by disabling timestamps, and then manually adding back updatedAt with a literal timestamp type to set updatedAt automatically as normal.
Like this:
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: sequelize.literal('CURRENT_TIMESTAMP')
},
type: { type: DataTypes.INTEGER, allowNull: true },
userId: { type: DataTypes.INTEGER, allowNull: false },
postId: { type: DataTypes.INTEGER, allowNull: false }
},
{ timestamps: false }
);

sequelize - inner join gives an error after added a foreign key

i have these 2 models:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true
},
service_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services',
key: 'id'
}
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
limit: {
type: DataTypes.INTEGER(11),
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
}
});
};
which is parent of this model: (services_user_prices can override services_prices )
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_user_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: true
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
currency: {
type: DataTypes.STRING(255),
allowNull: true
},
is_active: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
is_trial: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
start_date: {
type: DataTypes.DATE,
allowNull: false
},
end_date: {
type: DataTypes.DATE,
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
},
bundle_price_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services_prices',
key: 'id'
}
}
});
};
when trying to join them i get an error:
EagerLoadingError: services_prices is not associated to services_user_prices!
const result= await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 }, include:[{db.services_prices}]
});
in the db services_user_prices has foreign key to services_prices table
what am i doing wrong?
Well if you are using sequelize then you need to update your model because
by default, sequelize will be looking for foreign key starts with model name like
you have defined bundle_price_id as a foreign key for services_prices.
You need to change your column name to services_price_id then it will get fixed.
or if you want to use bundle_price_id you need to define it in your model relation as.
Model.belongsTo(models.ModelName, { foreignKey: 'your_key'} )
Please feel free if you need to ask anything else.
As complement of the above answer you need to add an identifier with as: on the association like this:
Model.belongsTo(models.ModelName, { foreignKey: 'your_key', as:'your_identifier' } )
Then when you do the include on the method you also call the identifier:
await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 },
include:[{
model: db.services_prices
as: 'your_identifier'
}]
});
If you don't define the foreignKey field, the as field will set the column name.

how can i use limit in include model using sequelize

i want to get user's images at limit 2 from Follow model.
Models
const Follow = connector.define('Follow', {
no: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
follower_id: {
type: Sequelize.INTEGER,
allowNull: true
},
target_id: {
type: Sequelize.INTEGER,
allowNull: true
},
isDelete: {
type: Sequelize.BOOLEAN,
allowNull: false
},
create_dt,
delete_dt
}
const User = connector.define('User', {
no: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
username: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false
},
password: {
type: Sequelize.STRING,
allowNull: false
},
profile_img: {
type: Sequelize.STRING,
allowNull: true
},
bio: {
type: Sequelize.STRING,
allowNull: true
},
phone: {
type: Sequelize.STRING,
allowNull: true
},
gender: {
type: Sequelize.STRING,
allowNull: true
},
website: {
type: Sequelize.STRING,
allowNull: true
},
isDelete: {
type: Sequelize.BOOLEAN,
allowNull: false
},
create_dt,
update_dt,
delete_dt
}
const Image = connector.define('Image', {
no: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
file: {
type: Sequelize.STRING,
allowNull: false
},
location: {
type: Sequelize.STRING,
allowNull: true
},
caption: {
type: Sequelize.STRING,
allowNull: true
},
tags: {
type: Sequelize.STRING,
allowNull: true
},
isDelete: {
type: Sequelize.BOOLEAN,
allowNull: false
},
create_dt,
update_dt,
delete_dt,
user_id: {
type: Sequelize.INTEGER,
allowNull: true
}
}
and, join
User.hasMany(Image, {foreignKey: 'user_id'})
Image.belongsTo(User, {foreignKey: 'user_id'})
User.hasMany(Follow, {foreignKey: 'follower_id'})
Follow.belongsTo(User, {foreignKey: 'follower_id'})
User.hasMany(Follow, {foreignKey: 'target_id'})
Follow.belongsTo(User, {foreignKey: 'target_id'})
so, i tried get user's images from follow by use include.
const followerImages = await Follow.findAll({
attributes: ['target_id'],
where:{
follower_id: loginUser_id
},
include:[
{
model: User,
required: true,
attributes: ['username', 'email', 'profile_img'],
include:[
{
model: Image,
required: true
}
]
}
]
})
but i want to get images at limit 2.
so i tried that
const followerImages = await Follow.findAll({
attributes: ['target_id'],
where:{
follower_id: loginUser_id
},
include:[
{
model: User,
required: true,
attributes: ['username', 'email', 'profile_img'],
include:[
{
model: Image,
required: true,
limit: 2
}
]
}
]
})
but it makes bugs i cant understand.
images field is a array contain empty object at 4.
all same..
what is the problem?
how can i solve this problem??
You can try :
include:[
{
model: Image,
attributes : ['id','user_id','image'] , // <---- don't forget to add foreign key ( user_id )
separate : true, // <--- Run separate query
limit: 2
}
]
Limit causes the issues some time on nested level , so it always safe to run that query separately.

Sequelize - How to define ON DELETE action during model definition

I would like to ask you if it is possible to set ON DELETE action while defining a Sequelize model, for example:
sequelize.define('oAuthAccessTokens', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
createdAt: Sequelize.DATE,
updatedAt: Sequelize.DATE,
accessToken: { type: Sequelize.STRING(256), allowNull: false },
expires: { type: Sequelize.DATE, allowNull: false },
scope: Sequelize.STRING(255),
clientId: {
type: Sequelize.STRING(80),
allowNull: false,
references: {
model: 'oAuthClients',
key: "clientId",
**onDelete: "cascade"** // here is my try
}
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'oAuthUsers',
key: "id",
**onDelete: "cascade"** // here is my try
}
}
});
I know it's possible to pass a proper option to hasOne() method, but what about such a model definition? I hope there is a way which is not mentioned in the official documentation.
Updated
The problem is solved now. The onDelete attribute should be outside the references one.
sequelize.define('oAuthAccessTokens', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
createdAt: Sequelize.DATE,
updatedAt: Sequelize.DATE,
accessToken: { type: Sequelize.STRING(256), allowNull: false },
expires: { type: Sequelize.DATE, allowNull: false },
scope: Sequelize.STRING(255),
clientId: {
type: Sequelize.STRING(80),
allowNull: false,
onDelete: "cascade",
references: {
model: 'oAuthClients',
key: "clientId",
}
},
userId: {
type: Sequelize.INTEGER,
onDelete: "cascade",
allowNull: false,
references: {
model: 'oAuthUsers',
key: "id"
}
}
});
The problem is solved now. The onDelete attribute should be outside the references one.
sequelize.define('oAuthAccessTokens', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
createdAt: Sequelize.DATE,
updatedAt: Sequelize.DATE,
accessToken: { type: Sequelize.STRING(256), allowNull: false },
expires: { type: Sequelize.DATE, allowNull: false },
scope: Sequelize.STRING(255),
clientId: {
type: Sequelize.STRING(80),
allowNull: false,
onDelete: "cascade",
references: {
model: 'oAuthClients',
key: "clientId",
}
},
userId: {
type: Sequelize.INTEGER,
onDelete: "cascade",
allowNull: false,
references: {
model: 'oAuthUsers',
key: "id"
}
}
});

Why do I have twice the foreign keys using Sequelize

I'm trying to setup a simple blog application, I have the following schema definition:
Here is User:
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define("User", {
id: {type: DataTypes.BIGINT, autoincrement:true, primaryKey: true},
firstName: {type: DataTypes.STRING},
lastName: {type: DataTypes.STRING},
nickName: {type: DataTypes.STRING},
email: {type: DataTypes.STRING, unique: true, comment: "Unique "},
password: {type: DataTypes.STRING},
salt: {type: DataTypes.STRING},
enabled: {type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true}
}, {
freezeTableName: true,
classMethods: {
associate: function (models) {
User.hasMany(models.Article, {as: "Articles", constraints: false});
User.hasMany(models.Comment, {as: "Comments", constraints: false});
}
}
});
return User;
};
Here is Article:
module.exports = function(sequelize, DataTypes) {
var Article = sequelize.define("Article", {
id: {type: DataTypes.BIGINT, autoincrement:true, primaryKey: true},
slug: {type: DataTypes.STRING, comment: "Unique URL slug to access the article"},
title: {type: DataTypes.STRING},
content: {type: DataTypes.TEXT},
created: {type: DataTypes.DATE, defaultValue: DataTypes.NOW},
published: {type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true}
}, {
freezeTableName: true,
classMethods: {
associate: function (models) {
Article.belongsTo(models.User, {as: "Author", foreignKey: "author_id"});
Article.hasMany(models.Comment, {as: "Comments", constraints: false});
}
}
});
return Article;
};
and Comment:
module.exports = function(sequelize, DataTypes) {
var Comment = sequelize.define("Comment", {
id: {type: DataTypes.BIGINT, autoincrement:true, primaryKey: true},
content: {type: DataTypes.TEXT},
status: {type: DataTypes.INTEGER, defaultValue: 1},
author: {type: DataTypes.BIGINT},
article: {type: DataTypes.BIGINT}
}, {
freezeTableName: true,
classMethods: {
associate: function (models) {
Comment.hasOne(Comment, {as : "Parent", foreignKey: "parent_id"});
Comment.belongsTo(models.User, {as: "Author", foreignKey: "author_id"});
Comment.belongsTo(models.Article, {as: "Article", foreignKey: "article_id"});
}
}
});
return Comment;
};
The tables are created correctly but I end up with 2 foreign keys each time, for instance this is the Article table in MySQL:
'id','bigint(20)','NO','PRI','0',''
'slug','varchar(255)','YES','',NULL,''
'title','varchar(255)','YES','',NULL,''
'content','text','YES','',NULL,''
'created','datetime','YES','',NULL,''
'published','tinyint(1)','NO','','1',''
'createdAt','datetime','NO','',NULL,''
'updatedAt','datetime','NO','',NULL,''
'author_id','bigint(20)','YES','MUL',NULL,''
'UserId','bigint(20)','YES','',NULL,''
UserId == author_id
User Table:
'id','bigint(20)','NO','PRI','0',''
'firstName','varchar(255)','YES','',NULL,''
'lastName','varchar(255)','YES','',NULL,''
'nickName','varchar(255)','YES','',NULL,''
'email','varchar(255)','YES','UNI',NULL,''
'password','varchar(255)','YES','',NULL,''
'salt','varchar(255)','YES','',NULL,''
'enabled','tinyint(1)','NO','','1',''
'createdAt','datetime','NO','',NULL,''
'updatedAt','datetime','NO','',NULL,''
This table is correct (no foreign keys)
Comment:
'id','bigint(20)','NO','PRI','0',''
'content','text','YES','',NULL,''
'status','int(11)','YES','','1',''
'author','bigint(20)','YES','',NULL,''
'article','bigint(20)','YES','',NULL,''
'createdAt','datetime','NO','',NULL,''
'updatedAt','datetime','NO','',NULL,''
'ArticleId','bigint(20)','YES','',NULL,''
'parent_id','bigint(20)','YES','MUL',NULL,''
'author_id','bigint(20)','YES','MUL',NULL,''
'article_id','bigint(20)','YES','MUL',NULL,''
'UserId','bigint(20)','YES','',NULL,''
ArticleId == article_id and UserId == author_id
As you can see I have the version camel cased and the one I've specified. What did I miss?
** EDIT **
There is no constraints in the database for the camel case field: UserId and ArticleId but Sequelize created the fields in the tables.
You need to add the foreign key on both sides of the relation, e.g:
User.hasMany(models.Article, {constraints: false, foreignKey: 'author_id'});

Resources