I need that when registering the user, the account should also be created automatically and I managed to do this using sequelize hooks, but the accountId I am not able to insert its value automatically and it always has a null value, I need that when the accountId has the id of Account, but I don't know how to do that
My models
import { Model, DECIMAL, INTEGER } from 'sequelize';
import db from '.';
class Account extends Model {
id!: number;
balance!: number;
};
Account.init({
id: {
type: INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
balance: {
type: DECIMAL(13, 2),
allowNull: false
},
},
{
sequelize: db,
modelName: 'accounts',
timestamps: false,
underscored: true,
},
);
export default Account;
import { Model, STRING, INTEGER } from 'sequelize';
import db from '.';
import Account from './account';
class User extends Model {
id!: number;
username!: string;
password!: string;
accountId!: any;
};
User.init({
id: {
type: INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
username: {
type: STRING(50),
allowNull: false,
},
password: {
type: STRING(200),
allowNull: false,
},
accountId: {
type: INTEGER,
// allowNull: false,
},
},
{
sequelize: db,
modelName: 'users',
tableName: 'users',
freezeTableName: true,
timestamps: false,
underscored: true,
hooks: {
afterCreate(user, _op) {
Account.create({ balance: 100})
}
},
}
);
Account.hasOne(User, {foreignKey: 'id', as: 'accountId'});
User.belongsTo(Account, {foreignKey: 'accountId', as: 'idAccount'});
export default User;
My migrations
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
return queryInterface.createTable('users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
username: {
allowNull: false,
type: Sequelize.STRING(50),
},
password: {
allowNull: false,
type: Sequelize.STRING(200),
},
account_id: {
// allowNull: false,
type: Sequelize.INTEGER,
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
references: {
model: 'accounts',
key: 'id',
},
},
});
},
down: async (queryInterface, _Sequelize) => {
return queryInterface.dropTable('users');
},
};
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
return queryInterface.createTable('accounts', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
balance: {
allowNull: false,
type: Sequelize.DECIMAL(13,2),
},
});
},
down: async (queryInterface, _Sequelize) => {
return queryInterface.dropTable('accounts');
},
};
register = async (req: Request, res: Response) => {
const { username, password } = req.body;
const registerUser = await this.userController.register({username, password});
res.status(200).json({registerUser});
}
I've tried going through the hooks and inserting auto increment as well
Related
I am trying to configure a Foreign Key association between two tables on 'non-PrimaryKey' fields for one-to-many relation:
Asset.belongsTo(AssetClass)
AssetClass.hasMany(Asset)
I create tables first and add the constraint in the third migration:
migrations\20220621223626-create-asset.js
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('Assets', {
ticker: {
allowNull: false,
autoIncrement: false,
primaryKey: true,
type: Sequelize.STRING
},
shortName: {
allowNull: false,
type: Sequelize.STRING
},
fullName: {
allowNull: false,
type: Sequelize.STRING
},
assetClass: {
allowNull: false,
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('Assets');
}
};
migrations\20220622035610-create-asset-class.js
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('AssetClasses', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING,
allowNull: false
},
prio: {
type: Sequelize.INTEGER,
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('AssetClasses');
}
};
migrations\20220627211055-add-constraint-fk_asset-assetClass.js
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addConstraint('Assets', {
fields: ['assetClass'], //existing field in Assets table
type: 'foreign key',
name: 'fk_asset-assetClass',
references: {
table: 'AssetClasses', //reference to AssetClasses table
field: 'name' //name of the target field
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.removeConstraint('Assets', 'fk_asset-assetClass');
}
};
After running db::migrate I am getting a following error message:
SQLITE_ERROR: foreign key mismatch - "Assets_backup" referencing "AssetClasses"
which leaves me with a Assets_backup table in the database which I need to remove manually.
What seems to works though is:
Creating a new column assetClassId in Assets table and referencing it to Primary Key field (id) of AssetClasses table:
//addConstraint migration
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addConstraint('Assets', {
fields: ['assetClassId'], //existing field in Assets table
type: 'foreign key',
name: 'fk_asset-assetClass',
references: {
table: 'AssetClasses', //reference to AssetClasses table
field: 'id' //name of the target field
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.removeConstraint('Assets', 'fk_asset-assetClass');
}
};
//createTable Assets migration
assetClassId: {
allowNull: false,
type: Sequelize.INTEGER
},
How can I make it work for existing non-PK fields?
I'm using sequelize with typescript and i'm facing this error when I'm trying to create an association between two models...
Error: UserAdmin.belongsTo called with something that's not a subclass of Sequelize.Model
Here my codes:
User.ts Model:
import Sequelize, {Model, Association} from 'sequelize';
const bcrypt = require('bcrypt');
const connection = require('../../database');
const jwt = require('jsonwebtoken');
import UserClient from './UserClient';
import UserAdmin from './UserAdmin';
class User extends Model{
public id!: number;
public name!: string;
public email!: string;
public password!: string;
public receive_email!:boolean;
public image!:string | null;
public readonly createdAt!: Date;
public readonly updatedAt!: Date;
public async checkPassword(password: string): Promise<boolean> {
return bcrypt.compare(password, this.password);
}
public async generateToken(){
return jwt.sign({id: this.id}, process.env.APP_SECRET, {
expiresIn: 86400,
});
}
}
User.init(
{
name: Sequelize.STRING,
email: Sequelize.STRING,
password: Sequelize.STRING,
receive_email:Sequelize.BOOLEAN,
image:Sequelize.STRING,
},
{
sequelize: connection,
underscored:true,
modelName: 'User'
},
);
User.addHook(
'beforeSave', async(user:User) =>{
if(user.password){
user.password = await bcrypt.hash(user.password,8);
}
},
);
export default User;
UserAdmin.ts model:
import Sequelize, {Model, Association} from 'sequelize';
const bcrypt = require('bcrypt');
const connection = require('../../database');
const jwt = require('jsonwebtoken');
import User from './User';
class UserAdmin extends Model{
public id!:number;
public user_id!: number;
public access_level!: number;
public readonly createdAt!: Date;
public readonly updatedAt!: Date;
}
UserAdmin.init(
{
user_id: {
type: Sequelize.INTEGER,
references: {model: 'users', key:'id'},
onDelete: 'CASCADE'
},
access_level: Sequelize.INTEGER,
},
{
sequelize: connection,
underscored:true,
modelName: 'UserAdmin',
}
);
UserAdmin.belongsTo(User);
export default UserAdmin;
The migrations:
users migration:
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('users', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique:true
},
password: {
type: Sequelize.STRING,
allowNull: false,
},
receive_email:{
type: Sequelize.BOOLEAN,
defaultValue: true,
},
image:{
type:Sequelize.STRING,
allowNull:true,
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
},
updated_at:{
type: Sequelize.DATE,
allowNull: false,
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('users');
}
};
user_admins migration:
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('user_admins', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
user_id: {
type: Sequelize.INTEGER,
allowNull:false,
references: {
model: 'users',
key: 'id',
onUpdate: 'CASCADE',
onDelete:'CASCADE'
}
},
access_level: {
type: Sequelize.INTEGER,
allowNull:false,
},
created_at: {
allowNull: false,
type: Sequelize.DATE
},
updated_at: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('user_admins');
}
};
What should I do?
I solved this by adding the following code inside my User.ts:
User.hasOne(UserAdmin);
UserAdmin.belongsTo(User, {foreignKey: 'user_id', targetKey: 'id'});
I have two models in my Node JS application, Users and Companies. When I try to use the include function when getting the companies, I get the error:
message: "users is not associated to companies!"
This is the user model
import { Sequelize, DataTypes } from 'sequelize';
import { Application } from '../declarations';
export default function (app: Application) {
const sequelizeClient: Sequelize = app.get('sequelizeClient');
const users = sequelizeClient.define('users', {
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: true
},
role: {
type: DataTypes.STRING,
allowNull: true,
},
language: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'en',
},
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING,
allowNull: false,
},
}, {
underscored: true,
hooks: {
beforeCount(options: any) {
options.raw = true;
}
}
});
// eslint-disable-next-line no-unused-vars
(users as any).associate = function (models: any) {
(users as any).belongsTo(models.companies, {
foreignKey: 'companyId',
allowNull: true,
onDelete: "CASCADE",
});
};
return users;
}
and the companies model:
import { Sequelize, DataTypes, Model } from 'sequelize';
import { Application } from '../declarations';
export default function (app: Application) {
const sequelizeClient: Sequelize = app.get('sequelizeClient');
const companies = sequelizeClient.define('companies', {
name: {
type: DataTypes.STRING,
allowNull: false
},
phone: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
},
email: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
},
active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true,
},
}, {
underscored: true,
hooks: {
beforeCount(options: any) {
options.raw = true;
}
}
});
// eslint-disable-next-line no-unused-vars
(companies as any).associate = function (models: any) {
(companies as any).hasMany(models.users);
(companies as any).hasMany(models.patients);
};
return companies;
}
And the include function
function getSuperAdmin() {
return (context: HookContext) => {
const sequelizeClient = context.app.get("sequelizeClient");
context.params.sequelize = {
include: [
{
model: sequelizeClient.models.users,
as: 'users',
required: false,
where: {
'$users.role$': 'super_admin'
}
}
],
};
return context;
}
}
When I include the companies model in the user query, it works correctly. But not the other way around. Any ideas?
Thanks
I have a database that was created with Postgres that was set up for a single foreign key association, Now, this would be mapped as a role table model
consider I have two tables user and roles
roles contain role details and user contain user details of role
const uuid = require('uuid/v4');
('use strict');
module.exports = (sequelize, DataTypes) => {
const role = sequelize.define(
'role',
{
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
},
{}
);
role.beforeCreate((role) => (role.id = uuid()));
role.associate = function (models) {
role.hasMany(models.user), { foreignKey: 'roleId', as: 'user_roleId' };
};
return role;
};
role migration
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('roles', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
name: {
type: Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('roles');
},
};
user model
const uuid = require('uuid/v4');
('use strict');
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define(
'user',
{
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: DataTypes.STRING,
email: {
type: DataTypes.STRING,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
phoneNumber: {
type: DataTypes.STRING,
},
roleId: {
type: DataTypes.UUID,
},
},
{
timestamps: true,
paranoid: true,
defaultScope: {
attributes: { exclude: ['password'] },
},
}
);
user.beforeCreate((user) => (user.id = uuid()));
user.associate = function (models) {
user.belongsTo(models.role, { foreignKey: 'roleId', onDelete: 'CASCADE' });
};
return user;
};
user migration
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('users', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
firstName: {
type: Sequelize.STRING,
},
lastName: {
type: Sequelize.STRING,
},
email: {
type: Sequelize.STRING,
},
password: {
type: Sequelize.STRING,
},
phoneNumber: {
type: Sequelize.STRING,
},
roleId: {
type: Sequelize.UUID,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
deletedAt: {
allowNull: true,
type: Sequelize.DATE,
},
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('users');
},
};
after running the migration these tables are created in my database.role_id is also present in the user table. but role_id is not generated as a foreign key in my user table. also please verify that the relationship which is mention here(one to many) is correct or not.
please verify my code and give me any suggestions if any changes required. I'm new in development
Your user migration also needs to know about the foreign key; you do this by adding a references: key to the column definition. The Sequelize documentation has a foreign key example; scroll about half way down the page (or just search for references).
In your case the user migration should look something like:
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('users', {
// ... other fields omitted
roleId: {
type: Sequelize.UUID,
references: {
model: { tableName: 'role' }
key: 'id',
},
},
// ... more fields omitted
});
},
// down: omitted
}
I'm having trouble getting Sequelize.js to soft delete the rows in my table. I used Sequelize cli to do all my migrations and I'm not using the sync feature to resync the database on start. I have the timestamp fields and even the deletedAt field in my migration and models (model has paranoid: true also) and no matter what it still deletes the row instead of adding a timestamp to the deletedAt field. I noticed when do any querying it doesn't add the deletedAt = NULL in the query like I've seen in some tutorials. I'm using Sequelize.js v3.29.0.
Model File:
'use strict';
module.exports = function(sequelize, DataTypes) {
var Collection = sequelize.define('Collection', {
userId: {
type: DataTypes.INTEGER,
allowNull: false,
validate: {
isInt: true
}
},
name: {
type: DataTypes.STRING,
allowNull: false
},
description: DataTypes.TEXT,
createdAt: {
allowNull: false,
type: DataTypes.DATE
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE
},
deletedAt: {
type: DataTypes.DATE
}
}, {
classMethods: {
associate: function(models) {
Collection.belongsTo(models.User, { foreignKey: 'userId' })
}
}
}, {
timestamps: true,
paranoid: true
});
return Collection;
};
Migration File:
'use strict';
module.exports = {
up: function(queryInterface, Sequelize) {
return queryInterface.createTable('Collections', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
allowNull: false,
type: Sequelize.INTEGER
},
name: {
allowNull: false,
type: Sequelize.STRING
},
description: {
type: Sequelize.TEXT
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
},
deletedAt: {
type: Sequelize.DATE
}
});
},
down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('Collections');
}
};
Here is the code in the controller I'm using to destroy the collection object.
Collection.findOne({
where: {
id: collectionId,
userId: user.id
}
}).then(function(collection){
if (collection !== null) {
collection.destroy().then(function(){
res.redirect('/collection');
}).catch(function(error){
res.redirect('/collection/'+collectionId);
});
}
});
Make sure paranoid is attribute defined inside second object param.
..., {
classMethods: {
associate: function(models) {
Collection.belongsTo(models.User,{ foreignKey: 'userId' })
}
},
timestamps: true,
paranoid: true
}
You've defined paranoid as 3. Param and that is the problem.