Sequelize Association Error: A is not associated to B - node.js

I'm using Sequelize for my Postgres database. I have a Messages and a Users table; a user has many messages and a message belongs to a user. I've defined my models as follows:
User
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
}
},
password: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [8, 50],
}
},
}, {
modelName: 'User',
});
User.associate = (models) => {
User.hasMany(models.Message, { foreignKey: 'userId', as: 'Messages' })
}
return User;
};
Message
module.exports = (sequelize, DataTypes) => {
const Message = sequelize.define('Message', {
content: {
allowNull: false,
type: DataTypes.STRING,
validate: {
len: [1, 248],
}
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'Users',
key: 'id'
}
},
likes: {
defaultValue: 0,
type: DataTypes.INTEGER
},
}, {
modelName: 'Message',
});
Message.associate = (models) => {
Message.belongsTo(models.User, { foreignKey: 'userId', as: 'User', onDelete: 'CASCADE' })
}
return Message;
};
And here's how I'm testing them:
User.create({
firstName: 'Test', lastName: 'Test', email: 'test#test.com', password: '87654321'
}).then((newUser) => {
console.log(newUser.get())
})
Message.bulkCreate([
{ content: "Hello", likes: 0, userId: 1 },
{ content: "Hello World", likes: 0, userId: 1 },
{ content: "Hello World 2", likes: 123, userId: 1 }
])
.then((newMessages) => {
console.log(newMessages)
})
const findAllWithMessages = async () => {
const users = await User.findAll({
include: [{
model: Message
}]
});
console.log(JSON.stringify(users, null));
}
Here's my Migration file to create the users table:
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
}
},
password: {
type: Sequelize.STRING,
allowNull: false,
validate: {
len: [8, 50],
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Users');
}
};
And the messages table:
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Messages', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Users',
key: 'id',
as: 'userId',
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL',
},
content: {
allowNull: false,
type: Sequelize.STRING,
validate: {
len: [1, 248],
}
},
likes: {
defaultValue: 0,
type: Sequelize.INTEGER
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Messages');
}
};
I'm registering my models and associations using Sequelize CLI out of the box code when you run sequelize-cli init:
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);
}
});
const User = require('./user')(sequelize, Sequelize.DataTypes)
const Message = require('./message')(sequelize, Sequelize.DataTypes)
db.models = { User, Message }
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.DataTypes = Sequelize.DataTypes
module.exports = db;
Finally, when I run findAllWithMessages(), I'm getting this error UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: Message is not associated to User!
I can confirm that the models are being created and that the association between the models work because when I run a raw SQL query select * from "Messages" as a inner join "Users" as b on b.id = a."userId" where a."userId"=1; I get the correct results. So I'm assuming its a Sequelize thing.
Any help is appreciated!

I've found my issue. In the code I was importing from db.models = { User, Message } so this block Object.keys(db).forEach(modelName)... wasn't associating the models I was using. Essentially, I was calling the .associate function on instances of the models that were different than the instances I was using.

Related

How can I sequelize belongsToMany?

How can I belongsToMany two different columns in the same table with the ID in a different table?
User Model
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
firstName: {
type: DataTypes.STRING(255)
}
Message Model
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
userId1: {
type: DataTypes.UUID
},
userId2: {
type: DataTypes.UUID
}
belongsTo
thisModel.belongsTo(userModel, {
foreignKey: 'userId1',
foreignKey: 'userId2' // How can add this one here
})
Suppose your case is a message has a sender(userId1) and a receiver(userId2). Below code will work for this case:
const User = sequelize.define('user', {
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
firstName: {
type: DataTypes.STRING(255)
}
});
const Message = sequelize.define('message', {
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
text: {
type: DataTypes.STRING
},
userId1: {
type: DataTypes.UUID
},
userId2: {
type: DataTypes.UUID
}
});
// define the association
User.hasMany(Message, {
foreignKey: 'userId1',
as: 'sender'
})
User.hasMany(Message, {
foreignKey: 'userId2',
as: 'receiver'
})
Message.belongsTo(User, {
foreignKey: 'userId1',
as: 'sender'
});
Message.belongsTo(User, {
foreignKey: 'userId2',
as: 'receiver'
});
// Example using the association
sequelize.sync({
force: true
})
.then(async () => {
// create some users
await User.bulkCreate([
{ firstName: 'user1'},
{ firstName: 'user2'}
])
const users = await User.findAll()
const [user1, user2] = users
const message = await Message.create({
text: 'hello'
})
await message.setSender(user1)
await message.setReceiver(user2)
console.log(message)
})

