Sequelize Mysql - Unable to Insert model with one to many relationship - mysql

Design Overview: I've an application with Invoice creation and Inventory management features in it. Let's first understand the database design with 2 entities that we have as below:
Invoices
Items
Now, here I've a M:N relationship between these 2 entities because one invoice can contain multiple items and one item can be included in many such invoices.
So, I've created a 3rd table which we call joining table to associate these entities as shown in the image below,
Problem Statemet: I'm unable to insert model in the child table(invoice_items) using include attribute. Look at the code below to understand what's wrong happening here?
3 Model Classes as below:
1. Invoice:
Note: Providing with fewer attributes to keep it short.
module.exports = (sequelize, DataTypes) => {
const Invoice = sequelize.define('Invoice', {
invoiceId: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
invoiceNumber: {
type: DataTypes.INTEGER(6).UNSIGNED.ZEROFILL,
allowNull: false,
unique: true
},
invoiceTotal: {
type: DataTypes.DECIMAL(9,2),
allowNull: false,
defaultValue: 0.00
},
paymentTotal: {
type: DataTypes.DECIMAL(9,2),
allowNull: false,
defaultValue: 0.00
},
invoiceDate: {
type: DataTypes.DATEONLY,
defaultValue: DataTypes.NOW,
allowNull: false
}
}, {
underscored: true
});
Invoice.associate = function (model) {
Invoice.belongsTo(model.Customer, {
as: 'customer',
foreignKey: {
name: "cust_id",
allowNull: false
}
});
// association with 3rd table
Invoice.hasMany(model.InvoiceItem, {
as: 'invoice_item',
constraints: true,
onDelete: 'NO ACTION',
foreignKey: {
name: "invoice_id",
allowNull: false
}
});
};
return Invoice;
}
2. Item:
Note: Providing with fewer attributes to keep it short.
module.exports = (sequelize, DataTypes) => {
const Item = sequelize.define('Item', {
itemId: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
itemName: {
type: DataTypes.TEXT,
allowNull: false,
defaultValue: ''
},
// this is a opening stock
quantityInStock: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
defaultValue: 0,
},
unitPrice: {
type: DataTypes.DECIMAL(9,2),
allowNull: false,
defaultValue: 0.00
}
}, {
underscored: true
});
Item.associate = function (model) {
// association with 3rd table
Item.hasMany(model.InvoiceItem, {
as: 'invoice_item', // alias name of a model
constraints: true,
onDelete: 'NO ACTION',
foreignKey: {
name: "item_id",
allowNull: false
}
});
};
return Item;
}
3. Invoice_Item:
Note: Providing with fewer attributes to keep it short.
module.exports = (sequelize, DataTypes) => {
const InvoiceItem = sequelize.define('InvoiceItem', {
invoiceItemId: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
quantity: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
defaultValue: 0,
},
rate: {
type: DataTypes.DECIMAL(9,2),
allowNull: false,
defaultValue: 0.00
}
}, {
underscored: true
});
InvoiceItem.associate = function(model) {
InvoiceItem.belongsTo(model.Invoice, {
as: 'invoice',
foreignKey: {
name: "invoice_id",
allowNull: false
}
});
InvoiceItem.belongsTo(model.Item, {
as: 'item',
foreignKey: {
name: "item_id",
allowNull: false
}
});
}
return InvoiceItem;
}
Now, I'm using below code to create an invoice with the list of items in it. But, this is not inserting the child records in the joining table(invoice_items). What's wrong here in the code below?
invoice = await Invoice.create({
"invoiceNumber": req.body.invoiceNumber,
"invoiceDate": req.body.invoiceDate,
"invoiceTotal": req.body.invoiceTotal,
"paymentTotal": req.body.paymentTotal,
"cust_id": req.body.customer.custId,
invoice_items: [{
item_id: 1,
quantity: 2,
rate: 300
}]
}, {
include: [{
association: InvoiceItem,
as: 'invoice_item'
}]
});

