Sequelize validation doesn't work on PUT method - javascript

I'm pretty new to Sequelize. Here's a model that I have. The validation seems to be working fine on POST method, but it doesn't work on PUT method. I'm not sure what I'm missing here. I'd appreciate all the help guys.
const Sequelize = require('sequelize');
module.exports = (sequelize) => {
class Course extends Sequelize.Model {}
Course.init({
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
title: {
type: Sequelize.STRING,
allowNull: false,
validate: {
notNull: {
msg: 'Please provide a value for "title"'
},
notEmpty: {
msg: 'Please provide a value for "title"'
}
}
},
description: {
type: Sequelize.TEXT,
allowNull: false,
validate: {
notNull: {
msg: 'Please provide a value for "description"'
},
notEmpty: {
msg: 'Please provide a value for "description"'
}
}
}
}, { sequelize });
Course.associate = (models) => {
Course.belongsTo(models.User, {
foreignKey: {
fieldName: 'userId',
allowNull: false
}
})
};
return Course
}
Here's my code on main route.
router.put('/courses/:id', asyncHandler(async(req, res) => {
try {
const course = await Course.findByPk(req.params.id)
await course.update(req.body);
res.status(204).end();
} catch (error) {
console.error(error);
}
}));

Related

How to find several fields of a foreign key in a join table in Node.js Sequelize

I have a Node.js application with Express, Sequelize as ORM and PostgreSQL for the database. In this app I have candidate model and mission model as below.
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class candidat extends Model {
static associate(models) {
this.belongsToMany(models.mission, {
through: "candidat_mission",
foreignKey: "candidatId",
otherKey: "idMission",
});
}
}
candidat.init({
candidatId: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
lastName: {
type: DataTypes.STRING,
allowNull: false,
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
isEmail: true,
allowNull: false,
type: DataTypes.STRING,
unique: true,
},
}, {
sequelize,
modelName: 'candidat',
tableName: 'candidat',
freezeTableName: true,
});
return candidat;
};
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class mission extends Model {
static associate(models) {
this.belongsToMany(models.candidat, {
through: "candidat_mission",
foreignKey: "idMission",
otherKey: "candidatId",
})
}
}
mission.init({
idMission: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
title: {
type: DataTypes.STRING,
allowNull: false
},
aliasTitle: {
type: DataTypes.STRING,
allowNull: true
},
description: {
type: DataTypes.TEXT,
allowNull: true
}
}, {
sequelize,
modelName: 'mission',
tableName: 'mission',
freezeTableName: true,
});
return mission;
};
These two models are linked in many-to-many by a candidate_mission join table. In this model, I added fields like a foreign key which points to another table, that of users.
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class candidat_mission extends Model {
static associate(models) {
this.belongsTo(models.user, { foreignKey: "fk_user" });
}
}
candidat_mission.init({
candidatMissionId: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
candidatId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: { tableName: 'candidat' },
key: "candidatId",
},
},
idMission: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: { tableName: 'mission' },
key: "idMission",
},
},
fk_user: {
type: DataTypes.INTEGER,
allowNull: true,
references: {
model: { tableName: 'user' },
key: "userId",
},
},
}, {
sequelize,
modelName: 'candidat_mission',
tableName: 'candidat_mission',
timestamps: true,
freezeTableName: true,
});
return candidat_mission;
};
When I make a "GET" request, I do have the information from the candidate_mission table (if a candidate is linked to this mission), but for the user it only returns the ID and I would like it to return all the fields present in the Users model, what can I do?
Here, my function in the mission controller which allows to add a candidate to this mission :
const addCandidats = async (req, res) => {
try {
const mission = await Mission.findByPk(req.body.idMission);
if (mission) {
const candidat = await Candidat.findByPk(req.body.candidatId);
if (candidat) {
mission.addCandidat(candidat,
{through: {
fk_user: req.body.fk_user && req.body.fk_user
}});
return res.status(200).send(mission);
} else {
console.log("Candidat non trouvé");
return null;
}
} else {
console.log("Mission non trouvée!")
return null;
}
} catch (error) {
console.log(error);
}
};
Currently, my query returns me this :
"candidat_mission":
{
"candidatMissionId": 2,
"candidatId": 1,
"idMission": 7,
"fk_user": 1,
"createdAt": "2023-02-14T10:34:08.302Z",
"updatedAt": "2023-02-14T15:06:10.232Z"
},
And i want it to come back to me :
"candidat_mission":
{
"candidatMissionId": 2,
"candidatId": 1,
"idMission": 7,
"fk_user": {
"userId": 1,
"email": "blabla#gmail.com",
"name": "blabla"
},
"createdAt": "2023-02-14T10:34:08.302Z",
"updatedAt": "2023-02-14T15:06:10.232Z"
},
After associating 2 models, we have to query again to get the object along with the relationship.
await mission.addCandidat(candidat,
{through: {
fk_user: req.body.fk_user && req.body.fk_user
}});
const result = await CandidatMission.findOne({
where: { candidatId: req.body.candidatId, idMission: req.body.idMission },
include: models.user,
})
return res.status(200).send(result);