Sequelize Node Js Seeder file with Many-to-Many Association

I would like to find out what is the right way to add a many-to-many relation when seeding records with sequelize-cli. Now I understand that the easiest way to do this is to create another seeder file and manually set the values but is there a way to make some changes to my 2_user seeder file so that when a user is seeded with some value given for the role it automatically makes a record in the user_roles table. So basically same as the user.setRoles() one can use but in the seeder files. Any help is much appreciated.
Models
user.model.js
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
static associate(models) {
User.belongsToMany(models.Role, {
through: 'user_roles',
foreignKey: 'user_id',
otherKey: 'role_id',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});
User.hasMany(models.User_Role);
User.hasMany(models.Address, {
foreignKey: 'user_id',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});
}
}
User.init(
{
user_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
email: DataTypes.STRING,
password: DataTypes.STRING,
bio: DataTypes.STRING,
activity_status: DataTypes.BOOLEAN,
},
{
sequelize,
modelName: 'User',
}
);
return User;
};
role.model.js
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
static associate(models) {
User.belongsToMany(models.Role, {
through: 'user_roles',
foreignKey: 'user_id',
otherKey: 'role_id',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});
User.hasMany(models.User_Role);
User.hasMany(models.Address, {
foreignKey: 'user_id',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});
}
}
User.init(
{
user_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
email: DataTypes.STRING,
password: DataTypes.STRING,
bio: DataTypes.STRING,
activity_status: DataTypes.BOOLEAN,
},
{
sequelize,
modelName: 'User',
}
);
return User;
};
user_role.model
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User_Role extends Model {
static associate(models) {
User_Role.belongsTo(models.User, {
foreignKey: 'user_id',
});
User_Role.belongsTo(models.Role, {
foreignKey: 'role_id',
});
}
}
User_Role.init(
{
user_role_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
},
{
sequelize,
modelName: 'User_Role',
}
);
return User_Role;
};
Migrations
1-create-user
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('users', {
user_id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
email: {
type: Sequelize.STRING,
unique: true,
},
password: {
type: Sequelize.STRING,
},
bio: {
type: Sequelize.STRING,
},
activity_status: {
type: Sequelize.BOOLEAN,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('users');
},
};
3-create-role
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('roles', {
role_id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
unique: true,
type: Sequelize.INTEGER,
},
user_type: {
type: Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('roles');
},
};
6-create-user_role
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('user_roles', {
user_role_id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
user_id: {
type: Sequelize.INTEGER,
references: { model: 'users', key: 'user_id' },
onDelete: 'CASCADE',
},
role_id: {
type: Sequelize.INTEGER,
references: { model: 'roles', key: 'role_id' },
onDelete: 'CASCADE',
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('user_roles');
},
};
Seeders
1_role
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.bulkInsert(
'roles',
[
{
user_type: 'courier',
createdAt: new Date(),
updatedAt: new Date(),
},
{
user_type: 'receiver',
createdAt: new Date(),
updatedAt: new Date(),
},
{
user_type: 'donor',
createdAt: new Date(),
updatedAt: new Date(),
},
{
user_type: 'admin',
createdAt: new Date(),
updatedAt: new Date(),
},
],
{}
);
},
async down(queryInterface, Sequelize) {
await queryInterface.bulkDelete('Roles', null, {});
},
};
2_user
('use strict');
var bcrypt = require('bcryptjs');
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.bulkInsert(
'users',
[
{
email: 'courier#email.com',
password: bcrypt.hashSync('PassWord123#', 10),
bio: 'This is a courier type user!',
activity_status: true,
createdAt: new Date(),
updatedAt: new Date(),
role_id: 1,
},
{
email: 'donor#email.com',
password: bcrypt.hashSync('PassWord123#', 10),
bio: 'This is a donor type user!',
activity_status: true,
createdAt: new Date(),
updatedAt: new Date(),
},
{
email: 'receiver#email.com',
password: bcrypt.hashSync('PassWord123#', 10),
bio: 'This is a Receiver type user!',
activity_status: true,
createdAt: new Date(),
updatedAt: new Date(),
},
{
email: 'admin#email.com',
password: bcrypt.hashSync('PassWord123#', 10),
bio: 'This is a Admin type user!',
activity_status: true,
createdAt: new Date(),
updatedAt: new Date(),
},
],
{}
);
},
async down(queryInterface, Sequelize) {
await queryInterface.bulkDelete('Users', null, {});
},
};

