SequelizeEagerLoadingError, can't get data with include - javascript

I use Sequelize.js to make requests to database. I have a many-to-many relationship between two tables, and I made a third junction table. Here are my three tables. polit_in_article is the junction table.
politician.js:
module.exports = (sequelize, DataTypes) => {
const Politician = sequelize.define('politician', {
...
});
Politician.associate = (models) => {
Politician.hasMany(models.Polit_in_article, {
foreignKey: 'politicianId',
as: 'polit_in_articles',
});
};
return Politician;
};
article.js:
module.exports = (sequelize, DataTypes) => {
const Article = sequelize.define('article', {
...
});
Article.associate = (models) => {
Article.hasMany(models.Politician, {
foreignKey: 'articleId',
as: 'polit_in_articles'
});
};
return Article;
};
polit_in_article.js:
module.exports = (sequelize, DataTypes) => {
const Polit_in_article = sequelize.define('polit_in_article', {
times_mentioned: DataTypes.INTEGER,
});
Polit_in_article.associate = (models) => {
Polit_in_article.belongsTo(models.Article, {
// foreignKey: 'articleId',
as: 'articles',
});
Polit_in_article.belongsTo(models.Politician, {
// foreignKey: 'politicianId',
as: 'politicians',
});
};
return Polit_in_article;
};
And here is my controller(not sure if that is the right way to call it):
const Sequelize = require('sequelize');
const Article = require('../models').Article;
const Politician = require('../models').Politician;
const Polit_in_article = require('../models').Polit_in_article;
const Op = Sequelize.Op;
module.exports = {
getAllArticlesOfPolitician(req) {
return Article
.findAll({
include: [{
model: Polit_in_article,
include: [{
model: Politician,
where: {
lastname: req.query.politicianLastName,
}
}],
}],
}).then(response => response)
// .catch(err => err);
}
};
and with this I get an error SequelizeEagerLoadingError: polit_in_article is not associated to article. It is possible that I missed something, but I really don't know what to do here. I have tried to make the articles table to have association as: 'polit_in_articles', that worked until I needed to include the politicians tabel in to the query as well.

You need to use the through keyword in your associations. Articles will have politicians through the Polit_in_article model, however since you are just using the primary keys on it you can let it be inferred and leave out polit_in_article.js and just use a string to name the table.
Politician.associate = (models) => {
Politician.hasMany(models.Article, {
foreignKey: 'politicianId',
through: 'polit_in_article',
as: 'articles',
});
};
Article.associate = (models) => {
Article.hasMany(models.Politician, {
foreignKey: 'articleId',
through: 'polit_in_article',
as: 'politicians',
});
};
Now you can query through the join table by specifying as and through.
getAllArticlesOfPolitician(req) {
return Article.findAll({
include: [{
model: Politician,
as: 'politicians',
through: 'polit_in_article',
where: {
lastname: req.query.politicianLastName,
},
}],
})
.then(response => response)
.catch(err => err);
}

I just needed to fix association in article.js, I made association with politician instead of the junction table:
module.exports = (sequelize, DataTypes) => {
const Article = sequelize.define('article', {
...
});
Article.associate = (models) => {
Article.hasMany(models.Polit_in_article, {
foreignKey: 'articleId',
as: 'polit_in_articles'
});
};
return Article;
};

Related

I cannot delete a record "Cannot delete or update a parent row: a foreign key constraint fails FOREIGN KEY (`forumId`) REFERENCES `forums` (`id`))"

