assotiating two tables in sequelize - mysql

Im having problems associating 2 models. I will try to describe the problem as detailed as possible and hope you can help me.
I have 2 Models: Zone and PLZ (both are also tables in database-mysql).
There can be One Zone having many PLZs and one PLZ can belong to One zone.
On saving a zone with its PLZs I have a table called "zone_plz" with only two columns: zone_id and plz_id. Both have foreign keys to Zone.id and PLZ.id
Zone Model:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const PLZ = require('../models/PLZ');
const zone_plz = require('../models/relations/zone_plzs');
const Zone = sequelize.define('zone', {
name: {
type: Sequelize.STRING,
allowNull: false
},
color: {
type: Sequelize.STRING,
allowNull: false
}
}, {
timestamps: true
});
module.exports = Zone;
PLZ model:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const Zone = require('../models/Zone');
const zone_plz = require('../models/relations/zone_plzs');
const PLZ = sequelize.define('plz', {
plz: {
type: Sequelize.INTEGER,
allowNull: false
},
city: {
type: Sequelize.STRING,
allowNull: false
},
district: {
type: Sequelize.STRING
}
});
module.exports = PLZ;
and this is the zone_plz model:
const Sequelize = require('sequelize');
const sequelize = require('../../util/database');
const PLZ = require('../../models/PLZ');
const Zone = require('../../models/Zone');
const zone_plz = sequelize.define('zone_plz', {
zone_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: Zone,
key: 'id',
}
},
plz_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: PLZ,
key: 'id',
}
}
}, {
timestamps: true
});
module.exports = zone_plz;
and this is how I query it:
router.get('/', function (req, res, next) {
zone_plz.findAll({
include: [{
model: PLZ,
as: 'plz'
},
{
model: Zone,
as: 'zone'
}]
}).then((result) => {
res.send({status: true, data: result})
}).catch(function (err) {
next(err)
})
});
As you can see i want to return a zone with all the belonging plzs to the user.
Im new to sequelize and Im also not sure if this is the right approach. I get the error: plz is not associated to zone_plz!
Can anyone help me?

You created references, not associations. Please, first of all, read the differences: Sequelize model references vs associations
then create associations between plz & zone like:
plz.belongsToMany(zone, {through: 'zone_plz'});
zone.belongsToMany(plz, {through: 'zone_plz'});

Related

hasOne association in sequelize making multiple copies

