Sequelizejs is not associated to - node.js

I made some associate but it did not work, probably with me that something is wrong, ask for help.
There are two models
module.exports = function (sequelize, DataTypes) {
var pages_lang = require('./pages_lang')(sequelize, DataTypes);
return sequelize.define('pages', {
id: {
type: DataTypes.INTEGER(10),
allowNull: false,
primaryKey: true,
autoIncrement: true,
references : { model: "pages_lang", key: "page_id" }
},
name: {
type: DataTypes.STRING,
allowNull: false
},
published: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: '0'
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: '0000-00-00 00:00:00'
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: '0000-00-00 00:00:00'
}
}, {
classMethods: {
associate: function (models) {
this.hasMany(models.pages_lang, {onDelete: 'SET NULL', onUpdate: 'CASCADE', foreignKey: 'page_id', as: 'pages', through: models.pages_lang});
},
getAll() {
return this.findAll({include: [{model: pages_lang, as: 'pages_lang'}]}).then(function (result) {
return result;
});
}
}
});
};
module.exports = function (sequelize, DataTypes) {
return sequelize.define('pages_lang', {
id: {
type: DataTypes.INTEGER(10),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
page_id: {
type: DataTypes.INTEGER(10),
allowNull: false,
references : { model: "pages", key: "id" }
},
content: {
type: DataTypes.TEXT,
allowNull: false
}
}, {
classMethods: {
associate: function (models) {
this.belongsTo(models.pages, {foreignKey: 'id', foreignKeyConstraint:true, as: 'pages', through: models.pages});
}
}
});
};
But when you call results in an error
Unhandled rejection Error: pages_lang (pages_lang) is not associated
to pages!
Advance very grateful for the help

Your association alias (as) should match what you pass to findAll
this.hasMany(models.pages_lang, {onDelete: 'SET NULL', onUpdate: 'CASCADE', foreignKey: 'page_id', as: 'pages_lang' });
return this.findAll({include: [{model: pages_lang, as: 'pages_lang'}]});
Since the model is already called pages_lang, you can also skip the alias completely:
this.hasMany(models.pages_lang, {onDelete: 'SET NULL', onUpdate: 'CASCADE', foreignKey: 'page_id'});
return this.findAll({include: [pages_lang]});
Notice that I removed the through argument - it should only be used for belongsToMany (many-to-many)

Related

How can i access junction table in Sequelize?

Good evenings,fine sirs. I am working with Sequelize with NodeJS. I created Many-to-many association between two table User and Project.
//This is Project Model
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class Project extends Model {
static associate(models) {
const { User, Issue } = models;
this.belongsToMany(User, {
as: "project_users",
foreignKey: "project_id",
through: "projectuser",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
this.hasMany(Issue, {
as: "project_issues",
foreignKey: "project_id",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
}
}
Project.init(
{
project_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
projectname: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.STRING,
},
projecturl: {
type: DataTypes.STRING,
},
},
{
sequelize,
modelName: "Project",
}
);
return Project;
};
//This is User Model
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class User extends Model {
static associate(models) {
const { Commet, Project, Issue } = models;
this.hasMany(Commet, {
foreignKey: "user_id",
as: "user_commets",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
this.belongsToMany(Project, {
as: "project_user",
foreignKey: "user_id",
through: "projectuser",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
this.belongsToMany(Issue, {
as: "user_issues",
foreignKey: "user_id",
through: "issueuser",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
}
}
User.init(
{
user_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
role: {
type: DataTypes.STRING,
allowNull: false,
validate: {
roleValidator(role) {
let rolet = role.toLowerCase();
if (roles[rolet] === undefined) {
throw new Error("Invalid Role");
}
},
},
},
username: { type: DataTypes.STRING, allowNull: false },
usersurname: { type: DataTypes.STRING, allowNull: false },
avatarURL: { type: DataTypes.STRING, allowNull: true },
password: {
type: DataTypes.STRING,
validate: {
passwordValidator(password) {
if (password.length <= 5) {
throw new Error("Cannot be less than 5 characters");
}
},
},
},
email: {
type: DataTypes.STRING,
unique: true,
validate: { isEmail: true },
},
},
{
sequelize,
modelName: "User",
}
);
return User;
};
My question may be silly but, do i need to create junction table manually to access it from my code or is there any way to access it without creating it? Thank you for your answers.

Sequelize: build a staggered triple association

I'm trying to make a save that corresponds to three models: Person ->(hasOne)-> ContactInfo ->(hasMany)-> Phone.
Models:
Person:
'use strict';
const chalk = require('chalk');
const { Model } = require('sequelize');
const { gender } = require("../utils/enumList");
const { ageCalculation } = require('../utils/extraFunctions');
module.exports = (sequelize, DataTypes) =>
{
class Person extends Model
{
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models)
{
//Has one
Person.hasOne(models.ContactInfo, {
as: 'contactInfo_R',
foreignKey: {
name: "personId",
allowNull: false,
type: DataTypes.UUID,
unique: true,
},
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
Person.hasOne(models.Holder, {
as: 'holder_R',
foreignKey: {
name: "personId",
type: DataTypes.UUID,
allowNull: false,
unique: true,
},
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
Person.hasOne(models.Intermediary, {
as: 'intermediary_R',
foreignKey: {
name: "personId",
allowNull: false,
type: DataTypes.UUID,
unique: true,
},
onDelete: "CASCADE",
onUpdate: "CASCADE"
});
//Has many
Person.hasMany(models.Insured, {
as: "insured_R",
foreignKey: {
name: "personId",
allowNull: false,
type: DataTypes.UUID,
unique: false,
},
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
}
}
Person.init({
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV1,
primaryKey: true,
},
names: {
type: DataTypes.STRING,
allowNull: false,
},
surnames: {
type: DataTypes.STRING,
allowNull: false,
},
birth_date: {
type: DataTypes.DATEONLY,
allowNull: false,
},
age: {
type: DataTypes.VIRTUAL,
get()
{
return ageCalculation(this.getDataValue("birth_date"));
},
set(value)
{
throw new Error("No es necesario introducir la edad de la persona");
}
},
gender: {
type: DataTypes.ENUM(gender),
allowNull: false,
},
dni: {
type: DataTypes.STRING,
allowNull: true,
},
support_dni_address: {
type: DataTypes.STRING,
allowNull: true,
}
}, {
sequelize,
modelName: 'Person',
});
return Person;
};
ContactInfo:
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) =>
{
class ContactInfo extends Model
{
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models)
{
// define association here
//Has many
ContactInfo.hasMany(models.Phone, {
as: "phone_R",
foreignKey: {
name: "contactInfoId",
type: DataTypes.UUID,
allowNull: false,
},
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
//Belong to
ContactInfo.belongsTo(models.Person, {
as: "person_R",
foreignKey: {
name: "personId",
type: DataTypes.UUID,
allowNull: false,
unique: true,
},
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
}
}
ContactInfo.init({
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV1,
primaryKey: true,
},
nation: {
type: DataTypes.STRING,
allowNull: false,
},
region: {
type: DataTypes.STRING,
allowNull: true,
},
city: {
type: DataTypes.STRING,
allowNull: true
},
address_1: {
type: DataTypes.STRING,
allowNull: true,
},
address_2: {
type: DataTypes.STRING,
allowNull: true,
},
email: {
type: DataTypes.STRING,
allowNull: false,
validate: {
isEmail: {
arg: true,
msg: "Por favor, usar un formato de correo electrónico valido"
},
},
},
}, {
sequelize,
modelName: 'ContactInfo',
});
return ContactInfo;
};
Phone:
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) =>
{
class Phone extends Model
{
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models)
{
//Belong to
Phone.contactInfo = Phone.belongsTo(models.ContactInfo, {
as: "contactInfo_R",
foreignKey: {
name: "contactInfoId",
allowNull: false,
type: DataTypes.UUID,
unique: false
},
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
}
}
Phone.init({
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV1,
primaryKey: true,
},
nation_phone_code: {
type: DataTypes.STRING,
allowNull: false,
//TODO add predefined list
},
phone_number: {
type: DataTypes.STRING,
allowNull: false,
//TODO add formatting and validating
}
}, {
sequelize,
modelName: 'Phone',
});
return Phone;
};
Build Code:
let HolderPerson = await Models.Person.build({
names: personHolder_form.names,
surnames: personHolder_form.surnames,
birth_date: personHolder_form.birth_date,
gender: personHolder_form.gender,
dni: personHolder_form.dni,
support_dni_address: personHolder_form.support_dni_address,
contactInfo_R: {
nation: ContactInfoHolder_form.nation,
region: ContactInfoHolder_form.region,
city: ContactInfoHolder_form.city,
address_1: ContactInfoHolder_form.address_1,
address_2: ContactInfoHolder_form.address_2,
email: ContactInfoHolder_form.email,
phone_R: [
{ phone_number: '04269872654', nation_phone_code: '+58' },
{ phone_number: '02569871452', nation_phone_code: '+57' }
],
}
}, {
include: [{
association: {
model: Models.ContactInfo,
as: 'contactInfo_R'
},
include: [{
model: Models.Phone,
as: 'phone_R'
}]
}],
});
console.log(HolderPerson);
Console Error:
TypeError: Cannot read property 'name' of undefined
at Function._conformInclude (/home/sistemas/proyectos/Sistema_PreCris/node_modules/sequelize/lib/model.js:301:50)
at /home/sistemas/proyectos/Sistema_PreCris/node_modules/sequelize/lib/model.js:270:61
at Array.map (<anonymous>)
at Function._conformIncludes (/home/sistemas/proyectos/Sistema_PreCris/node_modules/sequelize/lib/model.js:270:39)
at new Model (/home/sistemas/proyectos/Sistema_PreCris/node_modules/sequelize/lib/model.js:104:24)
at new Person (/home/sistemas/proyectos/Sistema_PreCris/src/models/Person.js:10:5)
at Function.build (/home/sistemas/proyectos/Sistema_PreCris/node_modules/sequelize/lib/model.js:1326:12)
at primeraParte (/home/sistemas/proyectos/Sistema_PreCris/src/controllers/pruebas.js:86:52)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
I've done what I understand from the sequelize documentation but I can't get it to work. If I remove the association from the third model it works. I do not know what else to do.

Cyclic dependency found

I have the following error:
Unhandled rejection Error: Cyclic dependency found. coupons is
dependent of itself. Dependency chain: coupons -> orders => coupons
My order.js model looks like as follows:
'use strict';
module.exports = (sequelize, DataTypes) =>
{
var Order = sequelize.define('orders',
{
id:
{
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
userid:
{
type: DataTypes.INTEGER,
references:
{
model: 'users',
key: 'id'
}
},
coupon_id:
{
type: DataTypes.INTEGER,
allowNull: true,
references:
{
model: 'coupons',
key: 'id'
},
},
product:
{
type: DataTypes.INTEGER,
references:
{
model: 'products',
key: 'id'
}
},
address:
{
type: DataTypes.INTEGER,
references:
{
model: 'address',
key: 'id'
}
},
canceled:
{
type: DataTypes.INTEGER,
defaultValue: 0
},
quantity:
{
type: DataTypes.INTEGER,
},
note:
{
allowNull: true,
type: DataTypes.STRING
},
},
{
freezeTableName: true,
tableName: 'orders',
createdAt: 'createdat',
updatedAt: 'updatedat',
});
Order.associate = models => {
Order.hasMany(models.coupons, {
foreignKey: 'id',
onDelete: 'cascade',
onUpdate: 'cascade',
constrains: false
});
};
return Order;
};
and coupon.js looks like this:
'use strict';
module.exports = (sequelize, DataTypes) =>
{
var Coupon = sequelize.define('coupons',
{
id:
{
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
name:
{
type: DataTypes.STRING
},
code:
{
type: DataTypes.STRING
},
discount:
{
type: DataTypes.FLOAT
},
expires:
{
type: 'TIMESTAMP',
},
created_by:
{
type: DataTypes.INTEGER,
references:
{
model: 'users',
key: 'id'
},
},
maxuse:
{
type: DataTypes.INTEGER,
},
},
{
freezeTableName: true,
tableName: 'coupons',
createdAt: 'createdat',
updatedAt: 'updatedat'
});
Coupon.associate = models => {
Coupon.belongsTo(models.orders,
{
foreignKey: 'id',
onDelete: 'cascade',
onUpdate: 'cascade',
});
};
return Coupon;
};
It seems that I am doing something wrong with the associations. Any help would be appreciated.
NOTE: Everytime I comment out coupon_id: on orders.js, the error goes out. Still, I need this functionality.

Sequelize query singular instead of plural table name

I have an problem and I can't find anything that can solve it. I'm using sequelize and graphql to create an API in nodeJS. The database is using PostgresQL.
So I have two models: Simulation and Data. They are in two tables Simulations and Datas. The relation between them is one Simulation to many Datas.
The problem is this: when I make a query with Simulation (ex: Simulation.findAll()), it works correctly, querying "Simulations", but with Data, it queries on the "Data" table, not "Datas". What I really don't understand is that the code of my two models are almost the same.
Here is the model for Simulation:
module.exports = (sequelize, DataTypes) => {
const Simulation = sequelize.define('Simulation', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
});
Simulation.associate = function(models) {
Simulation.hasMany(models.Data, {
foreignKey: 'SimulationId',
})
};
return Simulation;
};
Here is the model for Data:
module.exports = (sequelize, DataTypes) => {
const Data = sequelize.define('Data', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING,
allowNull: false
},
content: {
type: DataTypes.TEXT,
allowNull: false
},
SimulationId: {
allowNull: false,
type: DataTypes.INTEGER,
},
});
Data.associate = function(models) {
Data.belongsTo(models.Simulation, {
foreignKey: 'SimulationId',
targetKey: 'id',
allowNull: false,
onDelete: 'CASCADE'
});
};
return Data;
};
And here are the migration files:
Simulation
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Simulations', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Simulations');
}
};
Data
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Datas', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING,
allowNull: false
},
content: {
type: Sequelize.TEXT,
allowNull: false
},
SimulationId: {
allowNull: false,
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
references: {
model: 'Simulation',
key: 'id',
as: 'SimulationId',
},
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Datas');
}
};
Thanks for helping me :)
You can use freezeTableName option to set whatever the model name you want, sequelize will not make the model names plural.
Sequelize automatically makes the model names plural. Why not call the table "Data" It is actually a plural form of the word "Data", so maybe a better name for the table.

Sequelize belongsToMany additional attributes in join table

I'm having problem with an additional attribute in the join table of the belongsToMany relation.
In the set or add method this attribute is not being passed to mysql.
I'm following the documentation pass as "through" the attribute within the set method, but it is not working.
Would anyone know what could be wrong since following the documentation is not working?
Note: The registration and update of the join is correct, only the additional attribute that is not being passed to the table.
Functionality Model:
export default function(sequelize, DataTypes) {
const Functionality = sequelize.define('functionality', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
field: 'name',
type: DataTypes.STRING(300),
allowNull: false
}
}, {
classMethods: {
associate: function(models) {
Functionality.belongsToMany(models.privilege, { as: 'privilegies', through: models.functionality_privilege, foreignKey: 'functionality_id' });
}
},
tableName: 'functionality',
freezeTableName: true,
timestamps: true,
createdAt: 'createdAt',
updatedAt: 'updatedAt'
});
return Functionality;
}
Privilege Model:
export default function(sequelize, DataTypes) {
const Privilege = sequelize.define('privilege', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
field: 'name',
type: DataTypes.STRING(300),
allowNull: false
}
}, {
classMethods: {
associate: function(models) {
Privilege.belongsToMany(models.functionality, { as: 'functionalities', through: models.functionality_privilege, foreignKey: 'privilege_id' });
}
},
tableName: 'privilege',
freezeTableName: true,
timestamps: true,
createdAt: 'createdAt',
updatedAt: 'updatedAt'
});
return Privilege;
}
FunctionalityPrivilege Model:
export default function(sequelize, DataTypes) {
const Functionalityprivilege = sequelize.define('functionality_privilege', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
edit: {
field: 'edit',
type: DataTypes.BOOLEAN
}
}, {
tableName: 'functionality_privilege',
freezeTableName: true,
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at'
});
return Functionalityprivilege;
}
Method Create:
create(options) {
let obj = options.payload;
return this.functionalityDao.create(obj)
.then((result) => {
return result.setPrivilegies(obj.privilegies, { through: { edit: obj.permissions }})
});
}
OR
return result.setPrivilegies(obj.privilegies, { through: { edit: true }})
I didn't manage to do this with 'set' function but it worked for me with 'add' method:
result.addPrivilege(privilege, { through: { edit: true }});
It should work for the already existing privilege. It didn't work with the array of entities (privileges in your case), so I had to call 'add' method several times. Like this:
return Promise.all(
privileges.map(privilege => result.addPrivilege(privilege, { through: { edit: true }}));
)

Resources