How to add foreign key using sequelize mysql - mysql

"I have 2 tables "Users" and "Profile_personals". How do I add a foreign key constraint to my profile personals using my "user_id" primary that's inside my Users table? I'm working with node.js, sequelize mysql.
Users(parent Table):
const Sequelize = require('sequelize')
const db = require("../database/db.js")
module.exports = db.sequelize.define(
"users",
{
user_id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
}
},
{
timestamps: false
}
)
Personals(Child Table):
const Sequelize = require('sequelize')
const db = require("../database/db.js")
module.exports = db.sequelize.define(
'profile_personals',
{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
biography: {
type: Sequelize.STRING
}
},
{
timestamps: false
}
)

Do it this way, I hope it's what you're looking for.
module.exports = db.sequelize.define(
'profile_personals',
{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
biography: {
type: Sequelize.STRING
},
// It is possible to create foreign keys:
user_id: {
type: Sequelize.INTEGER,
references: {
// This is a reference to another model
model: Users,
// This is the column name of the referenced model
key: 'user_id'
}
}
},
{
timestamps: false
}
);

Related

hasMany() associations can not be define in Squelize.js?

This is the teacher Table's Schema
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = require('../util/databaseConnection');
const Teacher = sequelize.define("teacher", {
teacherid: {
type: DataTypes.STRING,
allowNull: false,
primaryKey: true
},
surname: {
type: DataTypes.STRING,
allowNull: true
},
firstname: {
type: DataTypes.STRING,
allowNull: true
},
lastname: {
type: DataTypes.STRING,
allowNull: true
}
})
module.exports = Teacher;
This is the subject Model's Schema
const { Sequelize, DataTypes } = require("sequelize");
const sequelize = require('../util/databaseConnection');
const Subject = sequelize.define('subject', {
subjectid: {
type: DataTypes.INTEGER,
AutoIncrement: true,
primaryKey: true
},
subjectname: {
type: DataTypes.STRING
},
grade: {
type: DataTypes.STRING
},
subjectinfo: {
type: DataTypes.STRING
}
})
module.exports = Subject;
I need to define the association between teacher hasMany subject
Teacher.hasMany(Subject)
But following error
Naming collision between attribute 'subjects' and association
'subjects' on model teacher. To remedy this, change either foreignKey
or as in your association definition
You have to add Following keys
Teacher.hasMany(Subject, { foreignKey: 'teacher_id', targetKey: 'id' });
and in Subject model add following column
teacher_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'teacher',
key: 'id'
}
},

Sequelize - ORM - Associations not working

Using Sequelize with MySQL. I have three models. Consultant, FamilyMember and Appointments. Appointment refers to Consultant and FamilyMember.
I have defined the foreign keys in the Appointment model. When the DB is created - the foreign keys are visible - when I check through a MySQL client, on the appointment table. The table names are freeze - so there isn't any chance of pluralization of the table names.
Consultant Model:
module.exports = (sequelize, DataTypes) => {
const consultant = sequelize.define('consultant', {
ID: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false
},
FirstName: {
type: DataTypes.STRING,
allowNull: false
},
LastName: {
type: DataTypes.STRING,
allowNull: false
}
{
freezeTableName: true
}
);
return consultant;
};
Appointment Model:
module.exports = (sequelize, DataTypes) => {
const appointment = sequelize.define('appointment', {
// attributes
ID: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false
},
ConsultantID: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'consultant',
key: 'ID'
}
},
FamilyMemberID: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'familymember',
key: 'ID'
}
}
},
{
freezeTableName: true
}
);
appointment.associate = function (models) {
models.appointment.belongsTo(models.consultant, {
foreignKey: 'ConsultantID',
as: 'consultant',
});
models.appointment.belongsTo(models.familymember, {
foreignKey: 'FamilyMemberID',
as: 'familymember',
});
};
return appointment;
};
Family Member model:
module.exports = (sequelize, DataTypes) => {
const familymember = sequelize.define('familymember', {
// attributes
ID: {
primaryKey: true,
type: DataTypes.UUID,
allowNull: false
},
FamilyID: {
type: DataTypes.UUID,
allowNull: false
},
FirstName: {
type: DataTypes.STRING,
allowNull: false
},
LastName: {
type: DataTypes.STRING,
allowNull: false
}
},
{
freezeTableName: true
}
);
return familymember;
};
Then in the code I try to fetch appointment and get the related familymember and consultant like this
var appointments = await Appointment.findAll({
where: {
AppointmentDateConfirmed: {
$gte: moment().subtract(0, 'days').toDate()
}
}, include:[Consultant, FamilyMember]
}
)
However I get an error
UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: consultant is not associated to appointment!
I suppose you should register your associations after models registration like I pointed in this answer