After trying so many variations, I understand that there was a problem in the association of my model classes. And, below is the way of associating both Invoice and Item model classes for M:N(Many to Many) relationships. I can now update the join table(invoice_items) by inserting the record in it for each invoice we create in the system with the items in it.
Invoice.associate = function (model) {
// association in Invoice model class
Invoice.belongsToMany(model.Item, {
through: 'InvoiceItem',
constraints: true,
onDelete: 'NO ACTION',
foreignKey: {
name: "invoice_id", // foreign key column name in a table invoice_items table
allowNull: false
}
});
};
Item.associate = function (model) {
// association in Item model class
Item.belongsToMany(model.Invoice, {
through: 'InvoiceItem',
constraints: true,
onDelete: 'NO ACTION',
foreignKey: {
name: "item_id", // foreign key column name in a table invoice_items
allowNull: false
}
});
};
Create Invoice with Items in it:
Note: Passing itemId (1) as a parameter in the addItems() method. If you have multiple items in an invoice then you can add forEach loop here to iterate over each item and individually pass the itemId, quantity and rate for an item sold to the customer.
// first create the invoice
invoice = await Invoice.create(invoice);
// Next, add record in the join table
await invoice.addItems([1], {
through: {
quantity: item.quantity,
rate: item.rate
}
});
Database Tables with one Test Result:
1. Invoice Table:
2. Invoice_items Table(Join Table):

Related

Sequelize seems to ignore associations with natural keys and/or adds additional fields

