Try to create HABTM connection Sequelize.js - node.js

I'm trying to create a HABTM relationship with Sequelize but I can't get it done.... I still receive an error message:
return (tableName1.toLowerCase() < tableName2.toLowerCase()) ? (tableName1
^
TypeError: Cannot call method 'toLowerCase' of undefined
I have a User model, a Book model and an UserBooks model. And ofcourse my database contains a "users" table, "user_books" table and "books" table.
UserBooks model:
module.exports = function(schema, DataTypes) {
var UserBooks = schema.define('UserBooks', {
}, {
tableName: 'user_books', // this will define the table's name
timestamps: false // this will deactivate the timestamp columns
});
UserBooks.sync();
return UserBooks;
};
User model:
module.exports = function(schema, DataTypes) {
var User = schema.define('User', {
keywords: DataTypes.STRING
}, {
tableName: 'users', // this will define the table's name
timestamps: false ,// this will deactivate the timestamp columns
syncOnAssociation:false
});
User.hasMany(Book, { foreignKey: 'user_id', through: UserBooks });
User.sync();
return User;
};
Book model:
module.exports = function(schema, DataTypes) {
var Book = schema.define('Book', {
keywords: DataTypes.STRING
}, {
tableName: 'books', // this will define the table's name
timestamps: false ,// this will deactivate the timestamp columns
syncOnAssociation:false
});
Book.hasMany(User, { foreignKey: 'book_id', through: UserBooks });
Book.sync();
return Book;
};

In your User model you are trying to create an association with a model that is not defined in that scope. In User.js, you only have access to User, not Book or UserBooks which are undefined. Thats whats causing your error.
You can either create associations in the place where you import all your models into your app, or in the models file by importing the models you want to associate with (bevare of circular imports). Your user model could be changed to:
module.exports = function(schema, DataTypes) {
var Book = schema.import(__dirname + '/book');
var UserBooks = schema.import(__dirname + '/userbooks');
var User = schema.define('User', {
keywords: DataTypes.STRING
}, {
tableName: 'users', // this will define the table's name
timestamps: false ,// this will deactivate the timestamp columns
syncOnAssociation:false
});
User.hasMany(Book, { foreignKey: 'user_id', through: UserBooks });
Book.hasMany(User, { foreignKey: 'book_id', through: UserBooks });
return User;
};
For another example of how to do it, see http://sequelizejs.com/articles/express#minimal-express-app
Also, I've removed the call to User.sync from your code. Sync is an async call, while import is sync. This means that your are defining your model, starting to sync it to the DB, and then returning it, before you know that it has finished syncing. This means you could potentially be trying to work create instances with it before the table has been created. Instead, you should use sequelize.sync to sync all your models at once, and attach a callback to wait for the sync to finish (see the link I posted for a code example)

Related

Handling multiple tables reference Id in a single column in PostgreSQL

In the PostgreSQL database, I want to manage a History table that relates to multiple modules in the application. It contains a 'common_id' field which stores the reference ids of each module, ie; different tables.
eg: If I am creating the history related to 3 tables. Profile, Event, Settings the history table will contain info as follows.
Common_id | Type
user_id | Profile
event_id | Event
settings_id | Settings
And I need to query the data based on each Id. Currently, PostgreSQL creates a default foreign key reference to one of the related tables and it causes errors while inserting into other tables. Below is the code snippet.
Repository Function
createHistory: async ({ models }, args) => {
return await models.History.create(args);
},
Model
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class History extends Model {
static associate(models) {
History.belongsTo(models.Training, {
foreignKey: 'common_id',
as: 'trainingId',
});
History.belongsTo(models.Club, {
foreignKey: 'club_id',
as: 'club',
});
History.belongsTo(models.User, {
foreignKey: 'created_by',
as: 'uid',
});
}
}
History.init(
{
message: DataTypes.STRING,
users_associated: DataTypes.ARRAY(DataTypes.INTEGER),
history_type: DataTypes.STRING,
},
{
timestamps: true,
sequelize,
paranoid: true,
modelName: 'History',
}
);
return History;
};

Sequelize doesn't read the new modelname after I do refactor (remove s in end modelname)

I've a backend app built in Express with Sequelize ORM.
Here is my code;
user.js (model)
'use strict';
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define('user', {
username: DataTypes.STRING,
}, {
// tableName: 'user'
});
user.associate = function(models) {
// associations can be defined here
};
return user;
};
user.js (controller):
const User = require('../models').user;
module.exports = {
getUser: function (req, res) {
User.findAll().then(value => {
res.json(value);
})
}
}
When I start the project, it return error Unhandled rejection SequelizeDatabaseError: relation "users" does not exist. As you can see my code above, I've set the model as user not users, and the table in db also user not users. It's only work fine if I add the tableName: 'user' in the model file.
NOTE: By the default, when I do create model with sequelize, the file name and model define is users, but I refactor file name and define inside model into user
Why does this happen?
This is default behavior - Sequelize automatically transforms model name to plural. In order to disable that you should freeze table name in model definition (or just set table name explicitly like you are actually doing):
freezeTableName: true,