So I am working on a project with Users, Products Carts, etc. And I am using sequelize to maintain a one-to-one relation between my User and the cart associated with it. I only want one Cart to be there for one User
User.hasOne(Cart);
Cart.belongsTo(Product);
sequelize.sync().then(
result=>{
return User.findByPk(1)
}
).then(user=>{
if(!user){
return User.create({
name: "Ary",
email: "test#test.com",
})
}
return user;
}).then(user=>{
console.log("here");
return user.createCart();
}).then(cart=>{
console.log("cartmain:");
console.log(cart);
app.listen(3000);
})
.catch(err => {console.log(err);})
I am currently working with only 1 default user, and by using the code above I am ensuring that the user is available and when it is confirmed I create a basket for that user using user.createCart() .
But whenever I run my code a new cart for that user gets created whereas I dont want that and dont expect that to happen as I am using one-to-one relation
Below are the models for my User and Cart:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const User = sequelize.define('user', {
id:{
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
email:{
type: Sequelize.STRING,
allowNull: false
}
})
module.exports = User;
const Sequelize = require('sequelize');
const sequelize = require("../util/database");
const Cart = sequelize.define('cart', {
id:{
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
}
})
module.exports = Cart
What can be done so that if a cart is not associated with a User it gets created if one is then it doesn't using sequelize

Sequelize in Nodejs creating duplicate tables upon app start

Ok. Landscape: Node, MySql, Sequelize
Issue: After creating a new data model & migration (node migrate.js which creates just fine), upon app start Sequelize creates a duplicate Table (and also forwards form data to the new table).
Ex: db.virtual_class is the main table, and upon start, db.virtual_classes is also created.
My model:
const Sequelize = require('sequelize');
const sequelize = require('../sequelize');
const model = sequelize.define('virtual_class', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
style: Sequelize.STRING, // e.g. Style of class
description: Sequelize.STRING(1024), // e.g. class Details
jwt_secret: Sequelize.STRING, // e.g. rando string to be used to gen unique keys for every room
});
module.exports = model;
I've isolated what I think is the issue - I'm including the model in a variable on my index controller for my functions.
const Virtual_class = require('./model');
const classQuery = require('./classQuery');
async function addClass({ style, description, secret }) {
const vClass = await Virtual_class.create({
style,
description,
jwt_secret: secret,
}, { raw: true });
return classQuery(vClass);
}
module.exports = {
addClass,
};
Class Query function to return the data in a usable object:
function classQuery(queryResult) {
if (!queryResult) {
return null;
}
return {
id: queryResult.id,
style: queryResult.style,
description: queryResult.description,
secret: queryResult.jwt_secret,
};
}
module.exports = classQuery;
and the migration:
module.exports = {
up: (sequelize, Sequelize) => sequelize.getQueryInterface().createTable('virtual_class', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
style: {
type: Sequelize.STRING,
},
description: {
type: Sequelize.STRING,
},
jwt_secret: {
type: Sequelize.STRING,
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.fn('now'),
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.fn('now'),
},
}),
down: sequelize => sequelize.getQueryInterface().dropTable('virtual_class'),
};
Net result is fine before I run app - DB shows new table, After running app - DB shows dup table.
I'm a relative noob, and been wracking my brain (and trying to find solutions here) to the problem. I've done this before with other migrations with no issue.
Any advice is appreciated! Thanks!
DOH! For those who are new like me - Sequelize automatically creates plural tables by default, You can force the override tp singular table names.

Sequelize Many To Many Relationship : Cannot read property 'split' of undefined

