Sequelize using postgres dialect add double column - mysql

I want to create a relationship between parents table and children table and this is how i doing it
// 20210226075430-create-child.js (children migration file)
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable("Children", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name: {
type: Sequelize.STRING,
},
age: {
type: Sequelize.STRING,
},
parentId: {
type: Sequelize.INTEGER,
allowNull: false,
onDelete: "CASCADE",
references: {
model: "Parents",
key: "id",
},
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable("Children");
},
};
// parent migration file
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable("Parents", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name: {
type: Sequelize.STRING,
},
age: {
type: Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable("Parents");
},
};
// child.js / children model
"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class Child extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
Child.belongsTo(models.Parent, { foreignKey: "parentId" });
}
}
Child.init(
{
name: DataTypes.STRING,
age: DataTypes.STRING,
parentId: DataTypes.INTEGER,
},
{
sequelize,
modelName: "Child",
}
);
return Child;
};
// parent model
"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class Parent extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
Parent.hasMany(models.Child);
}
}
Parent.init(
{
name: DataTypes.STRING,
age: DataTypes.STRING,
},
{
sequelize,
modelName: "Parent",
}
);
return Parent;
};
this code perfectly fine in mysql but when i change dialect to postgres i got error like this :
Executing (default): SELECT "id", "name", "age", "parentId", "createdAt", "updatedAt", "ParentId" FROM "Children" AS "Child";
(node:7496) UnhandledPromiseRejectionWarning: SequelizeDatabaseError: column "ParentId" does not exist
at Query.formatError (D:\work\www\express-starter\node_modules\sequelize\lib\dialects\postgres\query.js:386:16)
at Query.run (D:\work\www\express-starter\node_modules\sequelize\lib\dialects\postgres\query.js:87:18)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:7496) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:7496) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I have already tried to add foreign key in child.js (model) but i still got this error.
where i doing it wrong?

You didn't indicate parentId as a foreignKey option in the association from Parent to Children that's why Sequelize automatically generates its name like ParentId.
Just indicate the same option and value as in belongsTo like this:
Parent.hasMany(models.Child, { foreignKey: "parentId" });

Related

Running Sql migrations throws syntax error

I have created my first migration using sequelize-cli, now when I enter npx sequelize-cli db:migrate to run migration and create table in DB, I get error
I look into documentation could not find how and what should go into migration file.
Error
ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NUMBER, `otp` INTEGER, `otp_expiration_date` DATETIME, `createdAt` DATETIME NOT ' at line 1
My migration File
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
phone_number: {
type: Sequelize.NUMBER
},
otp: {
type: Sequelize.INTEGER(4)
},
otp_expiration_date: {
type: Sequelize.DATE
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Users');
}
};
My User Model:
const moment = require('moment');
'use strict';
module.exports = (sequelize, DataTypes) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
};
User.init({
name: {
type: DataTypes.STRING,
allowNull: false
},
phone_number: {
type: DataTypes.NUMBER
},
otp: {
type: DataTypes.INTEGER(4)
},
otp_expiration_date: {
type: DataTypes.DATE,
set(value) {
// convert regular Date to moment Date
value = moment(value).add(5, 'minutes');
this.setDataValue('otp_expiration_date', value);
}
},
is_otp_expired: {
type: DataTypes.VIRTUAL,
get() {
// otp_expiration_date < current date
return this.getDataValue(otp_expiration_date).isAfter(moment()) ? true : false
}
}
}, {
sequelize,
modelName: 'User',
});
return User;
};
I have tried
changing datatypes
moving getters into migration
removing createdAt
[SOLVED]
Problem was with DataType of phone_number , there is no Sequelize.NUMBER type per Sequelize docs
I confused Sequelize DataTypes with MySql DataTypes
phone_number: {
type: DataTypes.NUMBER <---- bug
}
Solution
phone_number: {
type: DataTypes.INTEGER <---- solution
}

Sequelize UUID with mySQL: Unable to set default value

