Foreign Key in Sequelize - mysql

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

Related

Make a reference between two schemes with sequelize creates an error

I try to make a reference between two database schemes. The first scheme is clinicdatabase and the second is supportdatabase
this is the model which is creating the error:
Unhandled rejection SequelizeDatabaseError: Failed to open the referenced table 'supportdatabase.clinics'
My model Staff (scheme: clinicdatabase), which needs the id, as a foreign key, from the model Clinic (scheme: supportdatabase) looks like:
module.exports = (sequelize, DataTypes) => {
const Staff = sequelize.define("Staff", {
STAFF_PASSWORD: DataTypes.STRING,
CLI_CLINICID: {
type: DataTypes.INTEGER,
references: {
model: {
tableName: "clinics",
schema: "clinicdatabase"
},
key: 'id'
}
}
},
);
return Staff;
}
Both schemes are connected and they are working. Is these reference even possible? Do i need some permissions for the schemes? If yes do you know wher to add this or what the right syntax is?

MySQL foreign key name, what is it?

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.

Cannot add or update a child row: a foreign key constraint fails CONSTRAINT `PageChild_Page_Id_fk` FOREIGN KEY (`PageId`) REFERENCES `Page` (`Id`)

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.

Sails js - waterline orm - mysql. Tables autogeneration

When I create my model in sails - waterline the db is autogenerated.
The problem is that my primary keys are unsigned int(10) and the external keys are int(11) (with sign). In fact the relationship is only in my models and not in db.
A code example is the following:
// A user may only have a single pet
var User = Waterline.Collection.extend({
identity: 'user',
connection: 'local-postgresql',
attributes: {
firstName: 'string',
lastName: 'string',
// Add a reference to Pet
pet: {
model: 'pet'
}
}
});
var Pet = Waterline.Collection.extend({
identity: 'pet',
connection: 'local-postgresql',
attributes: {
breed: 'string',
type: 'string',
name: 'string',
// Add a reference to User
user: {
model: 'user'
}
}
});
In this example my database is generated in the following way:
pet "id" (in pet table) is an autoincrement primary key unsigned int(10)
and "pet" (in user table that is an external key pointing to pet id) is a int(11) (signed int). There is a solution to that problem? thanks
The sails-postgresql adapter does not yet create foreign key relationships in the database itself. This is not incorrect and doesn't affect how you use sails/waterline. Everything will work fine, this is just an optimization that hasn't been implemented yet.
There's an open issue if you'd like to share your thoughts there: https://github.com/balderdashy/sails-postgresql/issues/123

Sequelize.js foreign key

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.