Make a reference between two schemes with sequelize creates an error - mysql

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?

Related

Using a const instead of values from database in Sequelize Node.js

I'm working on a project that has some users and roles. I want to add association (belongsToMany) on users and roles. I'm using MySQL database and users are stored in users table. Currently i'm storing roles in database as well but i want roles to be stored in a file instead of database. Is there a way i could use a const instead of table from database.
index.js file:
...
db.user = require("./user.model.js")(sequelize, Sequelize);
db.role = require("./role.model.js")(sequelize, Sequelize);
db.role.belongsToMany(db.user, {
through: "user_roles",
foreignKey: "roleId",
otherKey: "userId"
});
db.user.belongsToMany(db.role, {
through: "user_roles",
foreignKey: "userId",
otherKey: "roleId"
});
role.model.js file
module.exports = (sequelize, Sequelize) => {
const Role = sequelize.define("role", {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
name: {
type: Sequelize.STRING
}
});
return Role;
};
One thing that you could do is eliminate the Role table, and just create a UserRole table with a belongsTo() association to the User table. (And associate User to it by using hasMany())
You could then make the "name" column in UserRole have the ENUM datatype, and have the model draw the values available in that ENUM from reading the file in the file system. (Alternately, you can hard-code the values into the ENUM and that would be the "file" where you're updating possible role names)
I'm not totally sure what problem this is looking to solve, though. This seems like it would lead to a decrease in performance overall, though it WOULD eliminate the need for a Many-to-Many relationship that can be frustrating to work with.

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.

Sequelize create with associations

I have been trying to define a relationship between 3 tables and then create them all in one create function. For some reason, while creating the 3 models, the linking IDs (foreign keys) are undefined and are not passing on. Here are the associations:
Person.js:
models.person.Lead = models.person.hasMany(models.lead, {
onDelete: "CASCADE",
foreignKey: "person_id"
});
Lead.js:
models.lead.Person = models.lead.belongsTo(models.person, {foreignKey: 'person_id'});
models.lead.Sealant_customer = models.lead.hasOne(models.sealant_customer, {
onDelete: "CASCADE",
foreignKey: 'lead_id'
})
sealantCustomer.js:
models.sealant_customer.Lead = models.sealant_customer.belongsTo(models.lead);
The build function:
let sealantCustomer = models.sealant_customer.build({
address: body.address,
city: body.city,
roof_size: body.roofSize,
last_sealed: body.lastSealed,
existingSealant: body.existingSealant,
leaks_freq: body.leaksFrequency,
floor: body.floor,
elevator: body.elevator,
panels: body.panels,
home_type: body.homeType,
urgency: body.urgency,
next_step: body.nextStep,
more_info: body.moreInfo,
lead: {
site,
url: body.url,
date,
ip: body.ip,
person: {
name: body.name,
email: body.email,
phone: body.phone,
date,
city: body.city ? body.city : undefined,
address: body.address ? body.address : undefined,
}
}
}, {
include: [{
model: models.lead,
association: models.sealant_customer.Lead,
include: [{
model: models.person,
association: models.lead.Person
}]
}]
})
The outputted object is good except for the fact that lead_id and person_id are nulls (Each model has its own ID, but not the associated model's id). I also should note there are no validation errors and the data is good.
The library has a bug in the build function as far as I can tell. Same syntax with create worked perfectly.
In Sequelize v6, the association identifier in the include section is not valid. Otherwise, this build function should properly work.

SailsJS update and mySQL custom ID column not working

In SailsJS, I created a model Profiles including a custom primary key as follows:
module.exports = {
tableName: 'tbl_profiles',
autoPK: false,
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
user_id: {
type: 'integer',
size: 11,
columnName: 'user_id',
unique: true,
primaryKey: true,
},
...
Now, when calling the blueprint route to update a user profile, I get the following error:
ER_BAD_FIELD_ERROR: Unknown column 'tbl_profiles.id' in 'where clause'
Debugging this down (and seeing question SailsJS and mySQL custom ID name not working with blue prints not helping) I found out that the update is carried through all right in the db and that the record is changed but in the controller callback function an error and status 400 is raised nevertheless:
Profiles.update({user_id: req.param('id')}, req.body).exec(function(err, profile) {
if (err) {
return res.status(400).json(err);
} else {
return res.status(200).json(profile);
}
});
Tracing down the SQL involved in /node_modules/sails-mysql/node_modules/mysql/lib/protocol/sequences/Sequence.js:48:14, it seems the following statement is executed just after the update is finished (note the final WHERE clause):
SELECT `tbl_profiles`.`user_id`,
`tbl_profiles`.`lastName`,
`tbl_profiles`.`firstName`,
`tbl_profiles`.`date_of_birth`,
`tbl_profiles`.`address_line1`,
`tbl_profiles`.`address_line2`,
`tbl_profiles`.`zip_code`,
`tbl_profiles`.`city`,
`tbl_profiles`.`gender`,
`tbl_profiles`.`country_id`,
`tbl_profiles`.`phone`,
`tbl_profiles`.`user_id`
FROM `tbl_profiles` AS `tbl_profiles`
WHERE `tbl_profiles`.`id` = undefined
Where could I set SailsJS/Waterline to use the custom column ID? Setting autoPK true either in the beginning or the end of the model wouldn't do the trick..

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.