I've been trying for awhile to set id (primary key) for my Users table as UUID. However, I keep getting this error: Field 'id' doesn't have a default value, when I attempt to seed it.
This is what I have so far in my Users model:
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Users extends Model {};
Users.init({
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true
},
user_name: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notNull: {
msg: 'Please add a name',
},
},
},
{
sequelize,
modelName: 'Users',
});
return Users;
Likewise, this is what I have in my Users migration file:
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Admins', {
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true
},
user_name: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Users');
}
};
I'm pretty new to Sequelize, so would love some guidance on what's gone wrong!
By adding defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'), to your createdAt and updatedAt in your migration file defaults the value to the current timestamp.
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
},
So, I think I realised the issue:
For some reason, seeding it by using a seeder file would not auto-generate the fields that I thought would be auto-generated, so I had to put them in manually.
'use strict';
const { v4: uuidv4 } = require('uuid');
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.bulkInsert('Users', [{
id: uuidv4(),
user_name: 'John Doe',
"createdAt": new Date(),
"updatedAt": new Date()
}], {});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.bulkDelete('Users', null, {});
}
};
Initially, I had been trying to seed (running the command npx sequelize-cli db:seed:all) without the id: uuidv4() and the new Date(), which was why it didn't work.

ERROR: Cannot find module 'sequelize/types'

C:\Users\lenovo\Desktop\Yoobou\Yoobou>sequelize db:migrate
Sequelize CLI [Node: 14.15.1, CLI: 6.2.0, ORM: 6.3.5]
Loaded configuration file "config\config.json". Using environment
"development".
== 20201207141344-create-producteurs: migrating =======
ERROR: Cannot find module 'sequelize/types' Require stack:
C:\Users\lenovo\Desktop\Yoobou\Yoobou\migrations\20201207141344-create-producteurs.js
C:\Users\lenovo\AppData\Roaming\npm\node_modules\sequelize-cli\node_modules\umzug\lib\migration.js
C:\Users\lenovo\AppData\Roaming\npm\node_modules\sequelize-cli\node_modules\umzug\lib\index.js
C:\Users\lenovo\AppData\Roaming\npm\node_modules\sequelize-cli\lib\core\migrator.js
C:\Users\lenovo\AppData\Roaming\npm\node_modules\sequelize-cli\lib\commands\migrate.js
C:\Users\lenovo\AppData\Roaming\npm\node_modules\sequelize-cli\lib\sequelize
//MIGRATION 20201207141344-create-producteurs.js
'use strict'; const { UniqueConstraintError } =
require('sequelize/types');
module.exports = { up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('PRODUCTEURS', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
first_name: {
allowNull: false,
type: Sequelize.STRING,
unique: true,
},
last_name: {
allowNull: false,
type: Sequelize.STRING,
},
email: {
allowNull: false,
type: Sequelize.STRING,
Unique: true,
},
password: {
allowNull: false,
type: Sequelize.STRING,
},
avatar: {
allowNull: false,
type: Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
}); }, down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('PRODUCTEURS'); }, };
// ASSOCIATION MODELS 'use strict'; const { Model } = require('sequelize'); module.exports = (sequelize, DataTypes) => {
class ADMINISTRATEUR extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The models/index file will call this method automatically.
/
associate(models) {
// define association here
models.ADMINISTRATEUR.hasMany(models.CLIENTS);
models.ADMINISTRATEUR.hasMany(models.PRODUITS);
models.ADMINISTRATEUR.hasMany(models.ADRESSE_CLIENTS);
models.ADMINISTRATEUR.hasMany(models.CATEGORY_PRODUITS);
models.ADMINISTRATEUR.hasMany(models.COMMANDES);
models.ADMINISTRATEUR.hasMany(models.PRODUCTEURS);
models.ADMINISTRATEUR.hasMany(models.AVIS);
} } ADMINISTRATEUR.init(
{
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
avatar: DataTypes.STRING,
},
{
sequelize,
modelName: 'ADMINISTRATEUR',
} ); return ADMINISTRATEUR; }; 'use strict'; const { Model } = require('sequelize'); module.exports = (sequelize, DataTypes) =>
{ class PRODUCTEURS extends Model {
/*
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The models/index file will call this method automatically.
*/
static associate(models) {
// define association here
models.PRODUCTEURS.belongsTo(models.ADMINISTRATEUR , {
foreignKey: {
allowNull: false
}
});
models.PRODUCTEURS.hasMany(models.CLIENTS);
models.PRODUCTEURS.hasMany(models.PRODUITS);
models.PRODUCTEURS.hasMany(models.ADRESSE_CLIENTS);
models.PRODUCTEURS.hasMany(models.CATEGORY_PRODUITS);
models.PRODUCTEURS.hasMany(models.COMMANDES);
} }; PRODUCTEURS.init({
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
avatar: DataTypes.STRING }, {
sequelize,
modelName: 'PRODUCTEURS', }); return PRODUCTEURS; };
I finally found the answer I had to put the variable "const {UniqueConstraintError} = require ('sequelize / types')" in comment and retype sequelize db: migrate

