Generated table using belongstomany is not associated with any table - javascript

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.

Related

Column Cannot be NULL even if value is defined

I'm trying to seed data into a database and I'm getting this error:
name: 'SequelizeDatabaseError',
parent: Error: Column 'id' cannot be null
code: 'ER_BAD_NULL_ERROR',
errno: 1048,
sqlState: '23000',
sqlMessage: "Column 'id' cannot be null"
Here is the index to seed the data:
const seedUsers = require('./user-seeds');
const seedPosts = require('./post-seeds');
const seedComments = require('./comment-seeds');
const seedVotes = require('./vote-seeds');
const sequelize = require('../config/connection');
const seedAll = async () => {
await sequelize.sync({ force: true });
console.log('--------------');
await seedUsers();
console.log('--------------');
await seedPosts();
console.log('--------------');
await seedComments();
console.log('--------------');
await seedVotes();
console.log('--------------');
process.exit(0);
};
seedAll().catch(err => console.log('seedAll error: ', err));
the error seems to be thrown when seedPost() is called,
the following is the corresponding model:
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/connection');
// create Post Model
class Post extends Model {
static upvote(body, models) {
return models.Vote.create({
user_id: body.user_id,
post_id: body,post_id
}).then(() => {
return Post.findOne({
where: {
id: body.post_id
},
attributes: [
'id',
'post_url',
'title',
'created_at',
[sequelize.literal('(SELECT COUNT(*) FROM vote WHERE post.id = vote.post_id)'), 'vote_count']
],
include: [
{
model: models.Comment,
attributes: ['id', 'comment_text', 'post_id', 'user_id', 'created_at'],
include: {
model: models.User,
attributes: ['username']
}
}
]
});
});
}
}
// create field/column for Post model
Post.init(
{
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoincrement: true
},
title: {
type: DataTypes.STRING,
allowNull: false
},
post_url: {
type: DataTypes.STRING,
allowNull: false,
validate: {
isURL: true
}
},
user_id: {
type: DataTypes.INTEGER,
references: {
model: 'user',
key: 'id'
}
}
},
{
sequelize,
freezeTableName: true,
underscored: true,
modelName: 'post'
}
);
module.exports = Post;
this is what my seed file looks like:
const { Post } = require('../models');
const postdata = [
{
title: 'Donec posuere metus vitae ipsum.',
post_url: 'https://buzzfeed.com/in/imperdiet/et/commodo/vulputate.png',
user_id: 10
},
{
// ... more seeds
}
];
const seedPosts = () => Post.bulkCreate(postdata);
module.exports = seedPosts;
I'm not sure what I'm doing wrong, any help is greatly appreciated!
// create field/column for Post model
Post.init(
{
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoincrement: true
},
In your Post.init, autoincrement must be autoIncrement. Maybe in your case you'll need to recreate the table

Sequelize: Foreign key declared, but does not appear in the table

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.

how to use transactions in sequelize?

I have written two classes and migrations files for MySQL database using sequelize.
how can I save the user and his children using transactions in node.js? I want to create, a class where I can encapsulate all the database communications in one file and then call it from my CRUD methods.
user class :
'use strict';
module.exports = function(sequelize, DataTypes) {
const User = sequelize.define('User', {
id : {
type: DataTypes.INTEGER(11),
allowNull: false,
autoIncrement:true,
primaryKey:true
},
firstName : {
type: DataTypes.STRING(50),
allowNull: false
},
lastName : {
type: DataTypes.STRING(50),
allowNull: false
},
dateOfBirth : {
type: DataTypes.DATE,
allowNull: false
}
});
return User;
};
children class :
'use strict';
module.exports = function(sequelize, DataTypes) {
const Children= sequelize.define('Children', {
id : {
type: DataTypes.INTEGER(11),
allowNull: false,
autoIncrement:true,
primaryKey:true
},
userId : {
type: DataTypes.INTEGER(11),
allowNull: true,
references : {
model : 'Users',
key:'id'
}
},
status : {
type: DataTypes.BOOLEAN,
allowNull: false,
defaulValue: false
},
firstName : {
type: DataTypes.STRING(50),
allowNull: false
},
lastName : {
type: DataTypes.STRING(50),
allowNull: false
},
dateOfBirth : {
type: DataTypes.DATE,
allowNull: false
}
});
return Children;
};
Try :
let transaction;
try {
// get transaction
transaction = await sequelize.transaction();
//save here
User.build({
firstName: "John"
//other attributes
}).save().then(newUser => {
const id = newUser.id;
Children.build({
firstNames: "fsf"
userId: id // from newly created user
//other attributes
})
.save()
.then(children => console.log("svaed"))
}).catch(function(error) {
// error
});
// commit
await transaction.commit();
} catch (err) {
// Rollback transaction
if (transaction) await transaction.rollback();
}

Associate in Sequelize not working as intended

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;

Sequelize: TypeError: User.hasMany is not a function

I am having this weird behavior.
I have a User model, and a Client model. User has many Clients.
I am using this docs: http://docs.sequelizejs.com/manual/tutorial/associations.html
When I run the server, Sequelize throws TypeError: User.hasMany is not a function
Node version: 8.9.1
Dialect: postgres
Database version: Postgres 10
Sequelize version: 4.22.15
The following files are all in the same folder
user.js model
const Sequelize = require('sequelize');
const db = require('../index.js'); //This is an instance of new Sequelize(...)
const tableName = 'users';
const User = db.define('user', {
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
username: { //Username will be the email
type: Sequelize.STRING(80),
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
password: {
type: Sequelize.STRING,
allowNull: false,
validate: {
notEmpty: true
}
},
isAdmin: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
isActive: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
}
}, { tableName });
module.exports = User;
client.js model
'use strict'
const Sequelize = require('sequelize');
const db = require('../index.js');
const instanceMethods = {
toJSON() {
const values = Object.assign({}, this.get());
return values;
},
};
const Client = db.define('clients', {
ibid: {
type: Sequelize.BIGINT,
allowNull: true,
defaultValue: null
},
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
agreementSigned: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
totalBalance: {
type: Sequelize.DECIMAL(11,2),
allowNull: true,
defaultValue: null
},
currentAllocation: {
type: Sequelize.STRING,
allowNull: true,
defaultValue: null
}
}, { instanceMethods });
module.exports = Client;
index.js models
'use strict';
const User = require('./user')
const Client = require('./client');
User.hasMany(Client);
Client.belongsTo(User);
module.exports = {User, Client};
In the index.js,
you haven't exported the new sequelize instance you have initialised and thus it is not available to the client.js and user.js! the define function works on the sequelize instance object that you have created!
Also there is a circular dependency in the project which might create problem!
I tried your code and changed the structure and it works now! There might be another structures possible too but this one works for me!
1) Don't create a new instance of sequelize in the index.js rather create another file that will serve as initialisation for the sequelize instance!
sequelize_index.js (I have used this file for creating a base instance and then using this base instance in both the client and user models)
const Sequelize = require('sequelize');
const dbconfig=require('./dbconfig.json');
const sequelize = new Sequelize('postgres://' + dbconfig.USER + ":" + dbconfig.PASSWORD + "#" + dbconfig.HOST + ":5432/" + dbconfig.DB, {
host: dbconfig.HOST,
dialect: dbconfig.DIALECT,
pool: {
min: 0,
max: 5,
idle: 1000
}
});
module.exports={sequelize};
2) The client.js would look something like this!
'use strict'
const Sequelize = require('sequelize');
const sequelize=require('./sequelize_index').sequelize;
const db = require('./index.js');
const instanceMethods = {
toJSON() {
const values = Object.assign({}, this.get());
return values;
},
};
const Client = sequelize.define('clients', {
ibid: {
type: Sequelize.BIGINT,
allowNull: true,
defaultValue: null
},
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
agreementSigned: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
totalBalance: {
type: Sequelize.DECIMAL(11,2),
allowNull: true,
defaultValue: null
},
currentAllocation: {
type: Sequelize.STRING,
allowNull: true,
defaultValue: null
}
}, { instanceMethods });
module.exports = Client;
3) User.js
const Sequelize = require('sequelize');
const sequelize=require('./sequelize_index').sequelize;
const db = require('./index.js'); //This is an instance of new Sequelize(...)
const tableName = 'users';
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
username: { //Username will be the email
type: Sequelize.STRING(80),
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
password: {
type: Sequelize.STRING,
allowNull: false,
validate: {
notEmpty: true
}
},
isAdmin: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
isActive: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
}
}, { tableName });
module.exports = User;
4) index.js
'use strict';
const sequelize = require('./sequelize_index').sequelize;
const User = require('./user')
const Client = require('./client');
User.hasMany(Client);
Client.belongsTo(User);
sequelize.sync({force: false}).then(function () {
console.log("Database Configured");
});
module.exports = {User, Client};
After running the index.js, the database would be created!

Categories