How to populate table with foreign key values, using sequelize?

I have models: Business, Contributor, Feedback.
I have created relationship between Feedback and Contributor, and Feedback and Business like this:
Feedback.belongsTo(Business)
Feedback.belongsTo(Contributor)
The corresponding foreign key attributes are added to the table Feedback. Question is, how to populate them with IDs coming from Business and Contributor table records?
This approach only gets the first record. If I use findAll(), then I get undefined.
for (let assetsUrl of assetUrls) {
...
var businesses = null;
var reviews = null;
...
var timestamp = Math.floor(Date.now() / 1000);
var b_id = await Business.findOne({
attributes: ["id"],
})
var c_id = await Contributor.findOne({
})
businesses = await Business.upsert({
...
last_scraped: timestamp
});
reviews = await Review.upsert(
{
contributor_id: c_id.id,
business_id: b_id.id,
last_scraped: timestamp,
},
)
}
Business model:
class Business extends Model {}
Business.init(
{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
site: {
type: Sequelize.STRING,
},
name: {
type: Sequelize.STRING,
},
business_type: {
type: Sequelize.STRING,
unique: false,
defaultValue: "",
},
address: {
type: Sequelize.TEXT,
// allowNull defaults to true
},
price: {
type: Sequelize.STRING,
},
url: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
},
last_scraped: {
type: Sequelize.INTEGER,
defaultValue: Math.floor(Date.now() / 1000)
},
},
{
sequelize,
modelName: "business",
timestamps: true,
createdAt: false,
updatedAt: false,
underscored: true
}
);
Business === sequelize.models.Business;
Business.sync();
Contributor model:
class Contributor extends Model {}
Contributor.init(
{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
site: {
type: Sequelize.STRING,
},
name: {
type: Sequelize.STRING,
unique: false,
},
location: {
type: Sequelize.STRING,
unique: false,
},
photo: {
type: Sequelize.STRING,
unique: false,
},
url: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
},
status: {
type: Sequelize.SMALLINT,
},
last_scraped: {
type: Sequelize.INTEGER,
defaultValue: Math.floor(Date.now() / 1000)
},
},
{
sequelize,
modelName: "contributor",
timestamps: true,
createdAt: false,
updatedAt: false,
underscored: true,
}
);
Contributor === sequelize.models.Contributor;
Contributor.sync();
Feedback model:
class Feedback extends Model {}
Feedback.init(
{
contributor_id: {
type: Sequelize.INTEGER,
},
business_id: {
type: Sequelize.INTEGER,
},
date: {
type: Sequelize.STRING,
unique: false,
},
rating: {
type: Sequelize.STRING,
unique: false,
},
content: {
type: Sequelize.STRING,
unique: false,
},
last_scraped: {
type: Sequelize.INTEGER,
defaultValue: Math.floor(Date.now() / 1000)
},
},
{
sequelize,
modelName: "feedback",
timestamps: true,
createdAt: false,
updatedAt: false,
underscored: true,
}
);
Feedback.belongsTo(Contributor, { foreignKey: 'contributor_id' })
Feedback.belongsTo(Business, { foreignKey: 'business_id'})
Feedback=== sequelize.models.Review;
Feedback.sync();
A Good use case for model streaming but I think sequelize doesn't
support it yet
With your approch, using findOne combined with offset option you can
create/update the Feedback model like this.
// Get number of records to avoid unnecessary findOne in the loop
const bRecordCount = await Business.count();
const cRecordCount = await Contributor.count();
for (let i = 0; i < assetUrls.length; i++) {
const assetsUrl = assetUrls[i];
// ...
let bRecord = null;
let cRecord = null;
let options = {
attributes: ["id"],
// order by id to be sure we get different record each time
order: [['id', 'ASC']],
raw: true,
offset: i //skip already taken records
};
try {
if (i < bRecordCount && i < cRecordCount) {
bRecord = await Business.findOne(options)
cRecord = await Contributor.findOne(options)
}
if (bRecord && cRecord) {
feedback = await Feedback.upsert({
contributor_id: cRecord.id,
business_id: bRecord.id,
last_scraped: timestamp,
//...
});
}
} catch (err) {
console.log(err);
}
}
If you have many records you should consider using
findAll()
with offset and limit options,
then do a bulkCreate()
with updateOnDuplicate option to avoid making many database queries
To get Feedback items with certain attributes call findAll:
var feedback = await Feedback.findAll({
attributes: ['contributor_id', 'business_id', 'last_scraped']
})

