Inserting data in multiple tables using Sequelize - javascript

It's my first time using Sequelize with MySQL and would like to understand how to insert data into two tables with a foreign key dependency.
Let's say, I have two tables - bookingDescription and bookingSummary. The entities for the same are as follows
//bookingSummary
module.exports = (sequelize, DataTypes) => {
return sequelize.define('bookingSummary', {
headerId: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true,},
titleId: DataTypes.STRING,
abNumber: DataTypes.INTEGER,
userProfileId: DataTypes.INTEGER,
theatreId: DataTypes.STRING,
mFId: DataTypes.STRING,
createdBy: { type: DataTypes.TEXT, allowNull: false },
modifiedBy: { type: DataTypes.TEXT, allowNull: false },
status: DataTypes.STRING
}, {
tableName: 'booking_summary',
underscored: true
})
}
//bookingDescription
module.exports = (sequelize, DataTypes) => {
return sequelize.define('bookingWeek', {
lineId: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true,},
headerId: DataTypes.STRING,
titleId: DataTypes.STRING,
abNumber: DataTypes.INTEGER,
theatreId: DataTypes.STRING,
mFId: DataTypes.STRING,
theatreName: DataTypes.STRING,
city: DataTypes.STRING,
state: DataTypes.STRING,
playStartDate: DataTypes.DATE,
playEndDate: DataTypes.DATE,
preferredFormat: DataTypes.INTEGER,
screensInDay: DataTypes.INTEGER,
featureTypeFlag: DataTypes.TEXT,
cofeatureName: DataTypes.STRING,
exhbtrReqComment: DataTypes.STRING,
createdBy: { type: DataTypes.TEXT, allowNull: false },
modifiedBy: { type: DataTypes.TEXT, allowNull: false },
status: DataTypes.STRING
}, {
tableName: 'booking_description',
underscored: true
})
}
Foreign key references in bookingSummary are as follows
FOREIGN KEY (headerId) REFERENCES bookingSummary(headerId)
FOREIGN KEY (titleId, abNumber, mFId)
REFERENCES bookingSummary(abNumber)
I have an object of data which needs to be inserted into the tables at an instant.
Any idea on how to approach this ?

So, i would recommend you first learning about SQL relations, regardless of Sequelize, and your current project structure, because it seems to me that you still lack the basic understanding of the logic behind these associations, where they should be used and how.
Both your tables have duplicate fields, which makes no sense. Take a look here, for example: https://code.tutsplus.com/articles/sql-for-beginners-part-3-database-relationships--net-8561
As for your current code, i played with it a bit, and this is what i did(will work only if you're using model.sync(), because a column needs to be created automatically. Also use force:true if you already have the tables):
module.exports = (sequelize, DataTypes) => {
const bookingHeader = sequelize.define('bookingHeader', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true},
abNumber: DataTypes.INTEGER,
userProfileId: DataTypes.INTEGER,
theatreId: DataTypes.STRING,
mFId: DataTypes.STRING,
createdBy: { type: DataTypes.TEXT, allowNull: true },
modifiedBy: { type: DataTypes.TEXT, allowNull: true },
status: DataTypes.STRING
}, {
tableName: 'booking_header',
// underscored: true
})
bookingHeader.associate = function (models) {
bookingHeader.hasOne(models.bookingDescription);
};
return bookingHeader;
}
Booking description:
module.exports = (sequelize, DataTypes) => {
const bookingDescription = sequelize.define('bookingDescription', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, },
abNumber: DataTypes.INTEGER,
theatreId: DataTypes.STRING,
mFId: DataTypes.STRING,
theatreName: DataTypes.STRING,
city: DataTypes.STRING,
state: DataTypes.STRING,
playStartDate: DataTypes.DATE,
playEndDate: DataTypes.DATE,
preferredFormat: DataTypes.INTEGER,
screensInDay: DataTypes.INTEGER,
featureTypeFlag: DataTypes.TEXT,
cofeatureName: DataTypes.STRING,
exhbtrReqComment: DataTypes.STRING,
createdBy: { type: DataTypes.TEXT, allowNull: false },
modifiedBy: { type: DataTypes.TEXT, allowNull: false },
status: DataTypes.STRING
}, {
tableName: 'booking_description',
// underscored: true
})
bookingDescription.associate = function (models) {
bookingDescription.belongsTo(models.bookingHeader);
};
return bookingDescription;
}
In your route, you can do something like this:
const {bookingHeader,bookingDescription} = models;
app.post("/booking", async (req, res, next) => {
try {
const header = await bookingHeader.create(req.body)
const headerId = header.id
await bookingDescription.create({state:'active',createdBy:'somebody',modifiedBy:'somebody',bookingHeaderId:headerId})
res.json(header);
} catch (error) {
console.log(error)
res.status(500)
}
});
Notice that i hardcoded some of the fields for the description, just for example purposes. Also, it's possible that there is a "better" way to do this with Sequelize, but the docs are really poor, so this gets the job done.