I have 2 situations. The main thing that connects them is that the primary keys on the tables are not autoincrement integers, which seems to cause sequelize to try to create additional association or field names.
Situation 1, I have 2 tables, I have the associations defined. When I try to query it, a random extra field gets inserted, throwing an error.
Model 1 file
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessAccountSetting';
const tableName = 'BusinessAccountSettings';
class BusinessAccountSetting extends Model {
static doInit (sequelize) {
this.init({
_id: {
type: DataTypes.BIGINT.UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
BusinessAccountId: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false
},
BusinessSettingKey: {
type: DataTypes.STRING(200),
allowNull: false,
defaultValue: true
},
value: {
type: DataTypes.JSON,
allowNull: false
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsTo(models.BusinessAccount, {
as: 'business',
foreignKey: 'BusinessAccountId',
targetKey: '_id'
});
this.belongsTo(models.BusinessSetting, {
as: 'setting',
foreignKey: 'BusinessSettingKey',
targetKey: 'BusinessSettingKey'
});
};
};
module.exports = {
modelName,
model: BusinessAccountSetting
};
Model 2 file
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessSetting';
const tableName = 'BusinessSettings';
class BusinessSetting extends Model {
static doInit (sequelize) {
this.init({
BusinessSettingKey: {
type: DataTypes.STRING(200),
allowNull: false,
primaryKey: true,
unique: true
},
label: {
type: DataTypes.STRING(200),
allowNull: false
},
description: {
type: DataTypes.STRING(500),
allowNull: true
},
defaultValue: {
type: DataTypes.JSON,
allowNull: false
},
BusinessSettingGroupKey: {
type: DataTypes.STRING(200),
allowNull: false
},
order: {
type: DataTypes.SMALLINT.UNSIGNED,
allowNull: false
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsTo(models.BusinessSettingGroup, {
as: 'group',
foreignKey: 'BusinessSettingGroupKey',
targetKey: 'BusinessSettingGroupKey'
});
this.hasMany(models.BusinessAccountSetting, {
as: 'businessAccountSettings',
foreignKey: 'BusinessSettingKey',
sourceKey: 'BusinessSettingKey'
});
};
};
module.exports = {
modelName,
model: BusinessSetting
};
When I run this query
const settings = await sqldb.BusinessSetting.findAll({
include: [
{
model: sqldb.BusinessAccountSetting,
as: 'businessAccountSettings',
where: {
BusinessAccountId
},
required: false
}
]
});
It generates this sql
SELECT
`BusinessSetting`.`BusinessSettingKey`,
`BusinessSetting`.`label`,
`BusinessSetting`.`description`,
`BusinessSetting`.`defaultValue`,
`BusinessSetting`.`BusinessSettingGroupKey`,
`BusinessSetting`.`order`,
`BusinessSetting`.`createdAt`,
`BusinessSetting`.`updatedAt`,
`BusinessSetting`.`deletedAt`,
`businessAccountSettings`.`_id` AS `businessAccountSettings._id`,
`businessAccountSettings`.`BusinessAccountId` AS `businessAccountSettings.BusinessAccountId`,
`businessAccountSettings`.`BusinessSettingKey` AS `businessAccountSettings.BusinessSettingKey`,
`businessAccountSettings`.`value` AS `businessAccountSettings.value`,
`businessAccountSettings`.`createdAt` AS `businessAccountSettings.createdAt`,
`businessAccountSettings`.`updatedAt` AS `businessAccountSettings.updatedAt`,
`businessAccountSettings`.`deletedAt` AS `businessAccountSettings.deletedAt`,
`businessAccountSettings`.`BusinessSettingBusinessSettingKey` AS `businessAccountSettings.BusinessSettingBusinessSettingKey`
FROM
`BusinessSettings` AS `BusinessSetting` LEFT OUTER JOIN `BusinessAccountSettings` AS `businessAccountSettings` ON `BusinessSetting`.`BusinessSettingKey` = `businessAccountSettings`.`BusinessSettingKey`
AND (`businessAccountSettings`.`deletedAt` IS NULL AND `businessAccountSettings`.`BusinessAccountId` = 20)
WHERE (`BusinessSetting`.`deletedAt` IS NULL);
Which throws an error because of this:
`businessAccountSettings`.`BusinessSettingBusinessSettingKey` AS `businessAccountSettings.BusinessSettingBusinessSettingKey`
The associations are defined. The primary keys are defined. It should not be trying to add additional fields to fill in the blanks.
It's not an extra hook because it is trying to create a field for the reverse association which is already defined. It's not coming from another model association and I went through all of my files and remove the hooks: true flags just to be sure.
Problem #2, M:N associations with non-numeric keys
File #1
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessRoleTemplate';
const tableName = 'BusinessRoleTemplates';
class BusinessRoleTemplate extends Model {
static doInit (sequelize) {
this.init({
BusinessRoleTemplateKey: {
type: DataTypes.STRING(100),
primaryKey: true,
allowNull: false,
unique: true
},
description: {
type: DataTypes.STRING(250),
allowNull: true
},
group: {
type: DataTypes.STRING(50),
allowNull: true
},
isCategoryTemplate: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
ranking: {
type: DataTypes.TINYINT.UNSIGNED,
allowNull: false
},
active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsToMany(models.BusinessPermission, {
as: 'permissions',
through: models.BusinessRoleTemplatePermission
});
};
};
module.exports = {
modelName,
model: BusinessRoleTemplate
};
File 2
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessPermission';
const tableName = 'BusinessPermissions';
class BusinessPermission extends Model {
static doInit (sequelize) {
this.init({
BusinessPermissionKey: {
type: DataTypes.STRING(100),
allowNull: false,
primaryKey: true,
unique: true
},
plainText: {
type: DataTypes.STRING(100),
allowNull: false
},
description: {
type: DataTypes.STRING(250),
allowNull: true
},
requiresRank: {
type: DataTypes.INTEGER(2).UNSIGNED,
allowNull: false,
defaultValue: 10
},
BusinessPermissionGroupKey: {
type: DataTypes.STRING(100),
allowNull: false
},
isCategoryPermission: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsTo(models.BusinessPermissionGroup, {
as: 'group',
foreignKey: 'BusinessPermissionGroupKey',
targetKey: 'BusinessPermissionGroupKey'
});
this.hasMany(models.BusinessPermissionAlternative, {
as: 'alternates',
foreignKey: 'AlternateBusinessPermissionKey',
sourceKey: 'BusinessPermissionKey'
});
this.belongsToMany(models.BusinessRoleTemplate, {
as: 'roleTemplates',
through: models.BusinessRoleTemplatePermission
});
this.belongsToMany(models.BusinessRole, {
as: 'roles',
through: models.BusinessRolePermission
});
};
};
module.exports = {
modelName,
model: BusinessPermission
};
Association table
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessRoleTemplatePermission';
const tableName = 'BusinessRoleTemplatePermissions';
class BusinessRoleTemplatePermission extends Model {
static doInit (sequelize) {
this.init({
_id: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
BusinessPermissionKey: {
type: DataTypes.STRING(100),
allowNull: false
},
BusinessRoleTemplateKey: {
type: DataTypes.STRING(100),
allowNull: false
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: false
});
};
static associate (models) {
this.belongsTo(models.BusinessPermission, {
as: 'permission',
foreignKey: 'BusinessPermissionKey',
targetKey: 'BusinessPermissionKey'
});
this.belongsTo(models.BusinessRoleTemplate, {
as: 'role',
foreignKey: 'BusinessRoleTemplateKey',
targetKey: 'BusinessRoleTemplateKey'
});
};
};
module.exports = {
modelName,
model: BusinessRoleTemplatePermission
};
BusinessRoleTemplate hasMany BusinessPermissions through BusinessRoleTemplatePermissions
BusinessRoleTemplatePermissions has the associations for both tables defined, so there shouldn't be a need for anything else.
However, when I run this query:
role = await sqldb.BusinessRoleTemplate.findOne({
where: {
BusinessRoleTemplateKey: data.role
},
attributes: ['BusinessRoleTemplateKey', 'description', 'isCategoryTemplate', 'ranking'],
include: [
{
model: sqldb.BusinessPermission,
as: 'permissions',
attributes: ['BusinessPermissionKey', 'isCategoryPermission']
}
]
});
I get this SQL:
SELECT
`BusinessRoleTemplate`.`BusinessRoleTemplateKey`,
`BusinessRoleTemplate`.`description`,
`BusinessRoleTemplate`.`isCategoryTemplate`,
`BusinessRoleTemplate`.`ranking`,
`permissions`.`BusinessPermissionKey` AS `permissions.BusinessPermissionKey`,
`permissions`.`isCategoryPermission` AS `permissions.isCategoryPermission`,
`permissions->BusinessRoleTemplatePermission`.`_id` AS `permissions.BusinessRoleTemplatePermission._id`,
`permissions->BusinessRoleTemplatePermission`.`BusinessPermissionKey` AS `permissions.BusinessRoleTemplatePermission.BusinessPermissionKey`,
`permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateKey` AS `permissions.BusinessRoleTemplatePermission.BusinessRoleTemplateKey`,
`permissions->BusinessRoleTemplatePermission`.`createdAt` AS `permissions.BusinessRoleTemplatePermission.createdAt`,
`permissions->BusinessRoleTemplatePermission`.`updatedAt` AS `permissions.BusinessRoleTemplatePermission.updatedAt`,
`permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey` AS `permissions.BusinessRoleTemplatePermission.BusinessPermissionBusinessPermissionKey`,
`permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateBusinessRoleTemplateKey` AS `permissions.BusinessRoleTemplatePermission.BusinessRoleTemplateBusinessRoleTemplateKey`
FROM `BusinessRoleTemplates` AS `BusinessRoleTemplate`
LEFT OUTER JOIN (
`BusinessRoleTemplatePermissions` AS `permissions->BusinessRoleTemplatePermission`
INNER JOIN `BusinessPermissions` AS `permissions`
ON `permissions`.`BusinessPermissionKey` = `permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey`)
ON `BusinessRoleTemplate`.`BusinessRoleTemplateKey` = `permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateBusinessRoleTemplateKey`
AND (`permissions`.`deletedAt` IS NULL)
WHERE (`BusinessRoleTemplate`.`deletedAt` IS NULL AND `BusinessRoleTemplate`.`BusinessRoleTemplateKey` = 'Senior Manager');
With all sorts of stuff added:
added fields:
`permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey` AS `permissions.BusinessRoleTemplatePermission.BusinessPermissionBusinessPermissionKey`,
`permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateBusinessRoleTemplateKey` AS `permissions.BusinessRoleTemplatePermission.BusinessRoleTemplateBusinessRoleTemplateKey`
Added associations:
ON `permissions`.`BusinessPermissionKey` = `permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey`)
If I change the association in BusinessRoleTemplate to this, it works:
this.belongsToMany(models.BusinessPermission, {
as: 'permissions',
through: models.BusinessRoleTemplatePermission,
foreignKey: 'BusinessRoleTemplateKey',
otherKey: 'BusinessPermissionKey'
});
I shouldn't need to add the foreignKey and otherKey because the associations are already defined in the through table, but sequelize isn't recognizing them, it is trying to create them.

Sequelize M:N association not updating through table record

When I try to update a recipe with associated tags using the through option, no record is updated in the joining table in the mysql database I'm connected to.
Here are my models definitions:
export const Recipe = sequelize.define('Recipe', {
// Model attributes are defined here
title: {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.STRING,
allowNull: true
},
prepTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
cookTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
totalTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
servings: {
type: DataTypes.INTEGER,
allowNull: false
},
rating: {
type: DataTypes.INTEGER,
allowNull: false
},
notes: {
type: DataTypes.STRING, allowNull: true
},
}, {
// Other model options go here
tableName: 'Recipes'
});
export const Tag = sequelize.define('Tag', {
// Model attributes are defined here
name: {
type: DataTypes.STRING,
allowNull: false
},
}, {
// Other model options go here
tableName: 'Tags'
});
export const RecipeTag = sequelize.define('RecipeTag', {
// Model attributes are defined here
}, {
// Other model options go here
timestamps: false,
tableName: 'RecipeTags'
});
Here are my associations:
Recipe.belongsToMany(Tag, {
through: RecipeTag,
foreignKey: 'recipeId',
as: 'tags'
})
Tag.belongsToMany(Recipe, {
through: RecipeTag,
foreignKey: 'tagId',
as: 'recipes'
})
Here is the update call:
Recipe.update(args, {
include: [{
model: Tag,
through: RecipeTag,
as: 'tags',
where: {
recipeId: args.id
}
}],
where: {
id: args.id
},
});
Only one update mysql call is executed on the Recipes table. Is it possible to update the RecipeTags through table record in the same update call?

I created oneToMany relation but how I can get the single record belongs to the many record in Sequalize

Tagcategories Model
export const TagCategories = sequelize.define(
"tag_categories",
{
categoryId: {
type: DataTypes.INTEGER,
field: "category_id",
autoIncrement: true,
primaryKey: true,
},
title: {
type: DataTypes.STRING(50),
field: "title",
allowNull: false,
unique: true,
},
},
);
TagCategories.hasMany(TagGroups, {
foreignKey: "categoryId",
sourceKey: "categoryId",
});
export default TagCategories;
TagGroups Model
export const TagGroups = sequelize.define(
"tag_groups",
{
tagGroupId: {
type: DataTypes.INTEGER,
field: "tag_group_id",
autoIncrement: true,
primaryKey: true,
},
categoryId: {
type: DataTypes.INTEGER,
field: "category_id",
allowNull: false,
},
title: {
type: DataTypes.STRING(50),
field: "title",
allowNull: false,
unique: true,
},
},
);
In the above models I establish oneToMany relationship between the TagCategories and TagGroups
But I want to fetch the record from the TagGroup table with the TagCategories details.
Thanks in advance
Did you look at examples in official documentation?
Also, you need to add an association from TagGroups to TagCategories:
// there is no need to indicate `sourceKey` if this field is a primary key
TagGroups.belongsTo(TagCategories, {
foreignKey: "categoryId",
});
It's better to define all associations in static functions and call all of them separately after all models will be registered.
See the question and my answer here how to do it
In your case, the final request would be something like this
const tagGroup = await TagGroups.findOne({
where: {
tagGroupId: groupId
},
include: [{
model: TagCategories
}]
})

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

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.