Sequelize - Model and Migrations

[Resolved !]
I've researched a lot on the Internet and found some similar question with mine. But, I can't find the proper way to fix my problem. Please help.
I'm using Sequelize v6. I've some troubles in using models and migrations.
What I've done:
I generated role model using sequelize cli. And it gives me below code in models/role.js.
"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class Role extends Model {
static associate(models) {
// define association here
}
}
Role.init(
{
name: DataTypes.STRING,
description: DataTypes.STRING, },
{
sequelize,
modelName: "roles",
}
);
return Role;
};
And I also got migration file for that model in migrations/timestamp-create-role.js.
"use strict";
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable(
"roles", // <- I've changed this from Roles to roles because I want the MySQL convention.
{
roleId: {
allowNull: false,
autoIncrement: true,
field: "role_id",
primaryKey: true,
type: Sequelize.INTEGER,
},
name: {
allowNull: false,
type: Sequelize.STRING(30),
},
description: {
type: Sequelize.STRING(50),
},
createdAt: {
allowNull: false,
field: "created_at",
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
field: "updated_at",
type: Sequelize.DATE,
},
},
{
underscored: true,
}
);
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable("roles");
},
};
What I got in MySQL
By running the above migration, I got roles table with following columns:
role_id, name, created_at, updated_at which is fine. That is what I want in MySQL database.
Reading roles
/controllers/roles.js
const Role = require("../models").roles;
const catchAsync = require("../middlewares/catchAsync");
exports.findAll = catchAsync(async (req, res) => {
const roles = await Role.findAll();
return res.status(200).json({
status: "success",
data: {
roles,
},
});
});
What I'm not OK
With the above implementation, I got this error on the console.
Executing (default): SELECT `id`, `name`, `description`, `createdAt`, `updatedAt` FROM `roles` AS `roles`;
SequelizeDatabaseError: Unknown column 'id' in 'field list'
at Query.formatError (/home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/dialects/mysql/query.js:239:16)
at Query.run (/home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/dialects/mysql/query.js:54:18)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async /home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/sequelize.js:619:16
at async MySQLQueryInterface.select (/home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/dialects/abstract/query-interface.js:938:12)
at async Function.findAll (/home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/model.js:1741:21)
at async /home/hello-world/Thesis/SMS-API/src/controllers/roles.js:5:17
at async /home/hello-world/Thesis/SMS-API/src/middlewares/catchAsync.js:4:7
Another Attempt
I've modified models/role.js like below.
Role.init(
{
role_id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: DataTypes.STRING,
description: DataTypes.STRING,
created_at: DataTypes.DATE,
updated_at: DataTypes.DATE,
}
Next try, Next Error
With the above modification, I got new error.
Executing (default): SELECT `role_id`, `name`, `description`, `created_at`, `updated_at`, `createdAt`, `updatedAt` FROM `roles` AS `roles`;
SequelizeDatabaseError: Unknown column 'createdAt' in 'field list'
at Query.formatError (/home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/dialects/mysql/query.js:239:16)
at Query.run (/home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/dialects/mysql/query.js:54:18)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async /home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/sequelize.js:619:16
at async MySQLQueryInterface.select (/home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/dialects/abstract/query-interface.js:938:12)
at async Function.findAll (/home/hello-world/Thesis/SMS-API/node_modules/sequelize/lib/model.js:1741:21)
at async /home/hello-world/Thesis/SMS-API/src/controllers/roles.js:5:17
at async /home/hello-world/Thesis/SMS-API/src/middlewares/catchAsync.js:4:7
HELP
I've tried so many ways which cannot fix my problem yet. So, please help. I want MySQL naming convention in MySQL level which is underscore and JavaScript naming convention in Code level.
Thank you so much.
I've fixed my problem. I can now use each naming convention for their specific world: under_score for MySQL and camelCase for JavaScript.
So here I've written my solution if someone come across the same issue in the future.
I'm using sequelize-cli for creating migrations, models and seeders. You can check it here.
Migration
Migration is only responsible for creating/altering/deleting the tables and columns. It access with only the database.
migrations/timestamp-create-role-table.js
"use strict";
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable("roles", {
roleId: {
allowNull: false,
autoIncrement: true,
field: "role_id",
primaryKey: true,
type: Sequelize.INTEGER,
},
name: {
allowNull: false,
type: Sequelize.STRING(30),
},
description: {
type: Sequelize.STRING(50),
},
createdAt: {
allowNull: false,
field: "created_at",
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
field: "updated_at",
type: Sequelize.DATE,
},
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable("roles");
},
};
By running the above migration script, I got the roles table with following columns in my physical database.
role_id, name, description, created_at, updated_at
Seeder
Seeder will populate your table with initial test data. I've filled my roles table like below.
seeders/timestamp-roles-table-seeder.js
"use strict";
const roles = [
"official",
"office",
"admin"
].map((role) => {
return {
name: role,
created_at: new Date(),
updated_at: new Date(),
};
});
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.bulkInsert("roles", roles);
},
down: async (queryInterface, Sequelize) => {
await queryInterface.bulkDelete("roles", null, {});
},
};
Model
After I've created table and filled up with initial data, I need to create Role model in order to use as bridge between MySQL and JavaScript.
models/role.js
"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class Role extends Model {
static associate(models) {
// define association here
}
}
Role.init(
{
roleId: {
allowNull: false,
autoIncrement: true,
field: "role_id", // SELECT role_id AS id
primaryKey: true,
type: DataTypes.INTEGER,
},
name: DataTypes.STRING,
description: DataTypes.STRING,
createdAt: {
type: DataTypes.DATE,
field: "created_at",
},
updatedAt: {
type: DataTypes.DATE,
field: "updated_at",
},
},
{
sequelize,
tableName: "roles",
modelName: "Role",
}
);
return Role;
};
Getting roles from JavaScript
controllers/roles.js
const models = require("../models");
const catchAsync = require("../middlewares/catchAsync");
exports.findAll = catchAsync(async (req, res) => {
const roles = await models.Role.findAll();
/*
you can access
- role_id from db with roleId in JS
- created_at from db with createdAt in JS
*/
return res.status(200).json({
status: "success",
data: {
roles,
},
});
});
Hope it could help!