Sequelize especial methods don't get created when Using sequelize migrations

I am struggling when using sequelize migrations and a many-to-many relationship between Users and Roles.
This is the Users model:
'use strict';
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define('Users', {
username: DataTypes.STRING,
name: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING
}, {});
user.associate = function(models) {
// associations can be defined here
user.belongsToMany(models.Roles, {
through: models.UserRoles
});
};
return user;
};
This is the Roles model:
'use strict';
module.exports = (sequelize, DataTypes) => {
const role = sequelize.define('Roles', {
name: DataTypes.STRING
}, {});
role.associate = function(models) {
// associations can be defined here
role.belongsToMany(models.Users, {
through: models.UserRoles
});
};
return role;
};
This is the "create-user" migration:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
username: {
type: Sequelize.STRING,
allowNull: true,
len: [0, 20]
},
name: {
type: Sequelize.STRING,
allowNull: true,
},
email: {
type: Sequelize.STRING,
allowNull: false
},
password: {
type: Sequelize.STRING,
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Users');
}
};
This is the "create-role" migration:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Roles', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Roles');
}
};
This is the userRoles Model:
'use strict';
module.exports = (sequelize, DataTypes) => {
const user_role = sequelize.define('UserRoles', {
userId: DataTypes.INTEGER,
roleId: DataTypes.INTEGER
}, {});
user_role.associate = function(models) {
// associations can be defined here
};
return user_role;
};
And last one the "user-roles" migration:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('UserRoles', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
primaryKey: true,
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Users',
key: 'id'
}
},
roleId: {
primaryKey: true,
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Roles',
key: 'id'
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('UserRoles');
}
};
The problem happens when I try to access to the user.setRoles() from a controller:
exports.signup = (req, res) => {
console.log('creating new user', req.body.username);
// Save User to Database
User.create({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8)
})
.then(user => {
console.log('USER ADDED');
if (req.body.roles) {
Role.findAll({
where: {
name: {
[Op.or]: req.body.roles
}
}
}).then(roles => {
console.log('ROLES ', roles);
user.setRoles(roles).then(() => {
res.send({ message: "User was registered successfully!" });
});
});
} else {
console.log('NO ROLES > Normal User');
// user role = 1
user.setRoles([1]).then(() => {
res.send({ message: "User was registered successfully!" });
});
}
})
.catch(err => {
console.log('ERROR: ', err);
res.status(500).send({ message: err.message });
});
};
When I console.log the user using : console.log(Object.keys(user.__proto__)) I get this array where the special methods haven't been created, any idea what I am doing wrong?
Array(7) ["_customGetters", "_customSetters", "validators", "_hasCustomGetters", "_hasCustomSetters", "rawAttributes", "_isAttribute"]
Many thanks for your help!
Just call all associate functions after registering models. For instance:
const models = path.join(__dirname, 'models')
const db = {}
fs.readdirSync(models)
.filter(function (file) {
return (file.indexOf('.') !== 0) && (file.slice(-3) === '.js')
})
.forEach(function (file) {
var model = sequelize['import'](path.join(models, file))
db[model.name] = model
})
Object.keys(db).forEach(function (modelName) {
if (db[modelName].associate) {
db[modelName].associate(db)
}
})

