Composite primary key in junction table - Sequelize - mysql

Working with Sequelize and MySQL database, I was trying to achieve composite primary keys combination in junction table, but unfortunately without result.
I have tables:
They are in relation many to many. In junction table user_has_project I want two primary keys combination: user_id and project_id.
Sequelize models definition:
User:
module.exports = function(sequelize, Sequelize) {
var User = sequelize.define('user', {
id: {
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER(11)
},
name: {
type: Sequelize.STRING(100),
allowNull: false
}
},{
timestamps: false,
freezeTableName: true,
underscored: true
});
User.associate = function (models) {
models.user.belongsToMany(models.project, {
through: 'user_has_project',
foreignKey: 'user_id',
primaryKey: true
});
};
return User;
}
Project:
module.exports = function(sequelize, Sequelize) {
var Project = sequelize.define('project', {
id: {
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER(11)
},
name: {
type: Sequelize.STRING(100),
allowNull: false
}
},{
timestamps: false,
freezeTableName: true,
underscored: true
});
Project.associate = function (models) {
models.project.belongsToMany(models.user, {
through: 'user_has_project',
foreignKey: 'project_id',
primaryKey: true
});
};
return Project;
}
I was trying to 'force' Primary keys definition in user_has_project table using "primaryKey: true" in both models association, but definition above is creating only user_id as PRI and project_id as MUL

What is Sequelize version? I tested Sequelize 4 in sqlite3, the definition above makes a query
CREATE TABLE IF NOT EXISTS `user_has_project` (`created_at` DATETIME NOT NULL, `updated_at` DATETIME NOT NULL, `user_id` INTEGER(11) NOT NULL REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, `project_id` INTEGER(11) NOT NULL REFERENCES `project` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (`user_id`, `project_id`));
Is "PRIMARY KEY (user_id, project_id)" what you want?

Related

One-to-one relation on sequelize not working

