I am new to the database and learning sequelize (Postgres). I am building a blogging web app and trying to implement association in my DB but getting a server-side error as
error: creator is not associated with blogpost
here is what I have done till now.
creator_model
const Sequelize = require('sequelize');
const db = require('../db/dbConfig');
const bcrypt = require('bcrypt');
const Creator = db.sequelize.define('creator', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
password: {
type: Sequelize.STRING,
allowNull: false
}
},
{
hooks: {
beforeCreate: (Creator) => {
Creator.password = bcrypt.hashSync(Creator.password,10)
}
}
}
);
Creator.associate = (models) => {
console.log('visited here')
Creator.hasMany(models.BlogPost,{
foreignKey: "creatorId",
as: "owner",
onDelete: 'CASCADE'
});
}
module.exports = Creator;
Blog_model
const Sequelize = require('sequelize');
const Creator = require('../models/CreatorModel');
const db = require('../db/dbConfig');
const BlogPost = db.sequelize.define('blogpost',{
blogId: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
title: {
type: Sequelize.STRING,
allowNull: false
},
cover: {
type: Sequelize.STRING,
allowNull: false
},
body: {
type: Sequelize.TEXT,
allowNull: false
},
creatorId: {
type: Sequelize.INTEGER,
references:{
model: Creator,
key: 'id'
},
allowNull: false
},
likes: {
type: Sequelize.INTEGER,
defaultValue: 0
}
},{});
BlogPost.associate = (models) => {
BlogPost.hasMany(models.Comment,{
foreignKey: 'postId',
as: 'blogpost',
onDelete: 'CASCADE'
});
BlogPost.belongsTo(models.Creator,{
foreignKey: 'creatorId',
as: 'creator',
onDelete: 'CASCADE'
})
}
module.exports = BlogPost;
Comment_model
const Sequelize = require('sequelize');
const BlogPost = require('../models/BlogPostModel');
const db = require('../db/dbConfig');
const Comment = db.sequelize.define('comment',{
commentId: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
name: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false
},
message: {
type: Sequelize.TEXT,
allowNull: false
},
blogPostId: {
type: Sequelize.INTEGER,
references: {
model: BlogPost,
key: 'blogId'
},
allowNull: false
}
},{});
Comment.associate = (models) => {
Comment.belongsTo(models.BlogPost,{
foreignKey: 'blogPostId',
as: 'blog',
onDelete: 'CASCADE'
})
}
module.exports = Comment;
here is my DB config with express and sequelize
const Sequelize = require('sequelize');
const dotenv=require("dotenv");
dotenv.config();
const db ={}
const sequelize = new Sequelize(`${process.env.DB_NAME}`, `${process.env.DB_USERNAME}`, `${process.env.DB_PASSWORD}`, {
host: 'localhost',
dialect: 'postgres'
})
sequelize
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
db.sequelize = sequelize
db.Sequelize = Sequelize
sequelize.sync()
.then(() => {
console.log(`Database & tables created!`)
})
.catch(error => console.log("DB error: ",error));
module.exports = db;
controller.js
const BlogPost = require('../models/BlogPostModel');
const Comment = require('../models/CommentModel');
const Creator = require('../models/CreatorModel');
const getAllBlog = (req,res) =>{
BlogPost.findAll({
include: [
{
model: Creator,
as: "author",
include: [{
model: Comment,
as: "comments"
}]
}
]
})
.then(data => {
res.json(data)
})
.catch(error => {
res.status(500).json({error: error.message})
})
}
module.exports = {
getAllBlog
}
Related
I am trying to create seqeulize models in nodejs app on mysql db. However, When I run the codes, foreign keys are not being created as intended.
This are my models:
Category Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Category = sequelize.define("Category", {
category_id: {
type: DataTypes.STRING(255),
unique: true,
primaryKey: true,
},
name: { type: DataTypes.STRING, unique: true, allowNull: false },
slug: { type: DataTypes.STRING, unique: true, allowNull: false },
created_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal("CURRENT_TIMESTAMP"),
},
updated_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal(
"CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
),
},
});
Category.associate = (models) => {
Category.hasMany(models.Product);
};
return Category;
};
Product Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Product = sequelize.define("Product", {
product_id: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
slug: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
sku: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
short_description: {
type: DataTypes.TEXT,
allowNull: false,
},
description: {
type: DataTypes.TEXT,
allowNull: false,
},
price: {
type: DataTypes.DECIMAL,
allowNull: false,
min: 1,
},
discount: {
type: DataTypes.DECIMAL,
allowNull: true,
},
quantity: {
type: DataTypes.INTEGER,
},
vat: {
type: DataTypes.DECIMAL,
allowNull: true,
},
tags: {
type: DataTypes.STRING(255),
allowNull: true,
},
rate: {
type: DataTypes.INTEGER,
allowNull: true,
},
points: {
type: DataTypes.INTEGER,
allowNull: true,
},
new: {
type: DataTypes.VIRTUAL,
get() {
var msPerDay = 8.64e7;
// Copy dates so don't mess them up
var x0 = new Date(this.getDataValue("created_at"));
var x1 = new Date();
// Set to noon - avoid DST errors
x0.setHours(12, 0, 0);
x1.setHours(12, 0, 0);
// Round to remove daylight saving errors
return Math.round((x1 - x0) / msPerDay) <= 30;
},
set(value) {
throw new Error("Can't set Product.new property.");
},
},
thumb_image: {
type: DataTypes.STRING,
allowNull: true,
get() {
if (this.getDataValue("thumb_image")) {
return JSON.parse(this.getDataValue("thumb_image"));
}
return [];
},
set(val) {
this.setDataValue("thumbImage", JSON.stringify(val));
},
},
images: {
type: DataTypes.STRING,
allowNull: true,
get() {
if (this.getDataValue("images")) {
return JSON.parse(this.getDataValue("images"));
}
return [];
},
set(val) {
this.setDataValue("images", JSON.stringify(val));
},
},
featured: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
created_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal("CURRENT_TIMESTAMP"),
},
updated_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal(
"CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
),
},
});
Product.associate = (models) => {
Product.belongsTo(models.Category, {
foreignKey: "category_id",
});
Product.belongsTo(models.Brand, {
foreignKey: "brand_id",
});
Product.belongsTo(models.CartItem, {
foreignKey: "cart_id",
});
};
return Product;
};
Brand Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Brand = sequelize.define("Brand", {
brand_id: {
type: DataTypes.STRING(255),
unique: true,
primaryKey: true,
},
name: { type: DataTypes.STRING, unique: true, allowNull: false },
slug: { type: DataTypes.STRING, unique: true, allowNull: false },
created_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal("CURRENT_TIMESTAMP"),
},
updated_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal(
"CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
),
},
});
Brand.associate = (models) => {
Brand.hasMany(models.Product);
};
return Brand;
};
And these is my Models/index.js file
/* eslint-disable no-undef */
"use strict";
const fs = require("fs");
const path = require("path");
const Sequelize = require("sequelize");
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || "development";
const config = require(__dirname + "/../../config/config.js")[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
);
}
db.sequelize = sequelize;
db.Sequelize = Sequelize;
fs.readdirSync(__dirname)
.filter((file) => {
return (
file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
);
})
.forEach((file) => {
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes
);
db[model.name] = model;
});
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize
.sync({ force: process.env.NODE_ENV === "development" })
.then(() => {
console.log("Drop and re-sync db.");
});
module.exports = db;
Now when I run the server, I expected the products table to have the fields category_id and brand_id. However, am getting additional fields brand_brand_id and category_category_id on the products table.
Besides, I cannot retrieve the categories, brands and products with the include properties when fecthing data.
What I want is to have the products table properly created in the database with the required foreign keys
Since you have customized foreign keys you have to indicate them in both paired associations:
Category.associate = (models) => {
Category.hasMany(models.Product, { foreignKey: "category_id" });
};
Product.associate = (models) => {
Product.belongsTo(models.Category, {
foreignKey: "category_id",
});
Product.belongsTo(models.Brand, {
foreignKey: "brand_id",
});
Product.belongsTo(models.CartItem, {
foreignKey: "cart_id",
});
};
Brand.associate = (models) => {
Brand.hasMany(models.Product, { foreignKey: "brand_id" });
};
I'm trying to seed into a database. I have successfully seeded using 2 other models, but when I try to seed data into a Model called 'Comment', I get this error:
TypeError: this.sequelize.isDefined is not a function
It has only happened for this particular model, even though the syntax is practically identical to the other two. Has anyone gotten this error before?
Here is the seed.js file. I commented out the Comment section (the one that doesn't work) but the other two are just fine.
const sequelize = require('../config/connection');
const { User, Post, Comment } = require('../models');
const userData = require('./usersSeed.json');
const postData = require('./postsSeed.json');
const commentData = require('./commentSeed.json')
const seedDatabase = async () => {
await sequelize.sync({ force: true });
await User.bulkCreate(userData, {
individualHooks: true,
returning: true,
});
await Post.bulkCreate(postData, {
individualHooks: true,
returning: true,
});
/* await Comment.bulkCreate(commentData,
{
individualHooks: true,
returning: true,
}); */
process.exit(0);
};
seedDatabase();
Here is a model that works fine
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/connection');
class Post extends Model {}
Post.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true,
},
post_title: {
type: DataTypes.TEXT,
allowNull: false
},
post_text: {
type: DataTypes.TEXT,
allowNull: true,
},
user_id: {
type: DataTypes.INTEGER,
references: {
model: 'user',
key: 'id'
}
},
date_posted: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
}
},
{
sequelize,
timestamps: false,
freezeTableName: true,
underscored: true,
modelName: 'post',
}
)
module.exports = Post;
Here is the Comment model
const { Model, DataTypes } = require('sequelize');
const sequelize = require('sequelize');
class Comment extends Model {}
Comment.init(
{
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
comment_text: {
type: DataTypes.TEXT,
allowNull: false
},
post_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'post',
key: 'id'
}
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'user',
key: 'id'
}
}
},
{
sequelize,
timestamps: false,
freezeTableName: true,
underscored: false,
modelName: 'comment'
}
)
module.exports = Comment;
Here is the index for the Models
const User = require('./User');
const Post = require('./Post');
const Comment = require('./Comment')
User.hasMany(Post, {
foreignKey: 'user_id'
});
Post.belongsTo(User, {
foreignKey: 'user_id',
});
Comment.belongsTo(User, {
foreignKey: 'user_id'
});
Comment.belongsTo(Post, {
foreignKey: 'post_id'
});
User.hasMany(Comment, {
foreignKey: 'user_id'
});
Post.hasMany(Comment, {
foreignKey: 'post_id'
});
module.exports = { User, Post, Comment};
Wow so dumb. I needed to change the sequelize variable to require the connection
const sequelize = require('../config/connection');
Case: I have 2 tables; one for users and one for assignments. A user can have many assignments and an assignment can be assigned to many users. I have a form in the frontend to add assignment and assign the users for the assignment and I am really confused on how to add the assignment and user to the joint table 'user_assignment'. Can someone point where I am having the mistake? Also for this, I refer to Advanced M:N Associations.
I also attach my code for the Users and Assignments model, and other relevant code parts.
user.model.js
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define("users", {
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: {
type: DataTypes.STRING,
allowNull: false,
},
department: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
role: {
type: DataTypes.STRING,
allowNull: false,
},
});
return User;
};
assignment.model.js
module.exports = (sequelize, DataTypes) => {
const Assignment = sequelize.define("assignments", {
title: {
type: DataTypes.STRING,
allowNull: false,
},
department: {
type: DataTypes.STRING,
allowNull: false,
},
urgency: {
type: DataTypes.STRING,
allowNull: false,
},
assignmentBegin: {
type: DataTypes.STRING,
allowNull: false,
},
assignmentEnd: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.STRING,
allowNull: false,
},
});
return Assignment;
};
database/index.js
...
db.user = require("../models/user.model")(sequelize, Sequelize);
db.assignment = require("../models/assignment.model")(sequelize, Sequelize);
...
db.user.belongsToMany(db.assignment, {
through: "user_assignment",
as: "assignments",
foreignKey: "userId",
});
db.assignment.belongsToMany(db.user, {
through: "user_assignment",
as: "users",
foreginKey: "assignmentId",
});
...
assignment.controller.js
const db = require("../database");
const Assignment = db.assignment;
const User = db.user;
exports.create = async (req, res) => {
const {
participant,
title,
department,
urgency,
assignmentBegin,
assignmentEnd,
description,
} = req.body;
await Assignment.create({
title: title,
department: department,
urgency: urgency,
assignmentBegin: assignmentBegin,
assignmentEnd: assignmentEnd,
description: description
}).then(async result => {
for (i = 0; i < participant.length; i++) {
const user = await User.findByPk(participant[i])
// console.log(user.id)
await UserController.addAssignment(user.id, result.id);
// await UserController.addAssignment(2, 1)
}
}).catch(err => {
res.json({ message: "ERROR WHILE CREATING ASSIGNMENT!" });
console.log(">>> ERROR WHILE CREATING ASSIGNMENT!")
});
}
Any pointers on what I should do would be great!
I'd recommend you define the model associations inside each of the model files. Also you should hash/encrypt your passwords before saving them to the DB, you can use the .comparePassword() function outside of the model in a controller when logging in etc.
models/User.js
const Promise = require('bluebird')
const bcrypt = Promise.promisifyAll(require('bcrypt'))
function hashPassword (user) {
const SALT_FACTOR = 12
if (!user.changed('password')) {
return;
} else {
user.setDataValue('password', bcrypt.hashSync(user.password, SALT_FACTOR))
}
}
module.exports = User = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: {
type: DataTypes.STRING,
allowNull: false,
},
department: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
role: {
type: DataTypes.STRING,
allowNull: false,
},
{
hooks: {
beforeCreate: hashPassword,
beforeUpdate: hashPassword
}
})
User.associate = models => {
User."Association type here"(models."Model to associate",
{Options (For many to many add your "through" table here)}
)
// Example:
User.belongsToMany(models.Assignment, {
through: "UserAssignment"
})
}
User.prototype.comparePassword = function (password) {
return bcrypt.compareSync(password, this.password)
}
return User
}
And in the associated Model (models/Assignment.js):
module.exports = Assignment = (sequelize, DataTypes) => {
const Assignment = sequelize.define('Assignment', {
title: {
type: DataTypes.STRING,
allowNull: false,
},
department: {
type: DataTypes.STRING,
allowNull: false,
},
urgency: {
type: DataTypes.STRING,
allowNull: false,
},
assignmentBegin: {
type: DataTypes.STRING,
allowNull: false,
},
assignmentEnd: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
timestamps: false
})
Assignment.associate = models => {
Assignment.belongsToMany(models.User, {
through: "UserAssignment"
})
}
return Role
}
The joint table (models/UserAssignment.js):
module.exports = UserAssignment = (sequelize, DataTypes) => {
const UserAssignment = sequelize.define('UserAssignment', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
}
},
{
timestamps: false
})
return UserAssignment
}
And finally my index.js file (models/index.js), it programatically adds the models to the DB:
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0)
&& (file !== basename)
&& (file.slice(-3) === '.js');
})
.forEach(file => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
As an extra note, you can shorten down your createAssignment function in your controller by doing this instead:
const {
participant,
title,
department,
urgency,
assignmentBegin,
assignmentEnd,
description,
} = req.body;
await Assignment.create({
title: title,
department: department,
urgency: urgency,
assignmentBegin: assignmentBegin,
assignmentEnd: assignmentEnd,
description: description
}).then(async result => {
result.addUsers(participant)
}).catch(err => {
res.json({ message: "ERROR WHILE CREATING ASSIGNMENT!" });
console.log(">>> ERROR WHILE CREATING ASSIGNMENT!")
});
Hope this helps, if not lmk ill try to help some more.
I am making a web application which is similar to 'Twitter'.
When I ran the server,
'user is associated to user multiple times. To identify the correct association,
You must use the 'as' keyword to specify the alias of the association you want to include.'
<- this message appeared.
I applied 'as' keyword for the relationship between 'followers' and 'followings'.
but the error message kept on appearing.
I'm sure that I did something wrong in someway, but I can't figure out what exactly it is.
can somebody help me?
models/index.js
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.User = require('./user')(sequelize, Sequelize);
db.Post = require('./post')(sequelize, Sequelize);
db.Hashtag = require('./hashtag')(sequelize, Sequelize);
db.User.hasMany(db.Post); //1 : n
db.Post.belongsTo(db.User);
// m: n
db.Post.belongsToMany(db.Hashtag, { through: 'PostHashtag' });
db.Hashtag.belongsToMany(db.Post, { through: 'PostHashtag' });
// I use alias here *****
db.User.belongsToMany(db.User, {
foreignKey: 'followingId',
as: 'Followers',
through: 'Follow',
});
db.User.belongsToMany(db.User, {
foreignKey: 'followerId',
as: 'Followings',
through: 'Follow',
});
module.exports = db;
models/user.js
module.exports = (sequelize, DataTypes) => (
sequelize.define('user', {
email: {
type: DataTypes.STRING(40),
allowNull: true,
unique: true,
},
nick: {
type: DataTypes.STRING(15),
allowNull: false,
},
password: {
type: DataTypes.STRING(100),
allowNull: true,
},
provider: {
type: DataTypes.STRING(10),
allowNull: false,
defaultValue: 'local',
},
snsId: {
type: DataTypes.STRING(30),
allowNull: true,
},
}, {
timestamps: true,
paranoid: true,
})
);
models/post.js
module.exports = (sequelize, DataTypes) => (
sequelize.define('user', {
email: {
type: DataTypes.STRING(40),
allowNull: true,
unique: true,
},
nick: {
type: DataTypes.STRING(15),
allowNull: false,
},
password: {
type: DataTypes.STRING(100),
allowNull: true,
},
provider: {
type: DataTypes.STRING(10),
allowNull: false,
defaultValue: 'local',
},
snsId: {
type: DataTypes.STRING(30),
allowNull: true,
},
}, {
timestamps: true,
paranoid: true,
})
);
models/hashtag.js
module.exports = (sequelize, DataTypes) => (
sequelize.define('hashtag', {
title: {
type: DataTypes.STRING(15),
allowNull: false,
unique: true,
},
}, {
timestamps: true,
paranoid: true,
})
);
I think this will solve your problem you have to create a table follower than associate it with user table with following and follower alias and use it to query follower and following
follower Model
module.exports = (sequelize, datatypes) => {
sequelize.define('follower', {
_id: {
type: datatypes.integer,
allownull: false,
primarykey: true,
autoincrement: true
},
userid: {
type: datatypes.integer,
allownull: false
},
followingid: {
type: datatypes.integer,
allownull: false
}
});
}
association
db.follower.belongsTo(db.user, {
as: 'following',
foreignkey: 'followingid'
});
db.follower.belongsto(db.user, {
as: 'follower',
foreignkey: 'userid'
});
query to get follower
follower.findall({
where: {
followingid: userid
},
attributes: ['_id'],
include: [{
model: user, attributes:
['fullname', 'username', '_id', 'picture'],
as: 'follower'
}]
})
I use sequelize ORM in Mysql. I have 3 Models: Product, Collection, CollectionProduct
relationship between Product and Collection are many to many and for handle this in sequelize i used belongsToMany association. every thing is Ok but when i run this code to get a collection with its products with include Eager this error occure:
SequelizeEagerLoadingError: product is not associated to collection!
Product Model:
module.exports = (sequelize, Sequelize) => {
const Product = sequelize.define('product', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name_en: {
type: Sequelize.STRING(255),
},
description_en: {
type: Sequelize.STRING(1024),
},
price: {
type: Sequelize.FLOAT,
allowNull: false,
},
type: {
type: Sequelize.STRING(255),
},
height: {
type: Sequelize.INTEGER,
},
width: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {})
Product.associate = (models) => {
Product.belongsToMany(models.collection, { through: models.collectionProduct, as: 'collections', foreignKey: 'productId' })
}
return Product
}
Collection Model :
module.exports = (sequelize, Sequelize) => {
const Collection = sequelize.define(
'collection', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true,
},
name_en: {
type: Sequelize.STRING(255),
},
itemsCount: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {},
)
Collection.associate = (models) => {
Collection.belongsToMany(models.product, { through: models.collectionProduct, as: 'products', foreignKey: 'collectionId' })
}
return Collection
}
CollectionProduct Model:
module.exports = (sequelize, Sequelize) => {
const CollectionProduct = sequelize.define('collectionProduct', {
collectionId: {
type: Sequelize.INTEGER,
},
productId: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {})
CollectionProduct.associate = (models) => {}
return CollectionProduct
}
routes/collection.js
const express = require('express')
const router = express.Router()
const Collection = require('../../controllers/collectionController')
router.get('/:id', async (req, res) => {
const { id: collectionId } = req.params
const collection = await Collection.getOne(collectionId)
return collection
}
collectionController
const db = require('../models/index')
const Collection = db.collection
const Product = db.product
const getOne = async (collectionId) => {
const collection = await Collection.findByPk(collectionId, {
include: {
model: Product,
as: 'products',
attributes: ['id', 'name_en'],
},
})
return collection
}
I found my problem. in collectionController i used model: Product
and Product should be a sequelize model. but in my code this is a function that have been called in models/index. so i changed my calling and pass a sequelize model to getOne