I am using sequelize ORM for my node.js application and have created two simple models.
company.model.js
location.model.js
A company can have multiple locations and a location can belongs to one company.
Here are my models:
company.model.js
'use strict';
module.exports = function(sequelize, DataTypes) {
var Company = sequelize.define('Company', {
id: {
type: DataTypes.INTEGER(3),
allowNull: false,
primaryKey: true,
autoIncrement: true,
comment: "Primary and auto incremented key of the table"
},
companyName: {
field: "company_name",
type: DataTypes.STRING(255),
allowNull: false,
comment: "Company Name"
},
companyCode: {
field: "company_code",
type: DataTypes.STRING(20),
allowNull: false,
unique: true,
comment: "Company Code"
},
contactName: {
field: "contact_name",
type: DataTypes.STRING(100),
allowNull: true,
comment: "Name of contact person"
},
contactNo: {
field: "contact_no",
type: DataTypes.STRING(20),
allowNull: true,
comment: "Company contact number"
},
fax: {
field: "fax",
type: DataTypes.STRING(20),
allowNull: true,
comment: "Company fax number"
},
website: {
field: "website",
type: DataTypes.STRING(50),
allowNull: true,
comment: "Company website url if exist for e.g. mumbai.spiderman.com",
validate: {
isUrl: true
}
},
country: {
field: "country_id",
type: DataTypes.INTEGER(3),
allowNull: false,
comment: "Country for address purpose"
},
state: {
field: "state_id",
type: DataTypes.INTEGER(4),
allowNull: true,
comment: "State for address purpose"
},
city: {
field: "city_id",
type: DataTypes.INTEGER(5),
allowNull: true,
comment: "City for address purpose"
},
landmark: {
field: "landmark",
type: DataTypes.STRING(255),
allowNull: true,
comment: "Address landmark"
},
address: {
field: "address",
type: DataTypes.TEXT,
allowNull: true,
comment: "Company address"
},
status: {
field: "status",
type: DataTypes.ENUM('ACTIVE','INACTIVE','DELETED'),
allowNull: false,
defaultValue: 'ACTIVE',
comment: "Wether a company is active, inactive or deleted"
}
},{
underscored: true,
freezeTableName:true,
tableName:'company',
classMethods:{
associate:function(models){
Company.hasMany(models.Location);
}
},
});
return Company;
};
location.model.js
'use strict';
module.exports = function(sequelize, DataTypes) {
var Location = sequelize.define('Location', {
id: {
type: DataTypes.INTEGER(5),
allowNull: false,
primaryKey: true,
autoIncrement: true,
comment: "Primary and auto incremented key of the table"
},
locationType: {
field: "location_type",
type: DataTypes.ENUM('HEAD_OFFICE','REGIONAL_OFFICE','FRANCHISE'),
allowNull: false,
comment: "Type of location"
},
locationName: {
field: "location_name",
type: DataTypes.STRING(200),
allowNull: false,
comment: "Name of location"
},
locationCode: {
field: "location_code",
type: DataTypes.STRING(20),
allowNull: false,
unique: true,
comment: "Location Code"
},
contactName: {
field: "contact_name",
type: DataTypes.STRING(100),
allowNull: true,
comment: "Name of contact person"
},
contactNo: {
field: "contact_no",
type: DataTypes.STRING(20),
allowNull: true,
comment: "Location contact number"
},
fax: {
field: "fax",
type: DataTypes.STRING(20),
allowNull: true,
comment: "Location fax number"
},
website: {
field: "website",
type: DataTypes.STRING(50),
allowNull: true,
comment: "Location specific website url if exist for e.g. mumbai.spiderman.com",
validate: {
isUrl: true
}
},
country: {
field: "country_id",
type: DataTypes.INTEGER(3),
allowNull: false,
comment: "Location country for address purpose"
},
state: {
field: "state_id",
type: DataTypes.INTEGER(4),
allowNull: true,
comment: "Location state for address purpose"
},
city: {
field: "city_id",
type: DataTypes.INTEGER(5),
allowNull: true,
comment: "Location city for address purpose"
},
landmark: {
field: "landmark",
type: DataTypes.STRING(255),
allowNull: true,
comment: "Location landmark"
},
address: {
field: "address",
type: DataTypes.TEXT,
allowNull: true,
comment: "Location address"
},
status: {
field: "status",
type: DataTypes.ENUM('ACTIVE','INACTIVE','DELETED'),
allowNull: false,
defaultValue: 'ACTIVE',
comment: "Weather a location is active, inactive or deleted"
},
createdBy: {
field: "created_by",
type: DataTypes.INTEGER(11),
allowNull: true,
comment: "User ID who created this location"
},
updatedBy: {
field: "updated_by",
type: DataTypes.INTEGER(11),
allowNull: true,
comment: "User ID who updated this location"
}
},
{
timestamps: true,
underscored: true,
freezeTableName:true,
tableName:'location',
defaultScope: {
where: {
status: 'ACTIVE'
}
},
classMethods:{
associate:function(models){
Location.belongsTo(models.Company, { foreignKey:'company_id', foreignKeyConstraint:true} );
}
}
});
return Location;
};
Now I expected that It will sequelize.sync({force:true}) will create both tables and add a foreign key index to the location table. But it is only create tables. There is no any column named company_id on location table.
Resolved the problem at my own by writing the few lines of code in my singleton module of sequelize:
Object.keys(db).forEach(function(modelName) {
if(db[modelName].hasOwnProperty('associate')) {
db[modelName].associate(db);
}
});
The code will iterate over all the models and call their associate methods directly as they have been defined as classMethods.
Related
I'm trying to retrieve the first 4 characters of the school_name column and give the result the alias of schoolCode, but I'm receiving the following error:
original: RequestError: Invalid column name 'schoolCode'.
Currently I'm able to do it by using an aggregate function:
attributes: [
[Sequelize.fn('DISTINCT', Sequelize.col('STUDENT_ID')), 'studentId'],
'studentId',
'lastName',
'firstName',
'middleName',
[Sequelize.fn('SUBSTRING', Sequelize.col('SCHOOL_NAME'), 1, 4), 'schoolName'],
'courseNum',
'section'
],
I get the data that I need in an object with the property schoolName.
How can I get the same data in a property called schoolCode? when I change schoolName with schoolCode I get the above mentioned error
This is the definition of the table I'm querying
{
schoolName: {
type: DataTypes.STRING,
allowNull: true,
field: 'SCHOOL_NAME'
},
studentId: {
type: DataTypes.INTEGER,
allowNull: false,
field: 'STUDENT_ID',
},
lastName: {
type: DataTypes.STRING,
allowNull: true,
field: 'LAST_NAME'
},
firstName: {
type: DataTypes.STRING,
allowNull: true,
field: 'FIRST_NAME'
},
middleName: {
type: DataTypes.STRING,
allowNull: true,
field: 'MIDDLE_NAME'
},
programNum: {
type: DataTypes.STRING,
allowNull: true,
field: 'PROGRAM_NUM'
},
courseNum: {
type: DataTypes.STRING,
allowNull: true,
field: 'COURSE_NUM'
},
course: {
type: DataTypes.STRING,
allowNull: true,
field: 'COURSE'
},
section: {
type: DataTypes.STRING,
allowNull: true,
field: 'SECTION',
primaryKey: true
},
schStartDate: {
type: DataTypes.DATEONLY,
allowNull: true,
field: 'sch_start_date'
},
schEndDate: {
type: DataTypes.DATEONLY,
allowNull: true,
field: 'sch_end_date'
}
}
I'm trying to insert data to my table with foreign keys from another table. The relationship is already successfully created. But when I try to insert data to the table, it always input null, and I already handle it with add allowNull: false. But still don't know how to input the value into the foreign key value inside table column.
This is my Product model:
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true
},
name: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.TEXT,
allowNull: true
},
price: {
type: DataTypes.DECIMAL,
allowNull: false,
validate: {
isNumeric: {
args: true,
msg: 'Wrong price format'
}
}
},
image: {
type: DataTypes.TEXT,
allowNull: false
}
},
{
sequelize,
paranoid: true,
modelName: 'product'
}
);
and this is my category model:
category.init(
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true
},
name: {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.TEXT,
allowNull: false
}
},
{
sequelize,
paranoid: true,
modelName: 'category'
}
);
and this is relationship between them
category.hasMany(product, {
foreignKey: {
name: 'categoryId',
allowNull: false
},
onDelete: 'CASCADE'
});
product.belongsTo(category, {
foreignKey: {
name: 'categoryId',
allowNull: false
},
onDelete: 'CASCADE'
});
and on inserting code using express, this is the code:
const product = {
name,
description,
price,
image,
businessCompanyId,
categoryId
};
await Product.create(product);
Any help will be great, thank you!
Add a field of categoryId in Product model like this:-
categoryId: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: "category",
key: "id"
}
},
I have not proper understanding of businessCompanyId but hope this will help you!
I'm creating a Model for a 'users' table in MySQL. Ideally I'd like to have a 'firstName' and 'lastName' field and a 'fullName' that would be the addition of the other 2.
Is it possible to have that programatically in the Model or do I have to take care of that at INSERT time ?
const User = sequelize.define("users", {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true,
},
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
},
fullName: {
type: Sequelize.STRING(50),
allowNull: false,
// something that makes 'firstName' + ' ' + 'lastName' ❤️
},
email: {
type: Sequelize.INTEGER(30),
allowNull: false,
},
});
Virtual Colums are what you are looking for.
"Virtual" columns are columns that do not get saved in your database - they are calculated on the fly based on the values of other columns. They are helpful for saving space if there are values we want to use on our instances that can be easily calculated.
const User = sequelize.define("users", {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true,
},
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
},
fullName: {
type: DataTypes.VIRTUAL,
get() {
return `${this.firstName} ${this.lastName}`;
}
},
email: {
type: Sequelize.INTEGER(30),
allowNull: false,
},
});
For more infromation see virtual fields.
I am unable to migrate my models to MySQL db. It's throwing me the below error:
Loaded configuration file "config\config.json".
Using environment "development".
(node:5828) [SEQUELIZE0004] DeprecationWarning: A boolean value was passed to options.operatorsAliases. This is a no-op with v5 and should be removed.
== 20191218125700-mig_admin_roles: migrating =======
ERROR: Could not find migration method: up
models- admin_user.js
module.exports = (sequelize, DataTypes) => {
{
var admin_users = sequelize.define("adminUser", {
id: {
type: DataTypes.INTEGER(22),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: "id"
},
fname: {
type: DataTypes.STRING(20),
allowNull: false,
field: "fname"
},
lname: {
type: DataTypes.STRING(20),
allowNull: true,
field: "lname"
},
phoneNo: {
type: DataTypes.STRING(20),
allowNull: false,
field: "phoneNo"
},
emailId: {
type: DataTypes.STRING(20),
allowNull: false,
unique: true,
field: "emailId"
},
isActive: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: "0",
field: "isActive"
},
password: {
type: DataTypes.STRING(128),
allownull: false,
field: "password"
}
});
admin_users.associate = models => {
admin_users.hasMany(models.adminRole, {
foreignKey: "roleId"
});
};
return admin_users;
}
};
migration: mig-admin_user.js
"use strict";
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable("adminUser", {
id: {
type: Sequelize.INTEGER(22),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: "id"
},
fname: {
type: Sequelize.STRING(20),
allowNull: false,
field: "fname"
},
lname: {
type: Sequelize.STRING(20),
allowNull: true,
field: "lname"
},
phoneNo: {
type: Sequelize.STRING(20),
allowNull: false,
field: "phoneNo"
},
emailId: {
type: Sequelize.STRING(20),
allowNull: false,
unique: true,
field: "emailId"
},
isActive: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: "0",
field: "isActive"
},
password: {
type: Sequelize.STRING(128),
allownull: false,
field: "password"
}
});
},
down: (queryInterface, Sequelize) => {
/*
Add reverting commands here.
Return a promise to correctly handle asynchronicity.
Example:
return queryInterface.dropTable('users');
*/
}
};
I tried looking for this particular error, but couldn't find anything.
could anyone please tell where i might be going wrong?
You need a .sequelizerc in the root of your project and it contains something like this :
module.exports = {
'config': 'database/config.js',
'migrations-path': 'database/migrations',
'seeders-path': 'database/seeders'
}
And you have to point where are your migrations been located.
How do I define a unique index on a combination of columns in sequelize. For example I want to add a unique index on user_id, count and name.
var Tag = sequelize.define('Tag', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
},
count: {
type: DataTypes.INTEGER(11),
allowNull: true
},
name: {
type: DataTypes.STRING,
allowNull: true,
})
You can refer to this doc http://docs.sequelizejs.com/en/latest/docs/models-definition/#indexes
You will need to change your definition like shown below and call sync
var Tag = sequelize.define('Tag', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
},
count: {
type: DataTypes.INTEGER(11),
allowNull: true
},
name: {
type: DataTypes.STRING,
allowNull: true,
}
},
{
indexes: [
{
unique: true,
fields: ['user_id', 'count', 'name']
}
]
});
I have same issue to applied composite unique constraint to multiple
columns but nothing work with Mysql, Sequelize(4.10.2) and NodeJs
8.9.4 finally I fixed through following code.
queryInterface.createTable('actions', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
system_id: {
type: Sequelize.STRING,
unique: 'actions_unique',
},
rule_id: {
type: Sequelize.STRING,
unique: 'actions_unique',
},
plan_id: {
type: Sequelize.INTEGER,
unique: 'actions_unique',
}
}, {
uniqueKeys: {
actions_unique: {
fields: ['system_id', 'rule_id', 'plan_id']
}
}
});
If the accepted one is not working then try the below code. It worked for me in my case rather the accepted one.
var Tag = sequelize.define('Tag', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
unique: 'uniqueTag',
},
count: {
type: DataTypes.INTEGER(11),
allowNull: true,
unique: 'uniqueTag',
},
name: {
type: DataTypes.STRING,
allowNull: true,
unique: 'uniqueTag',
}
});
I tried to create an index on a single column.
This worked for me. Hope this helps.
Model
module.exports = (sequelize, DataTypes) => {
const Tag = sequelize.define(
"Tag",
{
name: { type: DataTypes.STRING, unique: true },
nVideos: DataTypes.INTEGER
},
{
indexes: [
{
unique: true,
fields: ["name"]
}
]
}
);
return Tag;
};
Migration
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable(
"Tags",
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING,
unique: "unique_tag"
},
nVideos: { type: Sequelize.INTEGER },
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
},
{
uniqueKeys: {
unique_tag: {
customIndex: true,
fields: ["name"]
}
}
}
);
},
down: queryInterface => {
return queryInterface.dropTable("Tags");
}
};
I prefer sequelize sync method with composite unique, If not passing indexes name u will get a error as below on adding many indexes in index array.
error: SequelizeDatabaseError: Identifier name 'LONG_NAME' is too long
module.exports = function (sequelize: any, DataTypes: any) {
return sequelize.define('muln_user_goals_transaction', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING(),
allowNull: false,
},
email: {
type: DataTypes.STRING(),
allowNull: false,
},
phone: {
type: DataTypes.STRING(),
allowNull: false,
},
amount: {
type: DataTypes.INTEGER(8),
allowNull: false
},
deleted: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
}, {
tableName: 'muln_user_goals_transaction',
timestamps: false,
indexes: [
{
name: 'unique_index',
unique: true,
fields: ['name', 'email', 'phone', 'amount', 'deleted']
}
],
defaultScope: {
where: {
deleted: false
}
}
});
};
Sequelize composite unique (manual)
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Model', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
fieldOne: {
type: Sequelize.INTEGER,
unique: 'uniqueTag',
allowNull: false,
references: {
model: 'Model1',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'cascade'
},
fieldsTwo: {
type: Sequelize.INTEGER,
unique: 'uniqueTag',
allowNull: false,
references: {
model: 'Model2',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'cascade'
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
.then(function() {
return queryInterface.sequelize.query(
'ALTER TABLE `UserFriends` ADD UNIQUE `unique_index`(`fieldOne`, `fieldTwo`)'
);
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Model');
}
};