Sequelize model class trying to access table name that is lower-cased "users" instead of capitalized "Users"

I'm trying to use the Sequelize model.create function but keep running into this error: Unhandled rejection SequelizeDatabaseError: relation "users" does not exist. The User class is making my table name all lowercased instead of capitalized.The table I created is called "Users" but the create function keeps trying to look for a table called "users".
Executing (default): SELECT "id", "first_name", "last_name", "email", "username", "password", "dob", "created_at" AS "createdAt", "updated_at" AS "updatedAt" FROM "users" AS "User";
It seems like the User class is trying to access a "users" table whenever it communicates with postgres. I tried using other functions and kept running into the same problem. My code is down below.
/model/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/db.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);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const model = sequelize['import'](path.join(__dirname, file));
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;
/model/users.js
'use strict';
const bcrypt = require('bcrypt');
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
first_name: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
last_name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false
},
dob: {
type: DataTypes.DATE,
allowNull: false
}
}, {
underscored: true,
instanceMethods: {
validPassword(password) {
return bcrypt.compareSync(password, this.password);
}
}
});
User.beforeCreate((user) => {
user.email = user.email.toLowerCase();
user.first_name = user.first_name.charAt(0).toUpperCase(0) + user.first_name.slice(1);
user.last_name = user.last_name.charAt(0).toUpperCase(0) + user.last_name.slice(1);
return bcrypt.hash(user.password, 8).then((hash) => {
user.password = hash;
});
});
User.associate = function(models) {
// associations can be defined here
};
return User;
};
/migrations/20191025125151-create-user.js
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
first_name: {
type: Sequelize.STRING,
allowNull: false
},
last_name: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
username: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
password: {
type: Sequelize.STRING,
allowNull: false
},
dob: {
type: Sequelize.DATE,
allowNull: false
},
created_at: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('NOW()')
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('NOW()')
}
}, {
timestamps: true,
underscored: true
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Users');
}
};
/controllers/user
const { User } = require('../../db/models');
const signup = (req, res) => {
const { first_name, last_name, username, email, password, dob } = req.swagger.params.data.value;
User.create({
first_name,
last_name,
password,
dob,
username,
email
})
.then((user) => {
console.log(user);
res.json({message: 'Success'});
})
}
Error Message:
Executing (default): SELECT "id", "first_name", "last_name", "email", "username", "password", "dob", "created_at" AS "createdAt", "updated_at" AS "updatedAt" FROM "users" AS "User";
Unhandled rejection SequelizeDatabaseError: relation "users" does not exist
at Query.formatError (/home/ubu/projects/stat/node_modules/sequelize/lib/dialects/postgres/query.js:366:16)
at query.catch.err (/home/ubu/projects/stat/node_modules/sequelize/lib/dialects/postgres/query.js:72:18)
at bound (domain.js:301:14)
at runBound (domain.js:314:12)
at tryCatcher (/home/ubu/projects/stat/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/ubu/projects/stat/node_modules/bluebird/js/release/promise.js:547:31)
at Promise._settlePromise (/home/ubu/projects/stat/node_modules/bluebird/js/release/promise.js:604:18)
at Promise._settlePromise0 (/home/ubu/projects/stat/node_modules/bluebird/js/release/promise.js:649:10)
at Promise._settlePromises (/home/ubu/projects/stat/node_modules/bluebird/js/release/promise.js:725:18)
at _drainQueueStep (/home/ubu/projects/stat/node_modules/bluebird/js/release/async.js:93:12)
at _drainQueue (/home/ubu/projects/stat/node_modules/bluebird/js/release/async.js:86:9)
at Async._drainQueues (/home/ubu/projects/stat/node_modules/bluebird/js/release/async.js:102:5)
at Immediate.Async.drainQueues (/home/ubu/projects/stat/node_modules/bluebird/js/release/async.js:15:14)
at runCallback (timers.js:794:20)
at tryOnImmediate (timers.js:752:5)
at processImmediate [as _immediateCallback] (timers.js:729:5)
You have a probleme in the creation of the table in database at the columns createdAt and updatedAt :
`'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
first_name: {
type: Sequelize.STRING,
allowNull: false
},
last_name: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
username: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
password: {
type: Sequelize.STRING,
allowNull: false
},
dob: {
type: Sequelize.DATE,
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('NOW()')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('NOW()')
}
}, {
timestamps: true,
underscored: true
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Users');
}
};`
Add the tableName property to your define call.
...
underscored: true,
tableName: 'Users',
instanceMethods: ...

