How do you properly change a model in sequelize? - javascript

I have the below two models, and am trying to change the userId property on the Report model to not have to be unique. When I change unique to false, or delete the property altogether, I am still getting the unique validation error when trying to create a Report with an existing userId (using models.Report.create({ userId: 1 }) when 1 is an existing user's id). I've also tried making a migration and running that to no avail.
Am I missing something here? Been stuck on this for a while, so any input is massively appreciated. Thank you.
Report.js
module.exports = (sequelize, DataTypes) => {
const Report = sequelize.define(
'Report',
userId: {
allowNull: false,
type: Sequelize.INTEGER,
unique: true,
},
);
Report.associate = function(models) {
Report.belongsTo(models.UserInfo, { foreignKey: 'userId' });
};
return Report;
};
UserInfo.js
module.exports = (sequelize, DataTypes) => {
const UserInfo = sequelize.define(
'UserInfo',
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
);
UserInfo.associate = function associate(models) {
ApplicantInfo.hasMany(models.Report, { foreignKey: 'applicantId' });
};
return ApplicantInfo;
};

Related

Sequelize – autocompletion for methods and attributes

This is my current setup:
const { Model, DataTypes } = require('sequelize');
class CustomModel extends Model {
static init(attributes, config) {
return super.init(attributes, {
...config,
timestamps: true,
underscored: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
});
}
}
class User extends CustomModel {
ahoy() {
const { email } = this.get();
console.log(`Ahoy, ${email}`);
}
}
User.init({
id: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
}, myConfigHere);
I now want to ensure that all User attributes, as well as its model methods, are showing up in VSCode autocomplete. How can I make this happen?
const user = await User.findOne({ where: { email: 'john#example.com' } });
user.email; // No autocomplete while typing
user.ahoy() // No autocomplete while typing
When I change the code to class User extends Model, then I can see the ahoy() being autocompleted, yet this does not apply to .email
Is there a way to fix this (e.g. with JSDoc)?
If you are using pure Javascript you won't be able to do that.
Consider using Typescript, then VSCode (or any editor really) will be able to watch your Object and suggest what attribute you want from it.

1:N relationship query to find one in Sequelize.js not working properly

I have started learning sequelize.js with node.js and having hard time defining relationships between models. I am trying to create 1:N relationship between users and roles tables i.e. many users can have same role.
Problem
When I query user model to test the defined relation ship it gives me error that original: error: column "RoleId" does not exist.
roles model:
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Role 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
Role.hasMany(models.User, {as: 'users'});
}
}
Role.init({
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
name:{
type: DataTypes.STRING,
allowNull: false
}
}, {
sequelize,
modelName: 'Role',
tableName: 'roles',
});
return Role;
};
users model:
'use strict';
const {
Model
} = require('sequelize');
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.belongsTo(models.Role, {foreignKey: 'roleId', as: 'role'});
User.belongsTo(models.Role);
}
}
User.init({
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false
},
mobile: {
type: DataTypes.STRING,
allowNull: false
}
// },
// roleId: {
// type: DataTypes.STRING,
// allowNull: false
// }
}, {
sequelize,
tableName: 'users',
modelName: 'User',
});
return User;
};
relationship tester js code:
const { User, Role } = require('./models');
User.findOne({
where: {email: 'admin#papertrader.org'}
})
.then((findedUser) => {
console.log(findedUser)
})
.catch((err) => {
console.log("Error while find user : ", err)
});
Can anyone one please guide me what is wrong with my code?

Why does Sequelize is inverting the INSERT query it produces by calling the custom N:N method?

Good evening.
I have a database with the following N:N association:
-> BlogPost.belogsToMany(Category through: PostsCategories)
-> Category.belongsToMany(BlogPost through: PostsCategories)
PostsCategories being the junction table's model.
On the process of inserting one BlogPost to the database, I have to catalog in which categories does it fall under on the junction table. So following some examples on the documentation I came up with:
const blogPost = await BlogPost.create({ title, content, userId });
await blogPost.addCategories(categoriesList);
So far so good, but there was an error. Basically Sequelize is inverting the order on the columns/values when writing the query. If I add
blogPost: { id: 3, categories: [1, 2] }
it produces this query:
"'INSERT INTO `PostsCategories` (`categoryId`,`postId`) VALUES (3,1),(3,2);'"
It's inverted and I've tried a gazillion things and it doesn't work. :(
Any thoughts on this?
Thanks!
EDIT: MY MODELS
module.exports = (sequelize, DataTypes) => {
const Category = sequelize.define('Category', {
name: DataTypes.STRING,
},
{ tableName: 'Categories', timestamps: false });
Category.associate = (models) => {
const { BlogPost, PostsCategories } = models;
Category.belongsToMany(
BlogPost, { through: PostsCategories, foreignKey: 'postId', as: 'blogPosts' },
);
};
return Category;
};
module.exports = (sequelize, DataTypes) => {
const BlogPost = sequelize.define('BlogPost', {
title: DataTypes.STRING,
content: DataTypes.STRING,
userId: DataTypes.INTEGER,
},
{ tableName: 'BlogPosts', timestamps: true, createdAt: 'published', updatedAt: 'updated' });
BlogPost.associate = (models) => {
const { User, PostsCategories, Category } = models;
BlogPost.belongsToMany(
Category, { through: PostsCategories, foreignKey: 'categoryId', as: 'categories' },
);
BlogPost.belongsTo(User, { foreignKey: 'userId', as: 'user' });
};
return BlogPost;
};
module.exports = (sequelize, _DataTypes) => {
const PostsCategories = sequelize.define('PostsCategories',
{},
{ timestamps: false, tableName: 'PostsCategories' });
return PostsCategories;
};
I got my answer. Lol.
My association declarations were faulty.
BlogPost.belongsToMany(
Category, { through: PostsCategories, foreignKey: 'categoryId', as: 'categories' },
);
Actually the foreignKey is related to the BlogPost on the junction table.
I also inverted my declaration to being able to "read" it better.
BlogPost.belongsToMany(
Category, { as: 'categories', through: PostsCategories, foreignKey: 'postId' },
);
BlogPost belongsToMany Category
if I query a BlogPost and want it with every category it'll return as 'categories'
the association is established through PostsCategories
the way the BlogPost associate with PostsCategories is with the foreignKey 'postId'