Checking if two values match from one to another table

So I started doing a app with JavaScript ORM- Sequelize.
I have a table called Workouts.js where the exercises are the id's in a table called Exercises.js.
Workouts.js
id
exercise_one
exercise_two
exercise_three
date
1
1
2
4
2022-02-21
2
4
3
2
2022-02-23
3
3
1
1
2022-02-25
I have another table called Workout_Volume.js which has the following values:
Workout_Volume.js
id
workout_id
exercise_id
sets
reps
weight
1
1
1
3
10
60
2
1
4
4
12
40
3
3
3
3
15
30
4
2
4
5
5
80
So my question is what is the correct way to validate in Workout_Volume.js workouit_id and exercise_id match as in Workouts.js when creating and updating Workout_Volume.js?
Workouts.js
const workout = (sequelize, DataTypes) => {
const Workout = sequelize.define(
'workouts', {
exercise_one: {
type: DataTypes.INTEGER(), allowNull: false,
references: { model: "exercises", key: "id" },
validate: {
notNull: { msg: "You need to provide exercise_id !" }
}
},
exercise_two: {
type: DataTypes.INTEGER(), allowNull: true,
references: { model: "exercises", key: "id" },
},
exercise_three: {
type: DataTypes.INTEGER(), allowNull: true,
references: { model: "exercises", key: "id" },
},
exercise_four: {
type: DataTypes.INTEGER(), allowNull: true,
references: { model: "exercises", key: "id" },
},
exercise_five: {
type: DataTypes.INTEGER(), allowNull: true,
references: { model: "exercises", key: "id" },
},
exercise_six: {
type: DataTypes.INTEGER(), allowNull: true,
references: { model: "exercises", key: "id" },
},
exercise_seven: {
type: DataTypes.INTEGER(), allowNull: true,
references: { model: "exercises", key: "id" },
},
exercise_eight: {
type: DataTypes.INTEGER(), allowNull: true,
references: { model: "exercises", key: "id" },
},
date: {
type: DataTypes.DATEONLY, allowNull: false,
validate: {
notNull: { msg: "You need to provide date !" }
}
}
},
{
timestamps: false,
freezeTableName: true,
})
Workout.associate = models => {
Workout.belongsToMany(models.exercises, {
foreignKey: "exercise_one",
through: 'exerciseOne',
targetKey: "id"
})
Workout.belongsToMany(models.exercises, {
foreignKey: "exercise_two",
through: 'exercisTwo',
targetKey: "id"
})
Workout.belongsToMany(models.exercises, {
foreignKey: "exercise_three",
through: 'exerciseThree',
targetKey: "id"
})
Workout.belongsToMany(models.exercises, {
foreignKey: "exercise_four",
through: 'exerciseFour',
targetKey: "id"
})
Workout.belongsToMany(models.exercises, {
foreignKey: "exercise_five",
through: 'exerciseFive',
targetKey: "id"
})
Workout.belongsToMany(models.exercises, {
foreignKey: "exercise_six",
through: 'exerciseSix',
targetKey: "id"
})
Workout.belongsToMany(models.exercises, {
foreignKey: "exercise_seven",
through: 'exerciseSeven',
targetKey: "id"
})
Workout.belongsToMany(models.exercises, {
foreignKey: "exercise_eight",
through: 'exerciseEight',
targetKey: "id"
})
Workout.belongsTo(models.workout_volume, {
foreignKey:"id",
targetKey: "workout_id",
through: "workout_volume"
})
}
Workout.sync()
return Workout
}
module.exports = workout
Workout_Volume.js
const workoutVolume = (sequelize, DataTypes) => {
const Workout_Volume = sequelize.define(
'workout_volume', {
workout_id: {
type: DataTypes.INTEGER, allowNull: false,
references: { model: "workouts", key: "id" },
validate: {
notNull: { msg: "You need to provide workout_id !" }
}
},
exercise_id: {
type: DataTypes.INTEGER, allowNull: false,
validate: {
notNull: { msg: "You need to provide exercise_id !" }
},
},
sets: {
type: DataTypes.INTEGER, allowNull: false,
validate: {
min: 1,
max: 100,
notNull: { msg: "You need to provide sets!" }
}
},
reps: {
type: DataTypes.INTEGER, allowNull: false,
validate: {
min: 1,
max: 100,
notNull: { msg: "You need to provide reps!" }
}
},
weight: {
type: DataTypes.INTEGER, allowNull: false,
validate: {
min: 0,
max: 1000,
notNull: { msg: "You need to provide sets!" }
}
}
},
{
timestamps: false,
freezeTableName: true,
},
)
Workout_Volume.associate = models => {
Workout_Volume.belongsTo(models.workouts,{
foreignKey: "workout_Id",
as: "workoutId",
targetKey: "id"
})
}
Workout_Volume.sync()
return Workout_Volume
}
module.exports = workoutVolume
My thoughts on making is:
To make associations with exercise_id to each exercise value in Workouts.js. The problem is that the exercises are 8 and I think the project will become more hard-coded;
Don't make assosiactions but make a for loop where I will check if the requested workout_id and exercises_id match the Workout.js values;
Or if there is better way to consturct the tables so it makes more sence
Or if there is better way to construct tables or something else.
workoutVolume.controller.js
const models = require('../models');
const Workout_Volume = models.workout_volume;
exports.getAllWorkouts_Volume = async (req, res) => {
try {
const workout_volume = await Workout_Volume.findAll()
return res.status(200).send(workout_volume)
} catch (error) {
return res.status(500).send(error)
}
}
exports.getWorkout_Volume = async (req, res) => {
try {
const workout_volume = await Workout_Volume.findByPk(req.params.id)
res.status(200).send(workout_volume)
} catch (error) {
return res.status(500).send(error)
}
}
exports.createWorkout_Volume = async (req, res) => {
try {
const exerciseExists = await Workout_Volume.findAll({
where: {
exercise_id: req.body.exercise_id,
workout_id: req.body.workout_id
},
attributes: ["exercise_id", "workout_id"]
})
if (exerciseExists.length !== 0) {
return res.status(500).send("Exercise already done for this workout!")
}
await Workout_Volume.create(req.body)
return res.status(201).send(req.body)
} catch (error) {
return res.status(500).send(error)
}
}
exports.updateWorkout_volume = async (req, res) => {
try {
const workout_volume = await Workout_Volume.findByPk(req.params.id)
console.log(req.body)
const exerciseExists = await Workout_Volume.findAll({
where: {
exercise_id: req.body.exercise_id,
workout_id: req.body.workout_id
},
attributes: ["exercise_id", "workout_id"]
})
if (exerciseExists.length !== 0) {
return res.status(500).send("Exercise already done for this workout!")
}
await workout_volume.update(req.body)
return res.status(200).send(req.body)
} catch (error) {
return res.status(500).send(error)
}
}
The problem here is that when I create I can't create invalid workout_id but can create exercise_id which is not in Workout.js.
Also when I try to update it already the length is !== 0
You definitely need to create a table/model Workout_Excercise instead of adding columns in Workout table/model. That way you will have as many exercises in a certain workout as you want.
And the second great benefit of having Workout_Excercise is that you will be able to create a correct foreign key from Workout_Volume to Workout_Excercise:
Workout.hasMany(models.workoutExercises, {
foreignKey: "workoutId",
})
WorkoutExercise.belongsTo(models.exercises, {
foreignKey: "exerciseId",
})
WorkoutExercise.hasMany(models.workout_volume, {
foreignKey: "workoutExerciseId",
})
WorkoutVolume.belongsTo(models.workout_exercise, {
foreignKey: "workoutExerciseId",
})