Node Sequelize migrations/models is it possible to share the same code?

I'm new at Sequelize so be patient.
I started up a new project using Sequelize
and migrations so I've got like this:
migrations/20150210104840-create-my-user.js:
"use strict";
module.exports = {
up: function(migration, DataTypes, done) {
migration.createTable("MyUsers", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
first_name: {
type: DataTypes.STRING
},
last_name: {
type: DataTypes.STRING
},
bio: {
type: DataTypes.TEXT
},
createdAt: {
allowNull: false,
type: DataTypes.DATE
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE
}
}).done(done);
},
down: function(migration, DataTypes, done) {
migration.dropTable("MyUsers").done(done);
}
};
models/myuser.js:
"use strict";
module.exports = function(sequelize, DataTypes) {
var MyUser = sequelize.define("MyUser", {
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
bio: DataTypes.TEXT
}, {
classMethods: {
associate: function(models) {
// associations can be defined here
}
}
});
return MyUser;
};
as you can see the table definition
is both on the migration and the model file.
I'm wondering if there is a way to share
the code ?
I mean I don't like to have logic in two files
if a field change I've to update twice.
UPDATE
following the Yan Foto example below
a different way may be cleaner.
schemas/users
'use strict';
module.exports = {
name: 'users',
definition : function(DataTypes) {
return {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
firstname: {
type:DataTypes.STRING
},
lastname: {
type:DataTypes.STRING
},
email: {
type: DataTypes.STRING,
unique: true
},
username: {
type:DataTypes.STRING,
unique: true
}
};
}
};
models/users
'use strict';
var Schema = require('../schemas/users');
module.exports = function(sequelize, DataTypes) {
return sequelize.define(
Schema.name,
Schema.definition(DataTypes),
{
freezeTableName: true ,
instanceMethods: {
countTasks: function() {
// how to implement this method ?
}
}
}
);
};
migrations/20150720184716-users.js
'use strict';
var Schema = require('../schemas/users');
module.exports = {
up: function (queryInterface, Sequelize) {
return queryInterface.createTable(
Schema.name,
Schema.definition(Sequelize)
);
},
down: function (queryInterface, Sequelize) {
return queryInterface.dropTable(Schema.name);
}
};
I wondered the same thing as I started using sequelize and here is my solution. I define my models as bellow:
module.exports = {
def: function(DataTypes) {
return {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
username: DataTypes.STRING,
password: DataTypes.STRING,
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE,
}
},
config: {}
};
Where def defines the attributes and config is the optional options object accepted by define or migration methods. And I import them using the following code:
fs.readdirSync(__dirname + '/PATH/TO/models')
.filter(function(file) {
return (file.indexOf('.') !== 0) && (file !== basename);
})
.forEach(function(file) {
var name = file.substring(0, file.lastIndexOf(".")),
definition = require(path.join(__dirname + '/models', file));
sequelize['import'](name, function(sequelize, DataTypes) {
return sequelize.define(
name,
definition.def(DataTypes),
definition.config
);
});
});
For the migrations I have a similar approach:
const path = require('path');
module.exports = {
up: function (queryInterface, Sequelize) {
return queryInterface.createTable(
'users',
require(path.join(__dirname + '/PATH/TO/models', 'user.js')).def(Sequelize)
);
},
down: function (queryInterface, Sequelize) {
return queryInterface.dropTable('users');
}
};

Resources