Sequelize Update HasMany Relationships

I would like to update the rows of a hasMany relation, I have a table InRoutes that can have many InRouteDetails, so when I update InRoute I also need to update it details, there are three cases that can happen, delete an detail, update an detail and add an detail.
When I try to update using setInRouteDetails but for some reason he tries to get an InRouteDetail that is equal an object given me this error: Truncated incorrect DOUBLE value: '[object Object]'
This is my model:
export default (sequelize, DataType) => {
const InRoutes = sequelize.define('InRoutes', {
id: {
type: DataType.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: DataType.STRING,
allowNull: false,
validate: {
notEmpty: true,
},
},
description: {
type: DataType.TEXT,
allowNull: true,
},
createdBy: {
type: DataType.STRING,
allowNull: true,
},
updatedBy: {
type: DataType.STRING,
allowNull: true,
},
}, {
classMethods: {
associate: (models) => {
InRoutes.hasMany(models.InRoutesDetails, {
foreignKey: 'InRouteId',
as: 'InRouteDetails',
onDelete: 'CASCADE',
});
InRoutes.belongsTo(models.Trunks, {
foreignKey: 'trunkId',
as: 'TrunkId',
onDelete: 'CASCADE',
});
},
},
});
return InRoutes;
};
This is where I try do update "InRoute" with his association "InRouteDetails":
async update(data, params, updatedBy) {
data.updatedBy = updatedBy.username;
try {
const inRoute = await this.InRoutes.findOne({ where: params });
const teste = [{
id: 2,
mask: '89',
remove: 4,
add: '3',
destinationType: 'callback',
destination: 2,
InRouteId: 2,
}];
await inRoute.addInRouteDetails(teste);
await inRoute.update(data);
return defaultResponse(inRoute);
} catch (error) {
return errorResponse(error.message, HttpStatus.UNPROCESSABLE_ENTITY);
}
}
This gives me this result on console:
Executing (default): UPDATE `InRoutesDetails` SET `InRouteId`=?,`updatedAt`=? WHERE `id` IN ('[object Object]')
He tries to compare id with some object.