Node JS API Sequelize PostgreSQL UUID as primary key return error "column Nan does not exist"

I'm working on a REST API for the backend of a simple e-commerce app using Node JS, PostgreSQL and Sequelize, and I'm facing an issue with Sequelize when I try to add a product to the shopping cart. It returns an error "column Nan does not exist"
Initially I was using Integer for the user Id as the primary key, then I changed for UUID to better suit the purpose.
The code I'm using for the models and migrations is the following:
//User model
export default (sequelize, DataTypes) => {
const User = sequelize.define(
'User',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true,
unique: true,
},
name: {
type: DataTypes.STRING,
allowNull: false
},
password: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: {
name: 'user_email',
msg: 'A user with this email already exists.'
}
},
},
User.associate = models => {
User.hasOne(models.Cart, {
foreignKey: 'userId',
as: 'cart',
onDelete: 'cascade'
});
};
User.associate = models => {
User.hasMany(models.Order, {
foreignKey: 'userId',
as: 'orders',
onDelete: 'cascade'
});
};
return User;
};
//User migration
export const up = (queryInterface, Sequelize) =>
queryInterface.createTable('Users', {
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true,
unique: true,
},
name: {
allowNull: false,
type: Sequelize.STRING
},
password: Sequelize.STRING,
email: {
allowNull: false,
type: Sequelize.STRING,
unique: true
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('now')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('now')
},
});
export const down = queryInterface => queryInterface.dropTable('Users');
Cart model
export default (sequelize, DataTypes) => {
const Cart = sequelize.define('Cart', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true,
},
userId: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false
},
cartItem: {
type: DataTypes.TEXT,
allowNull: false,
get(value) {
return JSON.parse(this.getDataValue(value));
},
set(value) {
this.setDataValue('cartItem', JSON.stringify(value));
}
}
});
Cart.associate = models => {
Cart.belongsTo(models.User, {
foreignKey: 'userId',
as: 'owner'
});
};
return Cart;
};
Cart migration
export const up = (queryInterface, Sequelize) =>
queryInterface.createTable('Carts', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
},
userId: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false
},
cartItem: {
type: Sequelize.TEXT,
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('now')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('now')
}
});
export const down = queryInterface => queryInterface.dropTable('Carts');
Code to handle the add to cart:
addToCart() {
return this.asyncWrapper(async (req, res) => {
const { body, user } = req;
body.userId = user.id;
const cart = await this.service.addToCart(body);
this.sendResponse(res, cart, undefined, 201);
});
}
Add to cart service
async cart(userId, options = {}) {
const cart = await super.find({ userId }, options);
return cart;
}
async addToCart(data, options) {
const { userId, productId, qty } = data;
const [result] = await this.model.findOrCreate({
where: { userId: +userId },
defaults: { cartItem: new CartItem() }
});
const cartData = JSON.parse(result.dataValues.cartItem);
const cartItem = new CartItem(cartData);
const product = await ProductService.getById(productId, { plain: true });
ExceptionHandler.throwErrorIfNull(product);
const cart = cartItem.addToCart(product, qty);
result.cartItem = cart;
result.save();
return result;
}
The SQL query generated by Sequelize is the following:
SELECT "id","userId","cartItem","createdAt","updatedAt" FROM "Carts" AS "Cart" WHERE "Cart"."userId" = NaN LIMIT 1;
The goal is to use UUID as primary key in the database.
This issue started when I changed the Datatype from Integer for UUID and I can't see what is wrong with the code.
Any advice on how to solve this?
Sequelize version: "^5.21.9" with "pg": "^8.2.0" and "pg-hstore": "^2.3.3".
If you switched a data type from INTEGER to UUID you shouldn't try to convert UUID-string to a number doing where: { userId: +userId }.
Pass userId as is:
where: { userId }