Related

foreignKey seems not working in a belongsTo clause

PROBLEM
I'm using sequelize to make an auto-generated query with a JOIN and I get that :
SELECT [...] FROM `weapon` AS `weapon` LEFT OUTER JOIN `stat` AS `mainStat` ON `weapon`.`ID` = `mainStat`.`ID` WHERE `weapon`.`type` = 'polearm';
However, the ON clause is incorrect, in fact, I want that :
[...] ON `weapon`.`mainStatID` = `mainStat`.`ID` [...]
Here is the associations I declared :
Weapon.hasOne( Stat, { foreignKey: 'mainStatID', as: 'mainStat' });
Stat.belongsTo( Weapon );
Stat.belongsTo( Weapon ); Just don't change anything.
Maybe I didn't understand something with .hasOne() and .belongsTo() concept ?
MODELS
Here is the two concerned Models :
const Weapon = sequelize.define('weapon', {
ID : { type: DataTypes.INTEGER, allowNull: false, autoIncrement: true, primaryKey: true },
name : { type: DataTypes.STRING, allowNull: false },
shortName : { type: DataTypes.STRING, allowNull: false },
type : { type: DataTypes.STRING, allowNull: false },
rarity : { type: DataTypes.INTEGER, allowNull: false },
baseAtk : { type: DataTypes.INTEGER, allowNull: false },
mainStatID : { type: DataTypes.INTEGER, allowNull: false },
description : { type: DataTypes.STRING, allowNull: false },
maxStack : { type: DataTypes.BOOLEAN, allowNull: false },
optionalEffect: { type: DataTypes.STRING, allowNull: true }
},
{
freezeTableName: true,
timestamps: false
})
const Stat = sequelize.define('stat', {
ID : { type: DataTypes.INTEGER, allowNull: false, autoIncrement: true, primaryKey: true },
displayName: { type: DataTypes.STRING, allowNull: false },
shortName : { type: DataTypes.STRING, allowNull: false },
value : { type: DataTypes.FLOAT, allowNull: false, get() {return parseFloat(this.getDataValue('value'))} }
},
{
freezeTableName: true,
timestamps: false
})
*Using mysql and sequelize 6.25.4
First of all, you should remove the explicit field definition for the foreign key:
mainStatID: { type: DataTypes.INTEGER, allowNull: false },
Secondly, if you would like a foreign-key field of MainStatID in the Weapon table then the relationship should be:
Weapon.belongsTo(Stat, { as: 'MainStat' });

How create (optimize) service on Backend (ExpressJS) with sequelize