How to use Sequelize associations with .then in controller

This is my ToWatch Model in toWatch-model.js file which in code has UserModel->ToWatch 1:1 relationship and has ToWatch->MovieModel 1:M relationship.
const Sequelize = require('sequelize');
const sequelize = require('./../common/db-config');
const MovieModel = require ("./movie-model");
const UserModel = require("./user-model");
const Model = Sequelize.Model;
class ToWatch extends Model{}
ToWatch.init({
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'id_towatch'
},
date: {
type: Sequelize.DATE,
allowNull: false,
field: 'date'
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
field: 'id_user',
references:{
model: UserModel,
key: "id"
}
},
movieId: {
type: Sequelize.INTEGER,
allowNull: false,
field: 'movie_id_towatch',
references:{
model: MovieModel,
key: "id"
}
},
},
{
sequelize,
modelName: 'towatch',
tableName: 'towatch',
timestamps: false
// options
});
//Here is the relation ************
UserModel.hasOne(ToWatch, {
foreignKey: {
type:Sequelize.DataTypes.INTEGER,
allowNull:false,
name:'fk_foreign_key_towatch'
}
});
ToWatch.belongsTo(UserModel);
ToWatch.hasMany(MovieModel, {
foreignKey: {
type:Sequelize.DataTypes.INTEGER,
allowNull:false,
name:'movie_id_towatch'
}
});
MovieModel.belongsTo(ToWatch);
module.exports = ToWatch;
I watched many tutorials, but being my first time trying to make a method that will return everything including something from my other table via ID, I wasn't sure where to put and how to put data that I need in this method, considering it has .then(data=>res.send). Tutorials were doing it other ways by fetching or using async-await, and even documentation didn't help me here. Can somebody tell me what to put and where inside this method, that is inside toWatch-controller.js file for me being able to see let's say all the movie data (title,img,date) ,as an array I think, of the getToWatch method.
const ToWatch = require('./../models/toWatch-model');
module.exports.getToWatch = (req,res) => {
ToWatch.findAll().then(toWatch => {
[WHAT DO I PUT HERE?]
res.send(toWatch);
}).catch(err => {
res.send({
status: -1,
error:err
})
})
}
I need something like this ToWatch{
color:red,
cinema:"MoviePlace",
movieId{title:"Anabel", img:"URL", date:1999.02.23}
As I understood your question right, what you trying to do is return toWatch model instances with including User and Movie models.
To do so you can pass options in findAll() method like below:
ToWatch.findAll({include: [{model: User}, {model: Movie}]})... //and rest of your code
Or alternatively to keep your code clean you can use scopes:
// below the toWatch-model.js file
ToWatch.addScope('userIncluded', {include: {model: User}})
ToWatch.addScope('movieIncluded', {include: {model: Movie}})
And in the getToWatch method:
// you can pass several scopes inside scopes method, its usefull when you want to combine query options
ToWatch.scopes('userIncluded', 'movieIncluded').findAll()... //rest of your code
For more information check out sequelize docs

Sequelize: Create with Association not working

I have three models: User, Teacher and a Student. A user can either be a teacher or a student depending upon the role.
Now, I would like to populate the Teacher and the Student model as the User model gets populated. This is the query that I am using which isn't populating the Teacher model. (And the student model as well on the other condition)
const user = await User.create({
...userDetails
include: [Teacher]
})
User Model:
const User = connObj.define('user', {
name: {
type: Sequelize.TEXT,
allowNull: false
},
username: {
type: Sequelize.STRING(50),
allowNull: false
},
email: {
type: Sequelize.TEXT,
allowNull: false
},
password: {
type: Sequelize.STRING(100),
allowNull: false,
set (password) {
const passHash = bcrypt.hashSync(password, salt)
this.setDataValue('password', passHash)
}
},
isTeacher: {
type: Sequelize.BOOLEAN,
defaultValue: false
}
})
Teacher Model:
const Teacher = connObj.define('teacher', {})
And the relation is
User.hasMany(Teacher)
User.hasMany(Student)
I have followed what is mentioned in the Sequelize docs and also other Stack Overflow answers but it just doesnt seem to work.

Categories

Resources