I'm trying to use Sequelize with express.js and MySQL, but i cant get a one-to-one relation to work.
The API always responses the address_id with the integer informed in the field, but not with the infos in the customers_addresses table. I try to force the eager loading by using { include: { all: true }}, but with no success.
Below is the files involved.
Can someone help ? :)
How the two tables are created:
CREATE TABLE IF NOT EXISTS `customers_addresses`
(`address_id` INTEGER NOT NULL auto_increment , `numero_casa` VARCHAR(255),
`complemento` VARCHAR(255), `rua` VARCHAR(255), `bairro` VARCHAR(255), `cidade`
VARCHAR(255), `estado` VARCHAR(2), `cep` VARCHAR(9), PRIMARY KEY (`address_id`))
CREATE TABLE IF NOT EXISTS `customers` (`customer_id` INTEGER NOT NULL auto_increment ,
`first_name` VARCHAR(25) NOT NULL, `last_name` VARCHAR(50) NOT NULL, `cpf` CHAR(11) NOT NULL,
`rg` VARCHAR(20) NOT NULL, `expedidor_rg` VARCHAR(20) NOT NULL, `inss_number` INTEGER,
`inss_situation` INTEGER, `email` VARCHAR(30), `phone` VARCHAR(20), `gender` VARCHAR(1),
`civil_state` VARCHAR(255), `address_id` INTEGER, PRIMARY KEY (`customer_id`),
FOREIGN KEY (`address_id`) REFERENCES `customers_addresses` (`address_id`))
The init-models.js file:
function initModels(sequelize) {
var customers = _customers(sequelize, DataTypes);
var customers_addresses = _customers_addresses(sequelize, DataTypes);
customers.hasOne(customers_addresses, { foreignKey: "address_id"});
customers_addresses.belongsTo(customers, { foreignKey: "address_id"});
return {
customers,
customers_addresses,
};
}
The customers.js model:
const Sequelize = require('sequelize');
module.exports = function(sequelize, DataTypes) {
return sequelize.define('customers', {
customer_id: {
autoIncrement: true,
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
first_name: {
type: DataTypes.STRING(25),
allowNull: false
},
last_name: {
type: DataTypes.STRING(50),
allowNull: false
},
cpf: {
type: DataTypes.CHAR(11),
allowNull: false
},
rg: {
type: DataTypes.STRING(20),
allowNull: false
},
expedidor_rg: {
type: DataTypes.STRING(20),
allowNull: false
},
inss_number: {
type: DataTypes.INTEGER,
allowNull: true
},
inss_situation: {
type: DataTypes.INTEGER,
allowNull: true
},
email: {
type: DataTypes.STRING(30),
allowNull: true
},
phone: {
type: DataTypes.STRING(20),
allowNull: true
},
gender: {
type: DataTypes.STRING(1),
allowNull: true
},
civil_state: {
type: DataTypes.STRING(255),
allowNull: true
},
address_id: {
type: DataTypes.INTEGER,
notNull: true,
references: {
model: 'customers_addresses',
key: 'address_id'
}
}
}, {
sequelize,
tableName: 'customers',
timestamps: false
});
};
How the API controller calls it:
customers.findAll({ include: { all: true }})
The query that is finally executed:
Executing (default): SELECT `customer_id`, `first_name`, `last_name`, `cpf`, `rg`, `expedidor_rg`, `inss_number`, `inss_situation`, `email`, `phone`, `gender`, `civil_state`, `address_id` FROM `customers` AS `customers`;
Try this in your API Controller. I think we should call the model name that have associations with the customer table
customers.findAll({include: [{model:customer_addresses}]})

Cannot add foreign key constraint errno: 1215 sequlize/mysql

So. I'm creating tables and while migrating i'm facing the error:
Cannot add foreign key constraint
errno: 1215
sqlState: 'HY000',
sqlMessage: 'Cannot add foreign key constraint',
sql: 'CREATE TABLE IF NOT EXISTS users_questionnaire_contact\n' +
" ( user_id int(10) unsigned NOT NULL DEFAULT '0',\n" +
" del int(10) unsigned NOT NULL DEFAULT '0',\n" +
" id_questionnaire int(10) unsigned NOT NULL DEFAULT '0',\n" +
" contact char(1) COLLATE 'utf8_general_ci' NOT NULL DEFAULT '1',\n" +
' createdAt datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,\n' +
' updatedAt datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,\n' +
' CONSTRAINT FK_UQContactUser FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,\n' +
' FOREIGN KEY (id_questionnaire) REFERENCES questionnaires(id),\n' +
' PRIMARY KEY (user_id, id_questionnaire)\n' +
' ) ENGINE=InnoDB DEFAULT CHARSET=utf8;'
},
I'm using sequlize.js orm and sequlize:cli for migrating. Here is my model form where i'm getting an error.
module.exports = function(sequelize, DataTypes) {
return sequelize.define('UserQuestionnaireContact', {
user_id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
defaultValue: '0',
primaryKey: true
},
id_questionnaire: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
defaultValue: '0',
primaryKey: true
},
contact: {
type: DataTypes.CHAR(1),
allowNull: false,
defaultValue: '1'
}
}, {
tableName: 'users_questionnaire_contact',
defaultScope: { attributes: { exclude: [ 'id'] } }
});
};
My user model:
module.exports = function(sequelize, DataTypes) {
const Model = sequelize.define('User', {
company_id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
references: {
model: 'Company',
key: 'id'
}
},
first_name: {
type: DataTypes.STRING(512),
allowNull: false
},
last_name: {
type: DataTypes.STRING(250),
allowNull: true
},
career_category_id: {
type: DataTypes.INTEGER(10),
allowNull: true
},
training_course_id: {
type: DataTypes.INTEGER(11),
allowNull: true
},
country_id: {
type: DataTypes.INTEGER(11),
allowNull: true
},
currency_id: {
type: DataTypes.INTEGER(11),
allowNull: true
},
}, {
tableName: 'users'
});
Model.associate = models => {
Model.belongsTo(models.Currency, {foreignKey: 'currency_id', as: 'curr'});
Model.belongsTo(models.Country, {foreignKey: 'country_id', as: 'country'});
Model.belongsTo(models.CareerCategory, {foreignKey: 'career_category_id', as: 'career'});
Model.belongsTo(models.TrainingCourse, {foreignKey: 'training_course_id', as: 'training_course'});
Model.belongsTo(models.Company, {foreignKey: 'company_id', as: 'company'});
Model.hasMany(models.Attempt, {foreignKey: 'user_id', as: 'attempts'});
Model.hasMany(models.UserQuestionnaireContact, {foreignKey: 'user_id', as: 'u_q_contact'});
Model.hasMany(models.UsersQuestionnaireAttemptLimit, {foreignKey: 'user_id', as: 'u_q_limit'});
};
return Model;
};
And my questionaries table which is related to:
const Model = sequelize.define('Questionnaire', {
type: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: true,
defaultValue: '0'
},
}, {
tableName: 'questionnaires'
});
Model.associate = models => {
Model.belongsToMany(models.Company, {
as: 'questCompanies',
foreignKey: 'questionnaire_id',
otherKey: 'company_id',
through: 'company_questionnaire_maps'});
Model.hasMany(models.Attempt, {foreignKey: 'questionnaire_id', as: 'q_attempts'});
Model.hasMany(models.QuestionGroup, {foreignKey: 'questionnaire_id', as: 'q_groups'});
Model.hasMany(models.CompanyQuestionnaireMap, {foreignKey: 'questionnaire_id', as: 'company_questionnaire_maps'});
};
Does somebody have any idea how to fix this ? Thanks in advance.