Tried to create API for internet store using ExpressJS and sequelize. I have users, basket and devices. To connect basket and choosen by user devices used middle table BasketDevice.
Models:
export const Models = {
User: sequelize.define('user',
{
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
email: { type: DataTypes.STRING, unique: true },
password: { type: DataTypes.STRING },
role: { type: DataTypes.STRING, defaultValue: 'USER' },
isActivated: { type: DataTypes.BOOLEAN, defaultValue: false},
activationLink: { type: DataTypes.STRING, unique: true }
}
),
Basket: sequelize.define('basket',
{
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
}
),
BasketDevice: sequelize.define('basketDevice',
{
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
}
),
Device: sequelize.define('device',
{
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
name: { type: DataTypes.STRING, allowNull: false, unique: true },
price: { type: DataTypes.INTEGER, allowNull: false },
img: { type: DataTypes.STRING, allowNull: false },
rating: { type: DataTypes.INTEGER, defaultValue: 0 },
}
}
Assotiations between tables:
Models.User.hasOne(Models.Basket)
Models.Basket.belongsTo(Models.User)
Models.Basket.hasMany(Models.BasketDevice, {as: 'devices'})
Models.BasketDevice.belongsTo(Models.Basket)
Models.Device.hasMany(Models.BasketDevice)
Models.BasketDevice.belongsTo(Models.Device)
Tryed to give in response basket include basket device
Basket service:
class BasketService {
async getBasket(token: string) {
const userData = await TokenService.verifyRefreshToken(token) as any
const basket = await Models.Basket.findOne({
where: { userId: userData.id },
include: [{model: Models.BasketDevice, as: 'devices'}]
})
return basket
}
}
Don't know how create getBasket function that gives added to cart devices and counting of one device
What is the opltimal way to give devices added in basket?

sequilize Referencing column 'partner_id' and referenced column 'id' in foreign key constraint 'partnerserviceareas_ibfk_1' are incompatible

This is my partner model
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = require('../connection');
const PartnerInfo = sequelize.define(
'partnerinfo',
{
id: {
type: DataTypes.UUID,
allowNull: false,
defaultValue: Sequelize.UUIDV4,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
phone: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
loginSecret: {
type: DataTypes.STRING,
allowNull: true,
},
gender: {
type: DataTypes.INTEGER,
defaultValue: 0, // 0:Female 1:male
},
dob: {
type: DataTypes.STRING,
allowNull: true,
},
image: {
type: DataTypes.STRING,
allowNull: true,
},
type: {
type: DataTypes.INTEGER,
defaultValue: 0, // 0:Value 1:Elite
},
joiningDate: {
type: DataTypes.STRING,
allowNull: false,
},
termination_date: {
type: DataTypes.STRING,
allowNull: true,
},
line1: {
type: DataTypes.STRING,
allowNull: true,
},
line2: {
type: DataTypes.STRING,
allowNull: true,
},
landmark: {
type: DataTypes.STRING,
allowNull: true,
},
city: {
type: DataTypes.STRING,
allowNull: true,
},
state: {
type: DataTypes.STRING,
allowNull: true,
},
country: {
type: DataTypes.STRING,
allowNull: true,
},
pincode: {
type: DataTypes.STRING,
allowNull: true,
},
},
{
timestamps: true,
}
);
module.exports = PartnerInfo;
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = require('../connection');
const PartnerInfo = require('./partnerinfo');
const ServiceArea = require('./servicearea');
const PartnerServiceArea = sequelize.define('partnerservicearea', {
id: {
type: DataTypes.UUID,
allowNull: false,
defaultValue: Sequelize.UUIDV4,
primaryKey: true,
},
partner_id: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'partnerinfos',
key: 'id',
},
},
servicearea_id: {
type: DataTypes.CHAR,
allowNull: false,
},
});
PartnerServiceArea.belongsTo(PartnerInfo, {
foreignKey: {
name: 'partner_id',
allowNull: false,
},
targetKey: 'id',
});
PartnerInfo.hasMany(PartnerServiceArea, {
foreignKey: {
name: 'partner_id',
allowNull: false,
},
targetKey: 'id',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});
PartnerServiceArea.belongsTo(ServiceArea, {
foreignKey: {
name: 'servicearea_id',
allowNull: false,
},
targetKey: 'id',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});
ServiceArea.hasMany(PartnerServiceArea, {
foreignKey: {
name: 'servicearea_id',
allowNull: false,
},
targetKey: 'id',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});
module.exports = PartnerServiceArea;
These are the two models I am trying to associate and also using default sync.
I need help with the linking and want to use complex query
This is the SQL query
CREATE TABLE IF NOT EXISTS `partnerserviceareas`
(
`id` CHAR(36) BINARY NOT NULL,
`partner_id` CHAR(36) BINARY NOT NULL,
`servicearea_id` CHAR(255) NOT NULL,
`createdAt` DATETIME NOT NULL,
`updatedAt` DATETIME NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`partner_id`) REFERENCES `partnerinfos` (`id`)
ON DELETE NO ACTION ON UPDATE CASCADE,
FOREIGN KEY (`servicearea_id`) REFERENCES `service_areas` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
and the error is
Referencing column 'partner_id' and referenced column 'id' in foreign key constraint 'partnerserviceareas_ibfk_1' are incompatible
Please check "charter set" and "collation" on the both related fields, if data type is "string/char" type.
There is no such problem ("foreign key constraint 'xxx' are incompatible") on integer data type (or at least I have not met such incompatibles).
Sometimes created table has different "charter set/collation" from foreign tables (foreign table created by others, restored from old dump etc).
If create new table (charter/collation to be same as foreign table):
CREATE TABLE IF NOT EXISTS `partnerserviceareas` (
...
)
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
If you have already both tables and would like to change a column:
ALTER TABLE `partnerserviceareas`
CHANGE COLUMN `partner_id` `partner_id` CHAR(36)
CHARACTER SET 'utf8mb4'
COLLATE 'utf8mb4_unicode_ci' NOT NULL ;