Problem with Sequelize and specifying foreign key in an association

I have placements that belong to an App. The foreign_key on the placements table is appId (not AppId). I have specified as follows but get the error:
Unhandled rejection SequelizeDatabaseError: column Placements.AppId does not exist
My Placement Model:
'use strict';
const App = require('./').App
module.exports = (sequelize, DataTypes) => {
const Placement = sequelize.define('Placement', {
name: DataTypes.STRING,
isActive: DataTypes.BOOLEAN,
}, {
tableName: 'placements'
});
Placement.associate = function(models) {
Placement.belongsTo(models.App, { foreignKey: 'appId'})
// associations can be defined here
};
return Placement;
};
How do I tell Sequelize that the foreignKey is appId and not AppId?
Hmm... I don't see nothing wrong with your code. Which version of Sequelize are you using?
Just a couple of non-related comments:
You don't need to import App, it is already in models object.
I think you don't need tableName parameter either.
Try to use the field property
Placement.belongsTo(models.App, {
foreignKey: {
name: 'AppId',
field: 'appId'
}
}
)
You need to have the AppId columns present in App model. Explicitly passing { foreignKey: 'appId'}) to belongsTo makes Sequelize use the key as it is.
So you need to create an App model which has -
const App = sequelize.define('App', {
AppId: DataTypes.INTEGER,
..
}, {
tableName: 'App'
});
Another options would be to change this
Placement.belongsTo(models.App, { foreignKey: 'appId'})
to
Placement.belongsTo(models.App)
This way Sequelize automatically handles all relations between the models.

How to return the result set of sequelize query in camel case fashion?

I have defined a table schema in the database in an underscored fashion but I want to return the result set API response in camel case fashion. I know I can process the underscored object returned by sequelize and convert it into camelcase fashion. Is there any functionality to return the response of a query in camelcase fashion in sequelize itself?
To archieve this you need to use field when defining your model.
module.exports = (sequelize, DataTypes) => {
const yourTable = sequelize.define('yourTable', { // table name use it for Sequelize
camelCase: { //camelCase name that you'll use with sequelize.
field: 'under_score', //underscore name on yor database.
type: DataTypes.STRING
},
keyId: { //need to the same with association
field: 'key_id',
type: DataTypes.INTEGER
},
}, {
tableName: 'your_table', // then name of the table on the db
underscored: true,
});
yourTable.associate = (models) => {
yourTable.belongsTo(models.otherTable, {
as: 'Something',
foreignKey: 'key_id', //put attention here and keyId above.
onDelete: 'cascade'
});
}
}

sequelize selecting columns that are not mentioned in the model

I have 2 tables that are in a 1 to many relationship (course has many subjects), and before doing a delete operation on subject I want to check if it is associated with any course, so here are my models:
Course:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Course = sequelize.define('Course', {
name: DataTypes.STRING,
desc: DataTypes.TEXT
}, {});
Course.associate = function(models) {
Course.belongsToMany(models.Subject, {
through: 'courseSubjects'
});
Course.hasMany(models.Batch)
};
return Course;
};
and subject:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Subject = sequelize.define('Subject', {
name: DataTypes.STRING,
desc: DataTypes.TEXT
}, {});
Subject.associate = function(models) {
Subject.belongsToMany(models.Module, {
through: 'subjectModules'
});
Subject.belongsToMany(models.Course, {
through: 'courseSubjects',
});
};
return Subject;
};
So this is the statement I am calling:
res.status(200).send(subject.getCourses())
and getting error:
Executing (default): SELECT Course.id, Course.name, Course.desc, Course.createdAt, Course.updatedAt, Course.courseId, courseSubjects.createdAt AS courseSubjects.createdAt, courseSubjects.updatedAt AS courseSubjects.updatedAt, courseSubjects.CourseId AS courseSubjects.CourseId, courseSubjects.SubjectId AS courseSubjects.SubjectId FROM Courses AS Course INNER JOIN courseSubjects AS courseSubjects ON Course.id = courseSubjects.CourseId AND courseSubjects.SubjectId = 34;
[0] Unhandled rejection SequelizeDatabaseError: Unknown column 'Course.courseId' in 'field list'
I do not understand why is it trying to select 'courseId'.. Please help me resolve this.
You need to add relation into course table as well, it will remove the 'courseId' column from select.

Resources