Problem coding a weak entity in sequelize

I am creating a cinema application. I have modeled the database on mySql but I am having trouble migrating it to Sequelize. I have followed the documentation but I am getting a lot of different errors.
I have tried using associations and indexes (as it should be). This is the model I am trying to make.
OCCUPIED_SEATS is composed of only two foreign keys and both make a unique index.
OCCUPIED_SEATS:
const SEATS = require("./Seats");
const SCREENING = require("./Screening");
const OCCUPIED_SEATS = sequelize.define("OCCUPIED_SEATS", {
//SEATS_ID
//SCREENING_ID
},
{
indexes: [
{
unique: true,
fields: [SEAT_ID, SCREENING_ID]
}
],
underscored: true
}
);
module.exports = OCCUPIED_SEATS;
SEATS:
const OCCUPIED_SEATS = require("./Occupied_Seats");
const SEATS = sequelize.define("SEATS", {
SEATS_ID: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true
},
ROW: {
type: Sequelize.STRING,
allowNull: false,
},
COLUMN: {
type: Sequelize.INTEGER,
allowNull: false
},
},
{
underscored: true
}
);
SEATS.hasMany(OCCUPIED_SEATS, {foreignKey: 'SEAT_ID'})
module.exports = SEATS;
SCREENING:
const OCCUPIED_SEATS = require("./Occupied_Seats");
const SCREENING = sequelize.define("SCREENING", {
SCREENING_ID: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true
},
SCREENING_START_TIME: {
type: Sequelize.TIME,
allowNull: false,
},
DATE: {
type: Sequelize.DATE,
allowNull: false
}
},
{
underscored: true,
indexes: [
{
unique: true,
fields: [ROOM_ID, SCREENING_START_TIME, DATE]
}
]
}
);
SCREENING.hasMany(OCCUPIED_SEATS, {foreignKey: 'SCREENING_ID'});
module.exports = SCREENING;
The error I am getting when I try this is:
[💻] Error: SEATS.hasMany called with something that's not a subclass of Sequelize.Model
How should I code the model?
Looks like in the new version of Sequelize you have to define your models through Sequelize.Model type:
class Seats extends Sequelize.Model {}
Seats.init({
id: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true
},
row: {
type: Sequelize.STRING,
allowNull: false,
},
...
});
module.exports = Seats;
And then somewhere else:
Seats.hasMany(OccupiedSeatc, {foreignKey: 'SEAT_ID'})
See model definition docs and accociation docs.

Node.js Sequelize virtual column pulling value from other model

I'm working with Sequelize 5.7, trying to utilize virtual datatype,
to pull related information into a model.
Given simplified company and user models, how do I get company.name
into user.companyname ?
company
let Schema = sequelize.define(
"company",
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING(45)
}
}
);
user
let Schema = sequelize.define(
"user",
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company: {
type: DataTypes.INTEGER.UNSIGNED,
references: {
model: sequelize.model('company'),
key: 'id'
}
},
/* This companyname contruct is pure fantasy, and the target of my question */
companyname: {
type: new DataTypes.VIRTUAL(DataTypes.STRING,['company']),
references: {
model: 'company',
key: 'name'
}
}
}
);
In your case, I think it is a better idea to use a relationship (an association)
Sequelize Associations
const User = sequelize.define('user', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company_id: {
type: DataTypes.INTEGER.UNSIGNED,
},
});
const Company = sequelize.define('company', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
},
});
User.belongsTo(Company, {
foreignKey: 'company_id', // you can use this to customize the fk, default would be like companyId
});
Company.hasMany(User);
Then when calling your model you do something like:
User.findAll({ include: Company }).then(users => console.log(users));
I solved the problem by using type: DataTypes.VIRTUAL in model
const { Model, DataTypes } = require('sequelize');
class User extends Model {
static init(sequelize) {
super.init({
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company_id: {
type: DataTypes.INTEGER.UNSIGNED,
},
companyname:{
type: DataTypes.VIRTUAL,
get() {
return this.Company?.get().name;
},
set(/*value*/) {
throw new Error('Do not try to set the `companyname` value!');
}
},
}, {
sequelize
})
}
static associate(models) {
this.belongsTo(Company, {
foreignKey: 'company_id',
});
}
}
module.exports = User;
to search just include the association :
User.findAll({ include: Company })
I usually create each model using 'class' in different files, but if you need, just include the code below in the #jalex19 solution
companyname:{
type: DataTypes.VIRTUAL,
get() {
return this.Company?.get().name;
},
set(/*value*/) {
throw new Error('Do not try to set the `fullName` value!');
}
},