Sequelize how to join 2 tables 1:N

I have 2 models: User and Foto
Each User has a lot of fotos, and each foto can have just 1 user related.
To do that i use include, the problem is, i can use the include just when i am querying the user and not when i query the foto.
I get there is no relationshop between User and foto problem.
So at the moment i have this:
Model User:
"use strict";
var sequelize = require('./index');
var bcrypt = require('bcrypt-nodejs');
var Foto = require('./Foto');
module.exports = function (sequelize, DataTypes) {
var User = sequelize.define("User", {
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isUnique: function (value, next) {
var self = this;
User.find({ where: { username: value } })
.then(function (user) {
// reject if a different user wants to use the same username
if (user && self.id !== user.id) {
return next('username already in use!');
}
return next();
})
.catch(function (err) {
return next(err);
});
}
}
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isUnique: function (value, next) {
var self = this;
User.find({ where: { email: value } })
.then(function (user) {
// reject if a different user wants to use the same email
if (user && self.id !== user.id) {
return next('Email already in use!');
}
return next();
})
.catch(function (err) {
return next(err);
});
}
}
},
typeOfUser: {
type: DataTypes.INTEGER,
allowNull:false,
defaultValue:2
},
country: {
type: DataTypes.STRING,
allowNull:true,
defaultValue:null
},
birthDate:{
type: DataTypes.DATEONLY,
allowNull:true,
defaultValue:null
},
reports: {
type: DataTypes.INTEGER,
defaultValue: 0
},
points: {
type: DataTypes.INTEGER,
defaultValue: 0
},
password: {
type: DataTypes.STRING,
allowNull:false
},
numberFotos: {
type: DataTypes.INTEGER,
defaultValue: 0
}
}, {
classMethods: {
generateHash: function (password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
},
associate: function(models){
User.hasMany(models.Foto,{foreignKey: "userId", as: "Fotos"});
}
},
instanceMethods: {
validPassword: function (password) {
return bcrypt.compareSync(password, this.password);
}
}
});
return User;
}
Model Foto:
"use strict";
var sequelize = require('./index');
var bcrypt = require('bcrypt-nodejs');
var User = require('./User');
module.exports = function (sequelize, DataTypes) {
var Foto = sequelize.define("Foto", {
reports: {
type: DataTypes.INTEGER,
defaultValue: 0
},
image: {
type: DataTypes.STRING,
allowNull: false
},
date: {
type: DataTypes.DATE,
allowNull: true
},
lat: {
type: DataTypes.STRING,
allowNull: true
},
lon: {
type: DataTypes.STRING,
allowNull: true
},
altitude: {
type: DataTypes.STRING,
allowNull: true
},
userId: {
type: DataTypes.INTEGER,
allowNull: false
},
plantId: {
type: DataTypes.INTEGER,
allowNull: true
},
},
{
associate: function (models) {
Foto.belongsToMany(models.User, {as:'Users'});
}
}
);
return Foto;
}
then i try to get something like this in a json three:
[{
FotoA:{
prop1:value1,
prop2:value2,
user:{
userProp1
}
}
FotoB:{
}
}]
on my route i do the following:
allPictures: function (req, res) {
Foto.findAll({include: [{ model: User, as: "Users",where:{userId: User.id} }]})
.then(function (fotos) {
res.send(fotos);
})
},
if there is a better way to do this instad of eager loading please share it, i just need to get the userId and the username.
Thanks
I guess you defined the association wrong, as you mentioned a Foto should belong to one User.
try
Foto.belongsTo(model.User);
instead of
associate: function (models) {
Foto.belongsToMany(models.User, {as:'Users'});
}
And also there should be no need for the where clause when selecting. If your associations are defined correctly, you can simply do
Foto.findAll({include: [models.User]})

