When using Sequelize.js, the following code doesn't add any foreign key on tables.
var MainDashboard = sequelize.define('main_dashboard', {
title: Sequelize.STRING
}, {
freezeTableName: true
})
MainClient.hasOne(MainDashboard, { foreignKey: 'idClient' })
MainDashboard.hasOne(MainClient, { foreignKey: 'clientId' })
sequelize.sync({ force: true })
Is there any way to force Sequelize.js to add these foreign key constraints?
Before I had the same problem, and solved when I understood the functioning of settings Sequelize.
Straight to the point!
Suppose we have two objects: Person and Father
var Person = sequelize.define('Person', {
name: Sequelize.STRING
});
var Father = sequelize.define('Father', {
age: Sequelize.STRING,
//The magic start here
personId: {
type: Sequelize.INTEGER,
references: 'persons', // <<< Note, its table's name, not object name
referencesKey: 'id' // <<< Note, its a column name
}
});
Person.hasMany(Father); // Set one to many relationship
Maybe it helps you
Edit:
You can read this to understand better:
http://docs.sequelizejs.com/manual/tutorial/associations.html#foreign-keys
For Sequelize 4 this has been updated to the following:
const Father = sequelize.define('Father', {
name: Sequelize.STRING
});
const Child = sequelize.define('Child', {
age: Sequelize.STRING,
fatherId: {
type: Sequelize.INTEGER,
references: {
model: 'fathers', // 'fathers' refers to table name
key: 'id', // 'id' refers to column name in fathers table
}
}
});
Father.hasMany(Child); // Set one to many relationship
Edit:
You can read more on associations at https://sequelize.org/master/manual/assocs.html
You need to add foreignKeyConstraint: true
Try:
MainClient.hasOne(MainDashboard, { foreignKey: 'idClient', foreignKeyConstraint: true })
I just tried to run your code, and the rows seem to be created fine:
CREATE TABLE IF NOT EXISTS `main_dashboard` (`title` VARCHAR(255), `id` INTEGER NOT NULL auto_increment , `idClient` INTEGER, PRIMARY KEY (`id`)) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `main_client` (`id` INTEGER NOT NULL auto_increment, `clientId` INTEGER, PRIMARY KEY (`id`)) ENGINE=InnoDB;
clientId is added to main_client, and idClient is added to main_dashboard
It seems you have slightly confused what the hasOne method does. Each time you call hasOne an association is created, so your code effectively associates the two tables twice. The method you are looking for is belongsTo
If you want each client to have one dashboard, the code would be the following:
MainClient.hasOne(MainDashboard, { foreignKey: 'clientId' })
MainDashboard.belongsTo(MainClient, { foreignKey: 'clientId' })
This creates a clientId field on the main_dashboard table, which relates to the id field of the main_client table
In short belongsTo adds the relation to the table that you are calling the method on, hasOne adds it on the table that is given as argument.
It's amazingly simple.
const MainDashboard = this.sequelize.define('main_dashboard', {/* attributes */}),
MainClient = this.sequelize.define('main_client', {/* attributes */});
MainDashboard.belongsTo(MainClient, { foreignKey: 'clientId' }); // Adds clientId to MainDashboard
It will link this as a foreign key and you may use it as an association. Let me know if I'm missing anything.
Related
I found out that sequelize is creating tables automatically according to the definition of my model names.
I have the following code:
const DataTypes = require("sequelize");
const sequelize = require("../mysql.js");
const Approver = sequelize.define("approver", {
subordinate_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: "user",
key: "id",
},
},
leader_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: "user",
key: "id",
},
},
main_leader_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: "user",
key: "id",
},
},
});
const connect = async () => {
await Approver.sync();
};
connect();
module.exports = Approver;
every time I run the local server, I get the following message in the terminal:
CREATE TABLE IF NOT EXISTS `approvers` (`id` INTEGER NOT NULL auto_increment , `subordinate_id` INTEGER NOT NULL, `leader_id` INTEGER NOT NULL, `main_leader_id` INTEGER NOT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`), FOREIGN KEY (`subordinate_id`) REFERENCES `user` (`id`), FOREIGN KEY (`leader_id`) REFERENCES `user` (`id`), FOREIGN KEY (`main_leader_id`) REFERENCES `user` (`id`)) ENGINE=InnoDB;
and I found out that the table creation is generated from the model's define because I put other names in the model and the table created was the same as the one I had named the code.
I don't know why the table that is created is in the plural "approvers" and in the model I put the name "approver" and apparently if I try to put another name the plural doesn't happen as well as the word "approver".
the big problem is that I have migrations and when I run them the table "approver" is created in my database, but when I run the command to start the local server, the sequelize creates one more table. So I end up with 2 tables in the database, "approver" of the migration and "approvers" of the model.
I already tried to put the migration and the model with the plural name "approver" but this causes an error when I try to use the model, the sequelize shows a missing field error when I try to create or update data, it says that the value "updatedAt" is missing, and this only happens because the automatically generated table creates this field, but the funniest thing is that the table was not created in my Dbeaver but the sequelize shows the error of being missing a field, even the model containing the plural name and the migration too...
I would like to get the result that the table is not created with the plural.
does anyone know how to solve this bug?
enter image description here
You have two problems here:
An auto-creation of a table according to a model definition
Pluralization of a table name while auto-creating it
Solutions:
Just remove sync call or the whole piece of the following code:
const connect = async () => {
await Approver.sync();
};
connect();
If you use migrations to create the whole structure and to make modifications to it then you don't need to use sync method of a model or a Sequelize instance.
Pluralization of table names can be turned off by indicating 'freezeTableName: true' in the model's options (see Enforcing table name to be equal to a model name in the official documentation).
I have three tables(models): Users,preferences,ideas. Users has a column 'username' as a primary key and I would like to add 'username' as foreign key to the other tables . How is it done in sequelize? I am a noob at sequelize ,so please do answer this. The hasMany,belongsTo were confusing to me. It would be really helpful if someone answers this.
For the two objects: User and Preference, you can specify the relationship as follows:
const User = sequelize.define('User', {
username: Sequelize.STRING,
});
const Preference = sequelize.define('Preference', {
id: Sequelize.INTEGER,
//Below, 'users' refer to the table name and 'username' is the primary key in the 'users' table
user: {
type: Sequelize.STRING,
references: {
model: 'users',
key: 'username',
}
}
});
User.hasMany(Preference); // Add one to many relationship
I would suggest to read the following document to understand better:
Sequelize Foreign Key
I am using Sequelize, a nodejs ORM for mysql. Using mysql workbench I made an EEM diagram and pushed that design into the db, so far so good.
Now in Sequelize I have to tell it what the design of the DB looks like, part of that is telling it what foreign keys are called.
In Workbench there is a foreign key tab in the tablethere are variables formatted likefd_positions_tradingPLan1` but I never name that, in fact in my EEM diagram I have
Then if I go to that foreign keys tab at the bottom I get this. I am confused as to exactly what I should tell the ORM the foreign key is...
Let's take your positions Table as reference. To build your model on sequelize you have to do the following:
module.exports = (sequelize, DataTypes) => {
const Position = sequelize.define('Position', { // this is the name that you'll use on sequelize methods, not what you have on your db
// define your columns like this:
tradeName: { //the name of the variable that you'll use on sequelize and js
field: 'trade_name', //the actual name of your column on the table
type: DataTypes.STRING(128) // the data type
},
// .......
// for your foreignKeys you have to define the column like your other attributes.
userId: {
field: 'user_id',
type: DataTypes.INTEGER
},
}, {
tableName: 'positions', //this is the name of your table on the database
underscored: true, // to recognize the underscore names
createdAt: 'created_at', //
updatedAt: 'updated_at',
});
//now for your association let's say that you defined your USER table like this example.
Position.associate = (models) => {
// on the foreignKey value, youhave to put the same that you define above, and on the db.
Position.belongsTo(models.User, { as: 'User', foreignKey: 'user_id' });
//depending on your other relations, you are gonna use hasMany, hasOne, belongsToMany
};
return Position;
};
Sequelize does the association only one way, that means that on this example, you can't query with sequelize from User to Position, to be able to
have two way association you have to defined on both models.
User.associate = (models) => {
// on this case we use hasMany cause user can have many positions I suppose, if not, use hasOne
User.hasMany(models.Poisition, { as: 'positions', foreignKey: 'user_id' }); //remeber to use the same foreignKey name
};
UPDATE:
as is an identfier for Sequelize. Let's say you make two associations for the same model, later when you try to query one of this associations, you can specify the association that you want
User.associate = (models) => {
User.hasMany(models.Poisition, { as: 'positions', foreignKey: 'user_id' });
User.hasMany(models.Poisition, { as: 'customerPositions', foreignKey: 'customer_id' });
};
//the actual association call
User.findAll({
include:[{
model: db.user,
as: 'positions'
}, {
model: db.user,
as: 'customerPositions'
}]
})
Now for fk_positions_users1, this is an identifier for MySQL itself. Sequelize only check for the foreignKey and the models involve. Obviously when Sequelize create the reference, it gives a template name using the table and column name. I tried myself creating a new foreignKey on my table and then updating the model and everything goes fine. You should'nt have problems with that.
I'm using Sails and Waterline for my model associations and I'm not sure what to do in order to fix this error I'm receiving when trying to update a PageChild object.
module.exports = {
tableName: 'Page',
adapter: 'mysql',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
Id: {type: 'integer', autoIncrement: true, primaryKey: true},
pageChildren: {
collection: 'PageChild',
via: 'Page'
}
},
};
module.exports = {
tableName: 'PageChild',
adapter: 'mysql',
attributes: {
Id: {type: 'integer', autoIncrement: true, primaryKey: true},
Page: {
model: 'Page',
columnName: 'PageId'
}
}
};
The model associations work perfectly fine for populating pageChildren from the Page object or for returning the Page object from any of the pageChildren. However, I encounter this foreign key issue when attempting to create or update a PageChild object.
In the mysql db, the Page table has an "Id" attribute while the PageChild table has "Id" and "PageId" attributes.
The error is self explanatory:
foreign key constraint fails CONSTRAINT `PageChild_Page_Id_fk` FOREIGN KEY (`PageId`) REFERENCES `Page` (`Id`)
The rule is, you can only add or update a value in child table which are already present in parent table. So at the time of insertion make sure the value you are trying to insert in child table, already exist in parent table.
What this means is that the ParentId that you add or update on the child row needs to exist on the Parent table.
So, this constraint means that you can't insert a row into PageChild with PageId = 50 if you don't have a row in Page that has an id with a value of 50.
For example, if you want to create a new page, you have to first create an entry in the Page table, then retrieve it's id value and only then can you start doing your inserts into the PageChild table using the id of the Page you made earlier.
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);
})