I'm trying to create many to many relationship using Sequelize + nodeJs using existing MySQL Database :
Below is my tables :
- "usr" Table : usr_id (PK)
- Intermediate "usr_role" : usr_id, role_id
- "role" table : role_id
This is my models
"User" Models:
"use strict";
var bcrypt = require('bcryptjs');
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
usrid : {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
field:'usr_id'
},
name :{
type: DataTypes.STRING,
allowNull: false,
field:'usr_name'
},
}, {
timestamps: false,
freezeTableName: true,
tableName: 'usr',
name:'User',
underscored:'true',
classMethods: {
associate:function(models){
User.belongsToMany(models.Role, { through: 'UserRole', foreignKey:'usr_id', as:'UserRoles'});
}
}
}
);
return User;
};
"Role" models
module.exports = function(sequelize, DataTypes) {
var Role = sequelize.define('Role', {
id : {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
field:'role_id'
},
name :{
type: DataTypes.STRING,
allowNull: false,
field:'role_name'
},
},{
timestamps: false,
freezeTableName: true,
tableName: 'role_ref',
underscored:'true',
classMethods: {
associate:function(models){
Role.belongsToMany(models.User, {
through: 'UserRole',
foreignKey:'role_id'});
}
}
}
)
return Role;
};
E:\nodejsWS\learn\node_modules\inflection\lib\inflection.js:795
var str_path = str.split( '::' );
^
TypeError: Cannot read property 'split' of undefined
at Object.inflector.underscore
(E:\nodejsWS\learn\node_modules\inflection\lib\inflection.js:795:25)
at Object.module.exports.underscoredIf
(E:\nodejsWS\learn\node_modules\sequelize\lib\utils.js:28:27)
at new BelongsToMany (E:\nodejsWS\learn\node_modules\sequelize
\lib\associations\belongs-to-many.js:134:15)
at Mixin.belongsToMany
(E:\nodejsWS\learn\node_modules\sequelize\lib\associations
\mixin.js:264:21)
at sequelize.define.classMethods.associate
(E:\nodejsWS\learn\models\Role.js:29:12)
at E:\nodejsWS\learn\models\index.js:50:21
this is my index.js
// Import models
fs
.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf(".") !== 0) && (file !== "index.js");
})
.forEach(function(file) {
var model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
//associate models
Object.keys(db).forEach(function(modelName) {
if ("associate" in db[modelName]) {
console.log(db);
db[modelName].associate(db);
}
});
Line 50 refer to db[modelName].associate(db), that cause the error.
Can somebody please guide me what's i'm doing wrong. Do i need to manually create intermediate Models 'UserRole'. Your help is very much appreciated. Thanks.
You need to specify the actual intermediate table's name in the belongsToMany config, or define the model UserRole. Also, unless your intermediate table has the fields, you'll probably also want to specify timestamps: false as well. So, for example:
Role.belongsToMany(models.User, {
through: 'usr_role',
foreignKey:'role_id',
timestamps: false
});
This will cause sequelize to use that table in the queries it builds without needing a model defined, and will prevent it from requesting the timestamp fields from either the User table or the intermediate.

Sequelize where with include

I am using sequelize as my backend ORM.
But I have a problem when I want "where" with a join table. The associations are good but I didn't know how to do for the "where".
This my code :
router.get('/id_presta_struct_unit/:id_presta_struct_unit', (req, res) => {
models.structures.findAll({
include: {
required: false,
model: models.structures_proposer_prestations,
where: {
id_presta_struct_unit: req.params.id_presta_struct_unit
},
include: {
model : models.unites_facturation,
}
}
}).then(data => {
res.writeHead(200, {'Content-Type': 'application/json; charset=utf-8'});
res.end(JSON.stringify(data));
});
});
I got this request
SELECT * FROM structures AS structures LEFT OUTER JOIN structures_proposer_prestations AS structures_proposer_prestations ON structures.id_structure = structures_proposer_prestations.id_structure AND structures_proposer_prestations.id_presta_struct_unit = '1' LEFT OUTER JOIN unites_facturation AS structures_proposer_prestations.unites_facturation ON structures_proposer_prestations.id_unite = structures_proposer_prestations.unites_facturation.id_unite;
But i would like to get
SELECT * FROM structures AS structures LEFT OUTER JOIN structures_proposer_prestations AS structures_proposer_prestations ON structures.id_structure = structures_proposer_prestations.id_structure LEFT OUTER JOIN unites_facturation AS structures_proposer_prestations.unites_facturation ON structures_proposer_prestations.id_unite = structures_proposer_prestations.unites_facturation.id_unite WHERE structures_proposer_prestations.id_presta_struct_unit = '1';
I don't know what to do I didn't find a post with the same problem
Can anyone point me in the right direction?
Thank you in advance.
Edit:
The associations
models.structures_employer_ressources.hasMany(models.ressources, { foreignKey: 'id_ressource' });
models.ressources.belongsTo(models.structures_employer_ressources, { foreignKey: 'id_ressource' });
The model of ressources
module.exports = function(sequelize, DataTypes) {
return sequelize.define('ressources', {
id_ressource: {
type: DataTypes.STRING,
allowNull: false,
primaryKey: true
}
........
},{
tableName: 'ressources',
updatedAt: 'date_modification',
createdAt: 'date_creation'
});
};
And the model of structures_employer_ressources
module.exports = function(sequelize, DataTypes) {
return sequelize.define('structures_employer_ressources', {
id_structure: {
type: DataTypes.STRING,
allowNull: false,
primaryKey: true,
references: {
model :'structures',
key: 'id_structure'
}
},
id_ressource: {
type: DataTypes.STRING,
allowNull: false,
primaryKey: true,
references: {
model :'ressources',
key: 'id_ressource'
}
}
},{
tableName: 'structures_employer_ressources',
updatedAt: 'date_modification',
createdAt: 'date_creation'
});
};
If you feed an array into the where clause of the initial join, you can run a raw query against the joins.
Example:
models.structures.findAll({
where:[["[structures_proposer_prestations].[id_presta_struct_unit] = " + req.params.id_presta_struct_unit, null]],
include: {
required: false,
model: models.structures_proposer_prestations,
where: {
id_presta_struct_unit: req.params.id_presta_struct_unit
},
include: {
model : models.unites_facturation,
}
}
}
The array can also take in standard object syntax and will be combined by an AND. The null I am passing in is for paramaters, so It can definitely be optimised to take in the id as a paramater, just don't know the syntax off hand.

Sequelize - Table Pluralization Error, No Instance within Table

I have run into a weird error where I receive a message for a pluralization version of my database table and it is being grouped into my sequel query. I scanned my models and routes and couldn't find any instance of a pluralization of my table name, and when I check the database tables the structures do not mention any pluralization. When I log the query, it looks like the pluralization error comes in at this section of the query
FROM images AS images LEFT OUTER JOIN descriptions AS description ON
Here is the full error message:
Unhandled rejection SequelizeDatabaseError: ER_NO_SUCH_TABLE: Table 'assistant.descriptions' doesn't exist
Here is my Images model:
module.exports = function(sequelize, DataTypes){
var Images = sequelize.define('images', {
pattern: DataTypes.STRING,
color: DataTypes.STRING,
imageUrl: DataTypes.STRING,
imageSource: DataTypes.STRING,
description_id: DataTypes.INTEGER
}, {
classMethods: {
associate: function(db) {
Images.belongsTo(db.Description, {foreignKey: 'description_id'});
}
}
});
return Images;
}
Here is my Description model:
module.exports = function(sequelize, DataTypes) {
var Description = sequelize.define('description', {
description_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
color: DataTypes.STRING,
body: DataTypes.STRING
});
return Description;
}
Here is how I associate the models in dbIndex:
var Sequelize = require('sequelize');
var sequelize = new Sequelize("assistant", "admin", "pwd", {
host: "host",
port: 3306,
dialect: 'mysql'
});
var db = {};
db.Description = sequelize.import(__dirname + "/descriptionModel");
db.Images = sequelize.import(__dirname + "/imagesModel");
db.Images.associate(db);
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
Here is my query:
router.get('/:pattern/:color/result', function(req, res, image){
console.log(req.params.color);
console.log(req.params.pattern);
db.Images.findAll({
where: {
pattern: req.params.pattern,
color: req.params.color
},
include: [db.Description],
attributes: ['id', 'pattern', 'color', 'imageUrl', 'imageSource', 'description_id']
}).then(function(image){
//console.log(doc.descriptions_id);
res.render('pages/suit-result.hbs', {
pattern : req.params.pattern,
color : req.params.color,
image : image
})
});
});
Here is the query before the error:
Executing (default): SELECT `images`.`id`, `images`.`pattern`, `images`.`color`, `images`.`imageUrl`, `images`.`imageSource`, `images`.`description_id`, `description`.`description_id` AS `description.description_id`, `description`.`color` AS `description.color`, `description`.`body` AS `description.body`, `description`.`createdAt` AS `description.createdAt`, `description`.`updatedAt` AS `description.updatedAt` FROM `images` AS `images` LEFT OUTER JOIN `descriptions` AS `description` ON `images`.`description_id` = `description`.`description_id` WHERE `images`.`pattern` = 'solid' AND `images`.`color` = 'navy-blue';
Seqeulize will pluralize your table names by default. To turn it off, include the option freezeTableName: true to all your model definition options that you don't want pluralized. For example, with the Description model:
var Description = sequelize.define('description', {
description_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
color: DataTypes.STRING,
body: DataTypes.STRING
}, {
freezeTableName: true
});