EagerLoadingError [SequelizeEagerLoadingError]: grl_entidade is not associated to stn_matriz_gerada

I have this error and can`t find a way arround it: EagerLoadingError [SequelizeEagerLoadingError]: grl_entidade is not associated to stn_matriz_gerada!
I have tryed many things, currently this is the way my app is:
stn_matriz_gerada.js
const Sequelize = require('sequelize');
module.exports = function(sequelize, DataTypes) {
return sequelize.define('stn_matriz_gerada', {
conta: {
type: DataTypes.STRING,
allowNull: true,
primaryKey: true
},
v1: {
type: DataTypes.STRING,
allowNull: true
},
t1: {
type: DataTypes.STRING,
allowNull: true
},
v2: {
type: DataTypes.STRING,
allowNull: true
},
t2: {
type: DataTypes.STRING,
allowNull: true
},
v3: {
type: DataTypes.STRING,
allowNull: true
},
t3: {
type: DataTypes.STRING,
allowNull: true
},
v4: {
type: DataTypes.STRING,
allowNull: true
},
t4: {
type: DataTypes.STRING,
allowNull: true
},
v5: {
type: DataTypes.STRING,
allowNull: true
},
t5: {
type: DataTypes.STRING,
allowNull: true
},
v6: {
type: DataTypes.STRING,
allowNull: true
},
t6: {
type: DataTypes.STRING,
allowNull: true
},
v7: {
type: DataTypes.STRING,
allowNull: true
},
t7: {
type: DataTypes.STRING,
allowNull: true
},
valor: {
type: DataTypes.DOUBLE,
allowNull: true
},
tipo: {
type: DataTypes.STRING,
allowNull: true
},
tipo_int: {
type: DataTypes.INTEGER,
allowNull: true
},
natureza_valor: {
type: DataTypes.STRING,
allowNull: true
},
exercicio: {
type: DataTypes.INTEGER,
allowNull: true
},
mes: {
type: DataTypes.INTEGER,
allowNull: true
},
grl_entidade: {
type: DataTypes.INTEGER,
allowNull: true,
references: {
model: 'grl_entidade',
key: 'id'
}
},
conteudo_txt: {
type: DataTypes.TEXT,
allowNull: true
}
}, {
sequelize,
tableName: 'stn_matriz_gerada',
schema: 'public',
timestamps: false
});
};
init-models.js
var DataTypes = require("sequelize").DataTypes;
var _grl_entidade = require("./grl_entidade");
var _grl_entidade_tipo = require("./grl_entidade_tipo");
var _grl_municipio = require("./grl_municipio");
var _grl_uf = require("./grl_uf");
var _stn_matriz_gerada = require("./stn_matriz_gerada");
function initModels(sequelize) {
var grl_entidade = _grl_entidade(sequelize, DataTypes);
var grl_entidade_tipo = _grl_entidade_tipo(sequelize, DataTypes);
var grl_municipio = _grl_municipio(sequelize, DataTypes);
var grl_uf = _grl_uf(sequelize, DataTypes);
var stn_matriz_gerada = _stn_matriz_gerada(sequelize, DataTypes);
grl_entidade_tipo.hasMany(grl_entidade,
{ foreignKey: { name: "grl_entidade_tipo"},
as: "grl_entidade_tipo_fk"},);
grl_entidade.belongsTo(grl_entidade_tipo,
{ foreignKey: { name: "grl_entidade_tipo"},
as: "grl_entidade_tipo_fk"},);
grl_municipio.hasMany(grl_entidade,
{ foreignKey: { name: "grl_municipio"},
as: "grl_municipio_fk"},);
grl_entidade.belongsTo(grl_municipio,
{ foreignKey: { name: "grl_municipio"},
as: "grl_municipio_fk"},);
grl_uf.hasMany(grl_municipio,
{ foreignKey: { name: "grl_uf"},
as: "grl_uf_fk"},);
grl_municipio.belongsTo(grl_uf,
{ foreignKey: { name: "grl_uf"},
as: "grl_uf_fk"},);
grl_entidade.hasMany(stn_matriz_gerada,
{ foreignKey: { name: "grl_entidade"},
as: "grl_entidade_fk"},);
stn_matriz_gerada.belongsTo(grl_entidade,
{ foreignKey: { name: "grl_entidade"},
as: "grl_entidade_fk"},);
return {
grl_entidade,
grl_entidade_tipo,
grl_municipio,
grl_uf,
stn_matriz_gerada,
};
}
module.exports = initModels;
module.exports.initModels = initModels;
module.exports.default = initModels;
MscService.js
class MscService {
static async getAllMscs() {
try {
return await database.stn_matriz_gerada.findAll();
} catch (error) {
throw error;
}
}
static async getAMsc(conta) {
try {
const theMsc = await database.stn_matriz_gerada.findAll({
where: { conta: Number(conta) },
include: [ {model: database.grl_entidade, as: 'grl_entidade_fk' }]
});
return theMsc;
} catch (error) {
console.log(error);
throw error;
}
}
}
export default MscService;
It has hasMany and belongsTo but stills give me the error of EagerLoadingError [SequelizeEagerLoadingError]: grl_entidade is not associated to stn_matriz_gerada!
Version: "sequelize": "^6.3.5",
Can anyone help me please?

How to generate migrations automatically from Sequelize models

I just started to program with node.js. I needed an ORM so I used Sequelize library. I wrote my User model as follows and I need to create a migration for it. Is there any way to create migrations automatically from the Sequelize models instead of writing them on my own?
I tried package sequelize-auto-migrations and run npx makemigration --name create_users but it returns error:
Unexpected token {
I'm using node v10.19.3
This is my Sequelize model:
const Model = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
getFullname() {
return [ this.firstname, this.lastname ].join(' ');
}
}
User.init({
firstName: { type: DataTypes.STRING, allowNull: false },
lastName: { type: DataTypes.STRING, allowNull: false },
email: { type: DataTypes.STRING, allowNull: false, unique: true },
national_number: { type: DataTypes.STRING, unique: true },
phone_number: { type: DataTypes.STRING, allowNull: false, unique: true },
username: { type: DataTypes.STRING, allowNull: false, unique: true },
join_date: { type: DataTypes.DATEONLY, defaultValue: sequelize.NOW },
last_login: { type: DataTypes.DATE },
password: { type: DataTypes.STRING, allowNull: false },
active: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true }
}, {
sequelize,
modelName: 'User',
});
return User;
};
You might want to try sequelize-cli instead. To run migrations you have to run this command npx sequelize-cli model:generate
This link on sequelize.com should help https://sequelize.org/master/manual/migrations.html

Categories