How can I achieve this SQL QUERY in sequelize (multiple joins and multiple AND/OR)

I've been struggling to achieve this (below SQL statement) in sequelize for a while now with no luck. I initially had to make separate sequelize queries to get the data but that just posed many limitations.
`SELECT "Documents".* FROM "Documents"
INNER JOIN "AccessTypes"
ON "AccessTypes"."id" = "Documents"."accessTypeId"
INNER JOIN "Users"
ON "Users"."id" = "Documents"."userId"
INNER JOIN "Departments"
ON "Departments"."id" = "Users"."departmentId"
WHERE
(("AccessTypes".name != 'private'
AND "Departments"."id" = ${req.decoded.departmentId})
OR "Users".id = ${req.decoded.id})
AND ("Documents"."title" ILIKE '%${searchQuery}%'
OR "Documents"."content" ILIKE '%${searchQuery}%'`
This is as far as I got
var dbQuery = {
where: {
$or: [
{
title: {
$iLike: `%${searchQuery}%`
}
},
{
content: {
$iLike: `%${searchQuery}%`
}
}
]
},
include: [{
model: db.Users,
where: { departmentId: req.decoded.departmentId }
},
{
model: db.AccessTypes,
where: { name: { $ne: 'private'}}
}]
};
db.Documents.findAll(dbQuery)
I still need to fetch another set of documents based on the userId supplied. I feel the way to go will be to perform an 'Include' within an '$or' statement. however my research so far leads me to believe that's not possible.
Here are my models
Access Types
export default (sequelize, DataTypes) => {
const AccessTypes = sequelize.define('AccessTypes', {
name: {
type: DataTypes.STRING,
allowNull: false,
isUnique: true
}
}, {
classMethods: {
associate: (models) => {
// associations can be defined here
AccessTypes.hasMany(models.Documents, {
foreignKey: 'accessTypeId',
onDelete: 'CASCADE'
});
}
}
});
return AccessTypes;
};
Users
export default (sequelize, DataTypes) => {
const Users = sequelize.define('Users', {
username: {
type: DataTypes.STRING,
unique: true,
allowNull: false
},
firstname: {
type: DataTypes.STRING,
allowNull: false
},
lastname: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
validate: {
isEmail: true
}
},
password: {
type: DataTypes.STRING,
allowNull: false
},
roleId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 3
},
departmentId: {
type: DataTypes.INTEGER,
allowNull: false
}
}, {
classMethods: {
associate: (models) => {
// associations defined here
Users.belongsTo(models.Roles, {
onDelete: 'CASCADE',
foreignKey: 'roleId'
});
Users.belongsTo(models.Departments, {
onDelete: 'CASCADE',
foreignKey: 'departmentId'
});
Users.hasMany(models.Documents, {
as: 'documents',
foreignKey: 'userId',
onDelete: 'CASCADE'
});
}
}, ...
Departments
export default (sequelize, DataTypes) => {
const Departments = sequelize.define('Departments', {
name: {
type: DataTypes.STRING,
allowNull: false,
isUnique: true
}
}, {
classMethods: {
associate: (models) => {
// associations can be defined here
Departments.hasMany(models.Users, {
foreignKey: 'departmentId',
onDelete: 'CASCADE'
});
}
}
});
return Departments;
};
and Documents
export default (sequelize, DataTypes) => {
const Documents = sequelize.define('Documents', {
title: {
type: DataTypes.STRING,
allowNull: false
},
content: {
type: DataTypes.TEXT,
allowNull: false
},
userId: {
type: DataTypes.INTEGER,
allowNull: false
},
accessTypeId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1
},
docTypeId: {
type: DataTypes.INTEGER,
allowNull: false
}
}, {
classMethods: {
associate: (models) => {
// associations can be defined here
Documents.belongsTo(models.Users, {
foreignKey: 'userId',
as: 'user',
onDelete: 'CASCADE'
});
Documents.belongsTo(models.DocumentTypes, {
foreignKey: 'docTypeId',
onDelete: 'CASCADE'
});
Documents.belongsTo(models.AccessTypes, {
foreignKey: 'accessTypeId',
onDelete: 'CASCADE'
});
}
}
});
return Documents;
};
Any Pointers Will be greatly appreciated
Thanks in Advance
This is quite complex query (in Sequelize way of course), so you need to build it differently than you did. You should use functions like sequelize.col(), sequelize.where(), sequelize.or() and sequelize.and(). Moreover, in order to include the Departments model in the query, you need to use nested include statement in the options object of the findAll query. You can nest the includes as much as you want.
where: sequelize.and(
sequelize.or(
sequelize.and(
sequelize.where(sequelize.col('AccessTypes.name'), '!=', 'private'),
sequelize.where(sequelize.col('Departments.id'), '=', req.decoded.departmentId)
),
sequelize.where(sequelize.col('Users.id'), '=', req.decoded.id)
),
sequelize.or(
{ title: { $iLike: `%${searchQuery}%` } },
{ content: { $iLike: `%{searchQuery}%` } }
)
),
include: [
{
model: db.Users,
include: [ db.Departments ]
},
{
model: db.AccessTypes
}
]
You need to briefly get through documentation of above mentioned functions. In a short, col() creates a proper column selection basing on model name and field, where() creates WHERE statement with use of three attributes - column, condition (comparator) and logic, or() creates OR statement and and() creates AND statement. Both or() and and() can obtain multiple arguments that allows you to create complex statements, like yours.

Categories

Resources