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'}],
});
}
};
Related
I am trying to insert data into MongoDB database but I get this error Cannot read property 'push' of undefined.
I can't understand what is the issue is here in my code. please help me with the solution. I am a Student and learning it.
here I am trying to push service into the category Model. for that, I have created a one to many relations between service and category. but I can't push the services into the category.
Schema design for category & Service =======
const mongoose = require("mongoose")
const Schema = mongoose.Schema
const CategorySchema = new Schema({
name:{
type:String,
required:true
},
services:[
{
type:Schema.Types.ObjectId,
ref:'Service'
}
]
},{ timestamps:true })
const Category = mongoose.model("Cat", CategorySchema);
module.exports = Category;
service======
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const serviceSchema = new Schema({
title:{
type: 'String',
required: true
},
description:{
type: 'String',
required: true
},
image: {
type: 'String',
required: true
},
price: {
type: 'Number',
required: true
},
category: {
type:Schema.Types.ObjectId,
ref:'Cat'
}
})
const Service = mongoose.model("Service", serviceSchema);
module.exports = Service;
here is my service controller
postService:(req, res)=>{
const { title, price, description,category} = req.body;
const image = req.file.filename;
const service = new Service({
title,
price,
category,
description,
image,
});
service.save()
.then((service)=>{
const category = Category.findOneAndUpdate({_id: service.category})
category.services.push(service)
category.save()
console.log(category)
return res.redirect("/admin/services");
})
.catch((err) => {
console.log(err);
return res.redirect("/admin/services/create");
});
},
do like this:
postService: async(req, res)=>{
const { title, price, description,category} = req.body;
const image = req.file.filename;
const service = new Service({
title,
price,
category,
description,
image,
});
try {
await service.save()
let categoryModel = await Category.findById(category);//category should be an ObjectId
categoryModel.services.push(service)
await categoryModel.save()
return res.redirect("/admin/services");
} catch (err) {
console.log(err);
return res.redirect("/admin/services/create");
}
},
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)
}
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.
I do not understand what the problem is.
And why each element from the 'tasks' array is null.
Schema = mongoose.Schema;
const userSchema = new Schema({
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
tasks: [{type: Schema.Types.ObjectId, ref: 'Task'}]
}
);
const taskSchema = new Schema({
title: String
});
const User = mongoose.model('User', userSchema);
const Task = mongoose.model('Task', taskSchema);
// Add some default to DB
const task1 = new Task({
title: "Welcome! Here You Can:"
});
const task2 = new Task({
title: "ADD EDIT DELETE SHARE your TASKS "
});
const defaultTasks = [task1, task2];
When create new User I Add defaultTasks
const newUser = {
email: req.body.email,
password: req.body.password,
tasks: defaultTasks
};
Get Users Tasks
app.get('/tasks/', function(req, res){
const email = req.query.user;
User
.findOne({email: email})
.populate('tasks')
.exec()
.then(foundUser => {
console.log(foundUser);
const data = [];
Object.keys(foundUser.tasks).forEach(function(key) {
const val = foundUser.tasks[key];
data.push([val.title, val._id]);
});
res.send(data);
console.log('Data to send ' + data);
});
});
Before .Populate() console.log {
{ tasks: [ 5cf78ac1d08ee617fc89f7ed, 5cf78ac1d08ee617fc89f7ee ]
After { { tasks: [],
Please Help! All that I found did not solve my problem.
Maybe problem in defaultTasks. But i dont see it.
Your code doesn't save your task to DB, it just creates an object. So later when you populate User there are no tasks in DB to be found.
const task1 = await new Task({
title: "Welcome! Here You Can:"
}).save();
// or
const task1 = await Task.create({
title: "Welcome! Here You Can:"
});
P.s. of course you can deal with asynchronous calls the way you want.
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;
};