I'm new to using Sequelize and for that I strictly follow the documentation here. It is written that we must use hasOne(), hasMany(), belongsTo() in order to add automatically the foreign keys. In my situation: I have a Category and a FAQ model, defined so:
Category.js
const { Sequelize } = require('sequelize');
const sequelize = require('../database/connection');
const Category = sequelize.define('Category', {
id: {
type: Sequelize.DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
categoryShop_id: {
type: Sequelize.DataTypes.UUID,
allowNull: true
},
name: {
type: Sequelize.DataTypes.STRING,
allowNull: false
},
active: {
type: Sequelize.DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
},
parent_id: {
type: Sequelize.DataTypes.INTEGER,
allowNull: true
}
});
Category.associate = (models) => {
Category.hasMany(models.faqs, {
onDelete:'CASCADE',
onUpdate:'CASCADE'
});
};
module.exports = Category;
Faq.js
const { Sequelize } = require('sequelize');
const sequelize = require('../database/connection');
const Faq = sequelize.define('Faq', {
id: {
type: Sequelize.DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
question: {
type: Sequelize.DataTypes.TEXT,
allowNull: false
},
answer: {
type: Sequelize.DataTypes.TEXT,
allowNull: false
},
product_id: {
type: Sequelize.DataTypes.STRING,
allowNull: true
},
active: {
type: Sequelize.DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
}
});
Faq.associate = (models) => {
Faq.belongsTo(models.categories, {
foreignKey: {
name: 'category_id',
allowNull: true
}
});
};
module.exports = Faq;
The migrations run without any errors, but I don't see the added columns to the table. What is the reason for this?
Your confusing model and migration code. Your migrations are ok, but lack the right foreign key columns for your associations.
Your association code looks ok but it belongs in your model.
Look at https://sequelizeui.app/ for some example code.
Related
I have three tables companies, subscriptions and companySubscription. As name defined company can canbuy/have plan or one subscription belongs to many companies.
So in model/schema I have defined as follows:
companies.js
const sequelize = require("../utils/database");
const bcrypt = require("bcrypt");
const { DataTypes, Model } = require("sequelize");
const subscription = require("./subscriptions");
const CompanySubscription = require("./companySubscription");
class companies extends Model {}
companies.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
contactNo: {
type: DataTypes.STRING,
allowNull: true,
},
companySize: {
type: DataTypes.INTEGER,
allowNull: true,
},
},
{ sequelize, modelName: "companies" }
);
subscription.belongsToMany(companies, { through: CompanySubscription });
module.exports = companies;
subscription.js
const sequelize = require("../utils/database");
const { DataTypes, Model } = require("sequelize");
class subscription extends Model {}
subscription.init(
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
subscriptionPlanType: {
type: DataTypes.ENUM,
values: ["Yearly", "Monthly"],
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
memberCount: {
type: DataTypes.INTEGER,
allowNull: false,
},
amount: {
type: DataTypes.FLOAT,
allowNull: false,
},
},
{ sequelize, modelName: "subscription" }
);
module.exports = subscription;
companySubscription.js
const sequelize = require("../utils/database");
const companies = require("./companies");
const subscription = require("./subscriptions");
const { DataTypes, Model } = require("sequelize");
class CompanySubscription extends Model {}
CompanySubscription.init(
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
status: {
type: DataTypes.ENUM,
values: ["active", "inactive"],
},
subscriptionType: {
type: DataTypes.ENUM,
values: ["Yearly", "Monthly"],
},
subscriptionPlanStartDate: {
type: DataTypes.DATE,
},
subscriptionPlanEndDate: {
type: DataTypes.DATE,
},
paidStatus: {
type: DataTypes.ENUM,
values: ["paid", "unpaid"],
},
paidDate: {
type: DataTypes.DATE,
},
},
{ sequelize, modelName: "CompanySubscription" }
);
module.exports = CompanySubscription;
In controller file I am able to manage to insert the data. Below is the code:
const addBIlling = async (req, res) => {
const foundSubcscription = await subscription.create({
subscriptionPlanType: "Monthly",
name: "s1",
memberCount: 15,
amount: 50.55,
});
const foundCompany = await companies.create({
name: "company1",
email: "company1#gmail.com",
contactNo: "87964644",
companySize: 20,
});
const insertedData = await foundSubcscription.addCompany(foundCompany, {
through: {
status: "active",
paidStatus: "paid",
subscriptionType: "Monthly",
subscriptionPlanEndDate: moment().add(1, "months"),
paidDate: moment().add(1, "months"),
},
});
console.log("inserted data ", insertedData);
res.json({ data: insertedData });
};
Now I want to fetch the records from db as which company has bought which subscription plan!
i.e. company name, subscription plan and its active and paid status and plan's expiry date.
I tried below code:
const billingList = async (req, res) => {
const billingData = await CompanySubscription.findAll({
include: [{ model: companies }],
});
console.log("billing data ", billingData);
};
Above code is throwing error "companies is not associated to CompanySubscription!".
Where have I made a mistake?
Don't try to import models to each other's modules directly. Define model registration functions in each model module and use them all to register models in one place/module and for associations you can define associate function inside each registration function and call them after ALL your models are already registered. That way you won't have cyclic dependencies and all associations will be correct.
See my answer here to get an idea how to do it.
I have two models in which one is Question and other is Answer, each answer has one question_id and question can have more then one answers.
I want to include all the answers of each question in my json response but I am keep getting an error
"message": "answer is not associated to question!"*
Below is the Question model:-
module.exports = (sequelize, Sequelize) => {
const Question = sequelize.define("question", {
question_id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
question_no: {
type: Sequelize.DOUBLE,
allowNull: false
},
question_text: {
type: Sequelize.STRING,
allowNull: false
},
question_text: {
type: Sequelize.STRING,
allowNull: false
},
question_required: {
type: Sequelize.BOOLEAN,
},
formpage_no: {
type: Sequelize.DOUBLE,
allowNull: false
},
med_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'medforms',
key: 'med_id'
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
med_name: {
type: Sequelize.STRING,
allowNull: true
},
version_no: {
type: Sequelize.STRING,
allowNull: false
}
}, {
freezeTableName: false, // true: if we want to make table name as we want else sequelize will make them prural
underscored: true // underscored: true indicates the the column names of the database tables are snake_case rather than camelCase
});
Question.associate = function (models) {
Question.hasMany(models.answer, {
foreignKey: 'question_id',
as: 'answers'
});
Question.hasMany(models.helpbox, {
foreignKey: 'question_id',
as: 'helpboxes'
});
// in future each question could have more than one document text
};
return Question;
};
And below is my answer model:-
module.exports = (sequelize, Sequelize) => {
const Answer = sequelize.define("answer", {
answer_id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
question_id: { // each answer has one questionId
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'questions',
key: 'question_id'
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
},
question_no: {
type: Sequelize.DOUBLE,
allowNull: true
},
answer_no: {
type: Sequelize.DOUBLE,
allowNull: true
},
answer_text: {
type: Sequelize.STRING,
allowNull: false
},
answer_icon: {
type: Sequelize.STRING,
allowNull: true
},
answer_reply: {
type: Sequelize.STRING,
allowNull: true
},
answer_logic: {
type: Sequelize.STRING,
allowNull: true
},
med_name: {
type: Sequelize.STRING,
allowNull: true
},
version_no: {
type: Sequelize.STRING,
allowNull: false
},
}, {
freezeTableName: false, // true: if we want to make table name as we want else sequelize will make them prural
underscored: true // underscored: true indicates the the column names of the database tables are snake_case rather than camelCase
});
Answer.associate = function (models) {
Answer.belongsTo(models.question, {
as: 'questions'
});
// in future each question could have more than one document text
};
return Answer;
};
below is the index.js class:-
var Sequelize = require('sequelize');
var env = process.env.NODE_ENV || 'development';
var config = require("../config/config.json")[env];
var db = {};
if (config.use_env_variable) {
var sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
var sequelize = new Sequelize(config.database, config.username, config.password, config);
}
db.Sequelize = Sequelize;
db.sequelize = sequelize;
// Models
db.medform = require("./medform.model.js")(sequelize, Sequelize);
db.version = require("./version.model.js")(sequelize, Sequelize);
db.question = require("./question.model.js")(sequelize, Sequelize);
db.helpbox = require("./helpbox.model.js")(sequelize, Sequelize);
db.answer = require("./answer.model.js")(sequelize, Sequelize);
db.document = require("./document.model.js")(sequelize, Sequelize);
module.exports = db;
This is my question controller
// Retrieve Question including answers from the database:
exports.getAllQuesData = (req, res) => {
const version_no = req.query.version_no;
const med_id = req.query.med_id;
var condition = [{ "version_no": version_no }, { "med_id": med_id }];
Question.findAll({
include: [
{
model: answer,
as: 'answers'
}
],
where: condition
})
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving questions."
});
});
};
Please help me what I am doing wrong why my associations are not working
You didn't register model associations. See my answer how to do it
Object.keys(db).forEach(function (modelName) {
if (db[modelName].associate) {
db[modelName].associate(db)
}
})
'use strict';
module.exports = (sequelize, type) => {
const article_comment = sequelize.define('article_comments', {
// attributes
id: {
type: type.INTEGER,
primaryKey: true,
autoIncrement: true
},
positive_rating:{
type: type.INTEGER,
allowNull: false
},
negative_rating:{
type: type.INTEGER,
allowNull: false
},
comment:{
type: type.STRING,
allowNull: false
},
updatedAt:{
type: type.STRING,
allowNull: false
},
createdAt:{
type: type.STRING,
allowNull: false
},
}, {});
article_comment.associate = function(models) {
// associations can be defined here
article_comment.hasMany(models.article_comments_user_ratings,{foreignKey:'comment_id'});
article_comment.hasMany(models.article_replies,{foreignKey:'comment_id'});
};
return article_comment;
};
And my rating for comments
'use strict';
module.exports = (sequelize, type) => {
const article_comments_user_ratings = sequelize.define('article_comments_user_ratings', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: type.INTEGER
},
rating:{
type: type.BOOLEAN,
allowNull: false
},
createdAt: {
allowNull: false,
type: type.DATE
},
updatedAt: {
allowNull: false,
type: type.DATE
}
}, {});
article_comments_user_ratings.associate = function(models) {
// associations can be defined here
article_comments_user_ratings.belongsTo(models.article_comments)
};
return article_comments_user_ratings;
};
However, when I use the findOrCreate method, it only does INSERT INTO "article_comments_user_ratings" ("id","rating","createdAt","updatedAt"). Which obviously is failing because In the database I also have the additional columns of user_id and comment_id for the article_comments_user_ratings table.
This isn't making any sense because with the sync() function, prior to moving to migrations, it was working.
I don't know what to do?
I fixed this issue by defining the associations after defining the model.
Example:
const User = UserModel(sequelize, Sequelize)
const Comment = CommentsModel(sequelize, Sequelize)
User.hasMany(UserCommentRating,{foreignKey:'user_id'})
Comment.hasMany(UserCommentRating,{foreignKey:'comment_id'})
It seems that the assocations inside the model is deprecated.
I am trying to associate two tables in Sequelize but I am getting the SequelizeEagerLoadingError that one table is not associated to another despite trying all the available fixes on this platform.
I have two tables, User and Item.
User (user.js)
const User = dbconnection.sequelize.define('users', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true},
name: {
type: Sequelize.STRING(80),
allowNull: false
},
email: {
type: Sequelize.STRING(120),
allowNull: false,
unique: true
},
dob: {
type: Sequelize.DATEONLY,
allowNull: false
},
password: {
type: Sequelize.STRING(256),
allowNull: false
}
});
User.associate = models => {
User.hasMany(models.Item, { as: 'items',foreignKey: 'user_id' })
}
dbconnection.sequelize.sync({ force: false })
.then(() => {
//console.log('Table created!')
});
module.exports = {
User
};
Item (item.js)
const Item = dbconnection.sequelize.define('items', {
id: { type: Sequelize.INTEGER, unique: true, autoIncrement: true, primaryKey: true},
item: {
type: Sequelize.STRING(80),
allowNull: true
},
item_type: {
type: Sequelize.STRING(10),
allowNull: false
},
comment: {
type: Sequelize.STRING(1000),
allowNull: true
},
user_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: { model: 'users', key: 'id' }
},
});
Item.associate = models => {
Item.belongsTo(models.User, { as: 'users',foreignKey: 'user_id' })
}
dbconnection.sequelize.sync({ force: false })
.then(() => {
// console.log('Table created!')
})
});
module.exports = {
Item
};
User hasMany(Item) while Item belongsTo(User) as shown above.
However, when I make a query to the Item table (as below),
const usersdb = require('./userdb')
const itemsdb = require('./itemdb')
class ItemsController {
static async getAllItems(req, res, next) {
try{
let allitems = await itemsdb.Item.findAll({
include: [{
model: usersdb.User
}]
})
return {items: allitems, status: true}
}
catch (e) {
return {items: e, status: false}
}
}
}
module.exports = ItemsController;
I get the SequelizeEagerLoadingError that "users is not associated to items!"
I have tried all the available fixes including this and this among others but to no success.
I have finally found a workaround. First, I dropped the tables and discarded the model definitions. Second, I generated migrations and models using the sequelize model:create --name ModelName --attributes columnName:columnType command. I then used the generated models to associate the two tables just as I had done earlier. Lastly, I ran the sequelize db:migrate command to create the tables and on running the query, it worked!
Earlier, I was creating the models manually. I was also creating the tables using the sequelize.sync({force: false/true}) command after loading the models.
User Model (user.js)
'use strict';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes(120),
allowNull: false,
unique: true
},
dob: {
type: DataTypes.DATEONLY,
allowNull: false
},
password: {
type: DataTypes.STRING(256),
allowNull: false
}
}, {});
User.associate = function(models) {
User.hasMany(models.Item, {as: 'Item', foreignKey: 'user_id'})
};
return User;
};
Item model (item.js)
'use strict';
module.exports = (sequelize, DataTypes) => {
const Item = sequelize.define('Item', {
item: {
type: DataTypes.STRING(80),
allowNull: true
},
item_type: {
type: DataTypes.STRING(10),
allowNull: false
},
comment: {
type: DataTypes.STRING(1000),
allowNull: true
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: { model: 'User', key: 'id' }
}
}, {});
Item.associate = function(models) {
Item.belongsTo(models.User, { as: 'User',foreignKey: 'user_id' })
};
return Item;
};
Query (queryitem.js)
const Item = require('../models').Item
const User = require('../models').User
class ItemsController {
static async getAllItems() {
try{
let allitems = await Item.findAll({
include: [{
model: User,
as: 'User'
}]
})
return {items: allitems, status: true}
}
catch (e) {
return {items: e, status: false}
}
}
}
module.exports = ItemsController;
I am running a simple query on two tables which are supposed to be associated, but I keep getting the following message:
item_translation is not associated to item!
Basically item_translation is supposed to belong to item. According to the docs, I have done everything correctly. Here are the models:
ItemTranslation model:
module.exports = function () {
return function (app) {
/** #type {Sequelize.Sequelize} */
const sequelize = app.get('sequelize')
const ItemTranslation = sequelize.define('item_translation', {
_id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
sourceId: {
type: Sequelize.STRING,
allowNull: false,
references: {
model: 'item',
key: '_id'
},
onDelete: 'cascade',
onUpdate: 'cascade'
},
text: {
type: Sequelize.STRING,
allowNull: false
}
}, {
freezeTableName: true
})
ItemTranslation.associate = function () {
ItemTranslation.belongsTo(sequelize.models.item)
}
}
}
Item Model:
module.exports = function () {
return function (app) {
/** #type {Sequelize.Sequelize} */
const sequelize = app.get('sequelize')
sequelize.define('item', {
_id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
text: {
type: Sequelize.TEXT,
allowNull: true
}
}, {
freezeTableName: true
})
}
}
Have I missed something?
I'm not sure but try this. I always explicitly define the foreign key.Some thing like this.
ItemTranslation.belongsTo(sequelize.models.item,{foreignKey:'sourceId'})
Item.associate = function () {
Item.hasMany(sequelize.models.ItemTranslation,{foreignKey:'sourceId'})
}