Unhandled rejection SequelizeDatabaseError: Cannot add foreign key constraint

I have 2 tables: admin_user and admin_account.
const Sequelize = require('sequelize');
module.exports = (sequelize, DataTypes) => {
var admin_user = sequelize.define('admin_user', {
id: {
autoIncrement: true,
type: Sequelize.INTEGER,
primaryKey: true
},
name: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
}
},
user_name:{
type: Sequelize.STRING,
allowNull: false,
unique: true
}
});
admin_user.associate = (models) =>{
admin_user.hasOne(models.admin_account, { foreignKey: 'admin_user_id' });
};
return admin_user;
};
'use strict';
const Sequelize = require('sequelize');
module.exports = (sequelize, DataTypes) => {
var admin_account = sequelize.define('admin_account', {
admin_user_id:{
type: Sequelize.INTEGER,
primaryKey: true
},
password: {
type: Sequelize.STRING
}
});
return admin_account;
};
and getting this error while creating the table:
Executing (default): CREATE TABLE IF NOT EXISTS admin_users (id INTEGER auto_increment , name VARCHAR(255), email VARCHAR(255) NOT NULL UNIQUE, user_name VARCHAR(255) NOT NULL UNIQUE, createdAt DATETIME NOT NULL, updatedAt DATETIME NOT NULL, PRIMARY KEY (id)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM admin_users FROM milkman_prod1
Executing (default): CREATE TABLE IF NOT EXISTS admin_accounts (admin_user_id INTEGER , password VARCHAR(255), createdAt DATETIME NOT NULL, updatedAt DATETIME NOT NULL, PRIMARY KEY (admin_user_id), FOREIGN KEY (admin_user_id) REFERENCES admin_users (id) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB;
Unhandled rejection SequelizeDatabaseError: Cannot add foreign key constraint
Please try with this code:
'use strict';
const Sequelize = require('sequelize');
module.exports = (sequelize, DataTypes) => {
var admin_account = sequelize.define('admin_user', {
admin_user_id:{
type: Sequelize.INTEGER,
primaryKey: true
},
password: {
type: Sequelize.STRING
}
});
admin_account.associate = (models) =>{
admin_account.belongsTo(models.admin_user);
};
return admin_account;
};

Waterline ORM inserting blank cells on MySQL

I've a Sails app, that uses MySQL as the DB (well, MySQL and others, but the problem is with MySQL). My problem is that is creating a record on the DB table, but all the cells are empty, and I don't understand why! Let me share the code and the table definition:
CREATE TABLE `components` (
`id` INT NOT NULL AUTO_INCREMENT,
`column1` VARCHAR(32) NOT NULL,
`column2` VARCHAR(50) NOT NULL,
`group` INT,
`subgroup` INT,
`column3` INT,
PRIMARY KEY (`id`),
FOREIGN KEY (`column1`) REFERENCES `table1`(`recipe_id`),
FOREIGN KEY (`group`) REFERENCES `table_groups`(`id`),
FOREIGN KEY (`subgroup`) REFERENCES `table_groups`(`id`),
FOREIGN KEY (`column3`) REFERENCES `table2`(`id`))
DEFAULT CHARSET=utf8;
Sails model definition:
module.exports = {
connection: 'mysqlDb',
autoCreatedAt: false,
autoUpdatedAt: false,
column1: {
type: 'string',
required: true
},
column2: {
type: 'string',
required: true
},
group: {
type: 'integer',
required: true
},
subgroup: {
type: 'integer',
required: true
},
column3: {
type: 'integer'
}
};
Waterline create query:
const data = {
column1: '383qa8475dd11231aa682y2728172y12',
column2: 'canvas',
groups: 2,
subgroup: 5,
column3: 1
};
Components.create(data).exec((error, results) => {
if(error) console.error(error);
else console.log('Created!');
});
It doesn't break, but the record on MySQL is empty, so why is inserting everything empty??? In the INT columns, is inserting a 0.
What am I missing?
Thanks!
Oh my... I found the problem. I forgot to wrap the column names, in the model, inside attributes key, so the model should be like this:
module.exports = {
connection: 'mysqlDb',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
column1: {
type: 'string',
required: true
},
column2: {
type: 'string',
required: true
},
group: {
type: 'integer',
required: true
},
subgroup: {
type: 'integer',
required: true
},
column3: {
type: 'integer'
}
}
};
Very silly mistake, but it cost me HOURS! Anyway, it is silly, but I will leave my question here, if anyone makes the same mistake.

Why Can't I Save Many to Many table with Different Column Value in Sequelize?

I have 2 tables with many to many relationships through an intersection table.
Products --> Orders <-- Outlets
This is what Sequelize generates
CREATE TABLE IF NOT EXISTS `Orders` (`id` INTEGER auto_increment , `amount` INTEGER, `orderDate` DATETIME, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `OutletId` INTEGER, `ProductId` INTEGER, `UserId` INTEGER, UNIQUE `Orders_ProductId_OutletId_unique` (`OutletId`, `ProductId`), PRIMARY KEY (`id`), FOREIGN KEY (`OutletId`) REFERENCES `Outlets` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, FOREIGN KEY (`ProductId`) REFERENCES `Products` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, FOREIGN KEY (`UserId`) REFERENCES `Users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB;
I know it creates a unique key: UNIQUE Orders_ProductId_OutletId_unique (OutletId, ProductId).
That's why I can't save, them with the same OutletId and ProductId, however, my case, OutletId and ProductId can be the same, but the orderDate must be different.
So I save this is okay,
OrderId, ProductId, OutletId, orderDate
1, 1, 1, '2016-1-1'
2, 2, 1, '2016-1-1'
However, when I save another row:
1, 1, 1, '2016-1-2'
MySql gives me this error:
ERROR 1062: 1062: Duplicate entry '1-1' for key 'Orders_ProductId_OutletId_unique'
Ok, so the question is, how can I create the model that has this validation or constraint?
Here are my models:
Order
'use strict';
module.exports = function(sequelize, DataTypes) {
var Order = sequelize.define('Order', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
amount: DataTypes.INTEGER,
orderDate: DataTypes.DATE
},
{
associate: function(models){
Order.belongsTo(models.Outlet);
Order.belongsTo(models.Product);
Order.belongsTo(models.User);
}
}
);
return Order;
};
Product
'use strict';
module.exports = function(sequelize, DataTypes) {
var Product = sequelize.define('Product', {
inventoryCode: DataTypes.STRING,
name: DataTypes.STRING,
nameKh: DataTypes.STRING,
unitKh: DataTypes.STRING,
unit: DataTypes.STRING,
monthlyCaseTarget: DataTypes.INTEGER,
pieces: DataTypes.INTEGER,
star: DataTypes.BOOLEAN,
price: DataTypes.FLOAT,
active: DataTypes.BOOLEAN
},
{
associate: function(models){
Product.belongsToMany(models.Outlet, {through: models.Order});
Product.belongsTo(models.Category);
// Product.hasMany(models.Order);
}
}
);
return Product;
};
Outlets
'use strict';
module.exports = function(sequelize, DataTypes) {
var Outlet = sequelize.define('Outlet', {
outletCode: DataTypes.STRING,
outletName: DataTypes.STRING,
outletNameKh: DataTypes.STRING,
outletSubtype: DataTypes.STRING,
perfectStoreType: DataTypes.STRING,
address: DataTypes.STRING
},
{
associate: function(models){
Outlet.belongsToMany(models.Product, {through: models.Order});
Outlet.belongsTo(models.Distributor);
// Outlet.hasMany(models.Order);
}
}
);
return Outlet;
};
Since sequelize produces this query:
UNIQUE Orders_ProductId_OutletId_unique (OutletId, ProductId)
so I kinda hack it by adding the composite unique key to the order column.
'use strict';
module.exports = function(sequelize, DataTypes) {
var Order = sequelize.define('Order', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
amount: {
type: DataTypes.INTEGER
},
orderDate: {
type: DataTypes.DATE,
unique: 'Orders_ProductId_OutletId_unique'
}
},
{
associate: function(models){
Order.belongsTo(models.Outlet);
Order.belongsTo(models.Product);
Order.belongsTo(models.User);
}
}
);
return Order;
};