I am trying to delete my forum and I would like that when I delete the forum all the members who are in the forum are also deleted here is the code of the controllers
module.exports.deleteGroup = async (req, res, next) => {
const token = req.cookies.jwt;
const decoded = jwtAuth.verify(token, process.env.TOKEN_SECRET);
const userTokenId = decoded.id;
try {
const { id } = req.params;
const currentUser = await User.findByPk(userTokenId);
if (!currentUser) return res.status(404).json('You must be logged in to make this request');
const forum = await Forum.findOne({ where: { id } });
if (!forum) return res.status(404).json("This forum does not exist please try again!");
if (forum.createByUserId === currentUser.id || currentUser.isAdmin) {
const deleteForum = await Forum.destroy({ where: { id } });
if (deleteForum) {
const deleteMembers = await ForumMember.destroy({ where: {} });
return res.status(200).json(`The forum ${forum.name} has been deleted`);
}
else {
return res.status(401).json(`You are not authorized to delete this forum`)
}
}
} catch (error) {
res.status(500).json(error.message)
}
}
My associations
//Users
models.User.belongsToMany(models.Forum, {
through: models.ForumMember,
foreignKey: 'userId',
otherKey: 'forumId'
});
//Forums
models.Forum.belongsToMany(models.User, {
through: models.ForumMember,
foreignKey: 'forumId',
otherKey: 'userId',
});
//ForumMember
models.ForumMember.belongsTo(models.Forum, {
foreignKey: 'forumId',
as: 'groups'
});
models.ForumMember.belongsTo(models.User, {
foreignKey: 'userId',
as: 'members'
});
}
};
ForumMember.init({
forumId: {
type: DataTypes.INTEGER,
references: {
model: 'Forum',
key: 'id'
},
},
userId: {
type: DataTypes.INTEGER,
references: {
model: 'User',
key: 'id'
},
Now when I execute on PostMan I get this response: "Cannot delete or update a parent row: a foreign key constraint fails (groupomania_database_development.forummembers, CONSTRAINT forummembers_ibfk_1 FOREIGN KEY (forumId) REFERENCES forums (id))" I think I have a problem with my associations. I'm a newbie on sequelize and I would like to have your help please
First, you need to delete child records in junk table and the final step would be the deletion of a forum.
Second, you didn't indicate a condition in ForumMember.destroy so Sequelize tries to delete all rows in ForumMeber regardless what forum they belong to.
const deleteMembers = await ForumMember.destroy({ where: { forumId: id } });
const deleteForum = await Forum.destroy({ where: { id } });
if (deleteForum) {
return res.status(200).json(`The forum ${forum.name} has been deleted`);
}
Third, to avoid inconsistent data in DB you need to use transactions if you make several modifications:
await sequelize.transaction(async (tr) => {
const deleteMembers = await ForumMember.destroy({ where: { forumId: id }, transaction: tr });
const deleteForum = await Forum.destroy({ where: { id }, transaction: tr });
...
});

Sequelize associations between two tables

I am fairly new to this (using sequelize) and everything is new to me. The thing is that I can create and get users through my "users.model.js" but now I want to create a model called "data.model.js" to associate some data to a certain user.
So according to the sequelize docs, my associations should be the following:
Users.hasMany(Data)
Data.belongsTo(Users)
But when sequelize creates my tables, I don't have my foreign key in my data table.
I will share my code with you:
config file (config.js):
const Sequelize = require('sequelize');
const connection = new Sequelize('drglicemia', 'root', '', {
host: 'localhost',
dialect: 'mysql'
});
module.exports = connection;
data.model.js:
const sequelize = require('sequelize');
const db = require('../config/database');
const usersTable = require('./users.model')
let Data = db.define('tabeladados', {
dta: { type: sequelize.DATEONLY },
hora: { type: sequelize.DATE },
indiceglicemia: { type: sequelize.STRING },
insulina: { type: sequelize.STRING },
medicacao: { type: sequelize.STRING },
}, {
timeStamps: false, tableName: 'tabeladados'
});
//associates the dataTable table with the users
Data.associate = () => {
Data.belongsTo(usersTable)
}
module.exports = Data;
users.model.js:
const sequelize = require('sequelize');
const promise = require('bluebird')
const bcrypt = promise.promisifyAll(require('bcrypt'))
const db = require('../config/database');
const dataTable = require('./data.model')
let Users = db.define('utilizadores', {
username: { type: sequelize.STRING },
email: { type: sequelize.STRING },
password: { type: sequelize.STRING },
}, {
timeStamps: false, tableName: 'utilizadores',
});
//encrypts the password before submiting to the database
Users.beforeCreate((user, options) => {
return bcrypt.hash(user.password, 10)
.then(hash => {
user.password = hash;
})
.catch(err => {
throw new Error();
});
});
//validates the password submited by the user with the one encrypted in the database
Users.prototype.validPassword = async (password) => {
return await bcrypt.compare(password, this.password);
}
//associates the users table with the dataTable
Users.associate = () => {
Users.hasMany(dataTable)
}
module.exports = Users;
I believe that when I am trying to associate my tables I am doing something wrong, because I feel that I am doing it the wrong way.
I don't know but everything works besides this.
But it's like what I said in the beginning, I am new to sequelize xD
I think the reason is circular reference. user.model.js requires data.model.js, and data.model.js requires user.model.js.
You need to create an index.js file. Require and make the associations for all models here, then re-export them. E.g.
./models/index.js:
const User = require('./user.model.js');
const Data = require('./data.model.js');
User.hasMany(Data);
Data.belongsTo(User);
module.exports = {User, Data}
service.js or controller.js:
const models = require('./models/index.js');
// use models
await models.User.findAll();
Remove below codes in your model file:
// Remove from user.model.js file
Users.associate = () => {
Users.hasMany(dataTable)
}
// Remove from data.model.js file
Data.associate = () => {
Data.belongsTo(usersTable)
}

Sequelize - Many to Many relationship Model A is not associated to Model B

I have two Entities: TrainingDay and Exercise which are in a many to many relationship. For the implementation of the relationship I have oriented myself on the following link: https://medium.com/#the_ozmic/how-to-create-many-to-many-relationship-using-sequelize-orm-postgres-on-express-677753a3edb5.
Unfortunately, I get the following error: Unhandled rejection SequelizeEagerLoadingError: TrainingDays is not associated to Exercises!
Exercises.js
//jshint esversion:6
const Sequelize = require('sequelize');
const database = require('../database.js');
const TrainingDays = require('./TrainingDays.js');
const Exercises = database.define('Exercises', {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
name: Sequelize.STRING,
description: Sequelize.STRING
});
// TODO: not shure why I have to wrap Exercise.belongsToMany... into Exercise.associate = function(models) {...
Exercises.associate = function(models) {
Exercises.belongsToMany(models.TrainingDays, {
through: 'ExerciseTrainingDays',
as: 'trainingDays',
foreignKey: 'exerciseId'
});
};
module.exports = Exercises;
TrainingDay.js
//jshint esversion:6
const Sequelize = require('sequelize');
const database = require('../database.js');
const TrainingPlans = require('./TrainingPlans.js');
const Exercises = require('./Exercises.js');
const TrainingDays = database.define('TrainingDays', {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
date: Sequelize.DATE,
muscleGroup: Sequelize.STRING
});
TrainingDays.associate= function(models){
TrainingDays.belongsTo(models.TrainingPlans);
TrainingDays.belongsToMany(models.Exercises, {
through: 'ExerciseTrainingDays',
as: 'exercises',
foreignKey: 'trainingDayId'
});
};
module.exports = TrainingDays;
Here is the Join Entity:
ExerciseTrainingDays.js
//jshint esversion:6
const Sequelize = require('sequelize');
const database = require('../database.js');
const ExerciseTrainingDays = database.define('ExerciseTrainingDays', {
ExerciseId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Exercises',
key: 'id'
}
},
TrainingDayId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'TrainingDays',
key: 'id'
}
}
});
module.exports = ExerciseTrainingDays;
I use the following code for testing:
//jshint esversion:6
const TrainingPlans = require('./models/TrainingPlans.js');
const TrainingDays = require('./models/TrainingDays.js');
const Exercises = require('./models/Exercises.js');
const Sets = require('./models/Sets.js');
const ExerciseTrainingDays = require('./models/ExerciseTrainingDays.js');
const database = require('./database.js');
database.sync();
TrainingPlans.findAll().then(trainingPlans => {
console.log("All trainingPlans:", JSON.stringify(trainingPlans, null, 4));
});
TrainingDays.findAll().then(trainingDays => {
console.log("All trainingDays:", JSON.stringify(trainingDays, null, 4));
});
Exercises.findAll().then(exercises => {
console.log("All exercises:", JSON.stringify(exercises, null, 4));
});
Exercises.findAll({
include:[{
model: TrainingDays,
where: {id : 1000}}]
}).then(exercise => {
console.log("All exercises:", JSON.stringify(exercise, null, 4));
});
After the call of Exercises.findAll({ include:[{… I get the described error. The other queries work in a proper way. I don't know what I'm doing wrong, I hope someone can help me.

Sequelize model association update not reflected as expected

I'm trying to associate tags to an organization via sequelize's set<Model>(...) method and it seems to be setting the tags correctly in the db but the updated org with these new tags does not reflect this.
organization model
'use strict';
module.exports = (sequelize, DataTypes) => {
var organization = sequelize.define('organization', {
...
}, {});
organization.associate = function (models) {
// associations can be defined here
organization.hasMany(models.tag)
};
return organization;
};
tag model
'use strict';
module.exports = (sequelize, DataTypes) => {
...
tags.associate = function(models) {
// associations can be defined here
tags.belongsTo(models.organization)
};
return tags;
};
method
/**
* Update organization
* #param {object} db - The db handle
* #param {object} stats - The datadog client
*/
function updateOrganization(db, stats) {
return function (req, res) {
let tagsToAdd = []
let tagsToDelete = []
let myOrg
db.organization.findOne({
where: {
id: req.params.id
},
include: ['tags', 'users', 'retrievals']
})
.then(org => {
myOrg = org
return org.getTags()
})
.then(tags => {
let promises = []
...a bunch of irrelevant logic
// Add all the new tags
tagsToAdd.forEach(tag => {
promises.push(myOrg.createTag({ name: 'newTag' }))
})
return Promise.all(promises)
})
.then(updatedOrg => {
console.log('updatedOrg = ', updatedOrg) <-- Does NOT have tags in updated org output even though they actually exist in db. Why not???
return res.status(HttpStatus.OK).send(updatedOrg)
})
}
}
After countless hours of smashing my skull against anything near me i finally figured out that i needed to call reload()
.then(updatedOrg => {
console.log('updatedOrg = ', updatedOrg)
return res.status(HttpStatus.OK).send(updatedOrg)
})
should be
.then(updatedOrg => {
return myOrg.reload()
})
.then(updatedOrg => {
return res.status(HttpStatus.OK).send(updatedOrg)
})

Including a belongsTo association in sequelize

I am following the sequelize example in the docs and I am stuck as to how to include an association to the parent in the child model.
In the docs on associations, models and the relationships between models are defined like so:
Product.User = Product.belongsTo(User);
User.Addresses = User.hasMany(Address);
return Product.create({
title: 'Chair',
user: {
first_name: 'Mick',
last_name: 'Broadstone',
}
}, {
include: [{
association: Product.User,
}]
});
The association is assigned to Product.User, and included in the include array.
In the sequelize minimum express application the models are defined in separate files and the associations are made by calling the methods on the models. In this case I have Message and User, with a belongsTo relationship between one message and its user.
//message.js
module.exports = (sequelize, DataTypes) => {
var Message = sequelize.define('Message', {
content: DataTypes.STRING,
authorId: DataTypes.INTEGER,
});
Message.associate = function (models) {
models.Message.belongsTo(models.User, {
foreignKey: 'authorId',
as: 'author',
});
};
return Message;
};
//user.js
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
firstName: DataTypes.STRING,
});
User.associate = function (models) {
models.User.hasMany(models.Message, {foriegnKey: 'authorId'});
};
return User;
};
I think I need to somehow get the association from the models. I followed the docs to make the associations between the models:
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
But how do I do Message.User = Message.belongsTo(User) such that when I create the include array do include[{association: Message.User}] ?
Right... I realised since the association was already made all I had to do was include the model:
const createMessage = async (message) => {
const author = await findUser(message.author);
if (author) {
const authorId = author.dataValues.id;
return db.Message.create({
content: message.content,
authorId: authorId,
});
} else {
return db.Message.create({
author: {
firstName: message.author,
},
content: message.content,
}, {include:[{model: db.User, as: 'author'}],
});
}
};

Categories