Convert SQL query to Sequelize Query Format - mysql

I'm new to Sequelize ORM. I would like to convert SQL query to Sequelize Query.
This is my SQL query, I want to convert this query to sequelize query:
SELECT * FROM `Posts` AS `Posts`
WHERE `Posts`.user_id IN
(SELECT `Follows`.receiver_id FROM `follows` AS `Follows`
WHERE `Follows`.user_id = user_id and `Follows`.status = "accept");
I have tried this but it does not return any data:
Posts
.findAll({ where: {
user_id: { [Op.in]: [{
include: [{
model: Follows,
attributes: ['receiver_id'],
where: {
user_id: user_id,
status:status
}
}]
}]
}
}})
.then(users => { res.send(users); })
After Executing above code it gives error in console
SELECT `event_id`, `user_id`, `event_message`, `e_imagepath`,
`createdAt`, `updatedAt`, `receiver_id`
FROM `Posts` AS `Posts`
WHERE `Posts`.`user_id` IN ('[object Object]');
I would like to convert SQL query to Sequelize Query.

You put your incude in the wrong position. Sequelize does not have a subquery feature as far I am aware of.
So you could do instead:
Posts
.findAll({ where: { user_id: user_id},
include: [{
model: Follows,
attributes: ['receiver_id'],
where: {
user_id: user_id,
status:status
}
}]
})
.then(users => { res.send(users); })
If the example above does not suits your need. You can also try to use a subquery by mixing raw SQL with Sequelize as the link below describes:
stackoverflow.com/questions/28286811/sequelize-subquery-as-field

This works fine.
router.get('/posts', function(req, res)
{
const user_id = req.session.user_id;
const status = "accept";
Posts.findAndCountAll({include:[{ model: Likes},{ model: Comments},{ model: Users}],
where:{user_id:{[Op.in]:[sequelize.literal('SELECT `Follows`.receiver_id FROM `follows` AS `Follows` WHERE `Follows`.user_id=1 and `Follows`.status="accept')]}}
})
.then((postdata)=>
{
Users.findAll({where:{user_id:user_id}})
.then((userdata)=>
{
res.send(postdata.rows)
// res.render('home',{title:'home',items:postdata.rows,user:userdata});
})
.catch((err)=>
{
})
})
.catch((err)=>
{
})
});

Related

Sorting of the sequencing belongstomany relationship does not work

The post and user tables created through sequencing have a belongstomany relationship, and a mapping table called like is created.
db.Post.belongsToMany(db.User, { through: 'Like', as: 'Likers' });
db.User.belongsToMany(db.Post, { through: 'Like', as: 'Liked' });
Using this, I wrote the following router to sort posts by the most likes.
const express = require('express');
const { Sequelize, Op } = require('sequelize');
const { Post, User, Image, Comment } = require('../models');
const router = express.Router();
router.get('/top', async (req, res, next) => { // loadTopPostsAPI / GET /posts/top
try {
const posts = await Post.findAll({
limit: 20,
offset: 0,
// Sort posts by the most likes
order: [[Sequelize.literal("(COUNT(`Likers->Like`.`PostId`))"), "ASC"]],
include: [{
model: User, // Post author
attributes: ['id', 'nickname'],
}, {
model: Image, // Post image
}, {
model: Comment, // Post Comment
include: [{
model: User, // Post Comment author
attributes: ['id', 'nickname'],
}],
}, {
model: User, // People who liked the post
as: 'Likers',
attributes: ['id'],
}],
})
res.status(200).json(posts);
} catch (error) {
console.error(error);
next(error);
}
});
But when I run the router, I get the following error
code: 'ER_BAD_FIELD_ERROR',
errno: 1054,
sqlState: '42S22',
sqlMessage: "Unknown column 'Likers->Like.PostId' in 'order clause'",
sql: 'SELECT `Post`.*, `User`.`id` AS `User.id`, `User`.`nickname` AS `User.nickname`, `Images`.`id` AS `Images.id`, `Images`.`src` AS `Images.src`, `Images`.`createdAt` AS `Images.createdAt`, `Images`.`updatedAt` AS `Images.updatedAt`, `Images`.`PostId` AS `Images.PostId`, `Comments`.`id` AS `Comments.id`, `Comments`.`content` AS `Comments.content`, `Comments`.`createdAt` AS `Comments.createdAt`, `Comments`.`updatedAt` AS `Comments.updatedAt`, `Comments`.`UserId` AS `Comments.UserId`, `Comments`.`PostId` AS `Comments.PostId`, `Comments->User`.`id` AS `Comments.User.id`, `Comments->User`.`nickname` AS `Comments.User.nickname`, `Likers`.`id` AS `Likers.id`, `Likers->Like`.`createdAt` AS `Likers.Like.createdAt`, `Likers->Like`.`updatedAt` AS `Likers.Like.updatedAt`, `Likers->Like`.`PostId` AS `Likers.Like.PostId`, `Likers->Like`.`UserId` AS `Likers.Like.UserId` FROM (SELECT `Post`.`id`, `Post`.`title`, `Post`.`desc`, `Post`.`ingredient`, `Post`.`recipes`, `Post`.`tips`, `Post`.`tags`, `Post`.`createdAt`, `Post`.`updatedAt`, `Post`.`UserId` FROM `posts` AS `Post` ORDER BY (COUNT(`Likers->Like`.`PostId`)) ASC LIMIT 0, 20) AS `Post` LEFT OUTER JOIN `users` AS `User` ON `Post`.`UserId` = `User`.`id` LEFT OUTER JOIN `images` AS `Images` ON `Post`.`id` = `Images`.`PostId` LEFT OUTER JOIN `comments` AS `Comments` ON `Post`.`id` = `Comments`.`PostId` LEFT OUTER JOIN `users` AS `Comments->User` ON `Comments`.`UserId` = `Comments->User`.`id` LEFT OUTER JOIN ( `Like` AS `Likers->Like` INNER JOIN `users` AS `Likers` ON `Likers`.`id` = `Likers->Like`.`UserId`) ON `Post`.`id` = `Likers->Like`.`PostId` ORDER BY (COUNT(`Likers->Like`.`PostId`)) ASC;',
parameters: undefined
},
How can I sort by resolving the above error?
Sequelize tries to form Subquery by default with associations and ORDER BY clause is composed within the subquery. However, SQL's ORDER BY has to be at the top level, so many cases when you need ORDER BY, OFFSET, LIMIT, you need to disable the subquery by adding subQuery: false. This will make Sequelize to form the query with JOIN instead of subquery.
await Post.findAll({
limit: 20,
offset: 0,
// Sort posts by the most likes
order: [[Sequelize.literal("(COUNT(`Likers->Like`.`PostId`))"), "ASC"]],
subQuery: false,
...
})
I bet this will make your current error go away but you have a new aggregation error, because this is trying to count full records which is disabled by MySQL by default. (ref: mysql error "ERROR 3029 (HY000): Expression #1 of ORDER BY contains aggregate function and applies to the result of a non-aggregated query")
To fix this issue and do count Likes by Post id, add PARTITION BY.
await Post.findAll({
limit: 20,
offset: 0,
// Sort posts by the most likes
order: [[Sequelize.literal("COUNT(`Likers->Like`.`PostId`) OVER (PARTITION BY `Post`.`id`)"), "ASC"]],
subQuery: false,
...
})

How to write an Inner Join query using sequelize ORM?

My inner join query looks as below
SELECT list.id, list.name,
sa.createdBy
FROM list
INNER JOIN data sa
ON sa.listId = list.id
WHERE sa.type = 'type1'
and sa.data = 'data1'
I am trying to write the above query using sequelize ORM.
I have written the following query but it is not giving desired result.
list.findAll({
include: [{
model: data,
required: true
where: {type: 'type1'}
}]
}).then(list => {
/* ... */
});
Your where clause doesn't fully contain the query you wrote
list.findAll({
include: [{
model: data,
required: true,
where: {
type: 'type1', // sa.type = 'type1'
data: 'data1', // sa.data = 'data1'
},
}]
}).then(lists => { // renamed to lists to prevent shadowing the "list" model variable
/* ... */
});

Query records that does not have an entry in another table using Sequelize include clause

Given Users table and Ratings table
How do I query all user records from Users table that does not have any rating record in Ratings table using Sequelize include clause
Note: Sequelize version 5.x
Thanks in advance
You can do this in two ways depending on how your models are defined.
1. Get all Users along with Ratings by using Sequelize Eager Loading. Then filter where user does not have any ratings.
const users = Users.findAll({
include: [Ratings]
});
const filteredUsers = users.filter(user => user.ratings.length === 0);
2. Get all userIds from the Ratings table and then pass these userIds to the where clause using the notIn Sequelize operator
const ratings = Ratings.findAll({
attributes: ["userId"],
group: ["userId"]
});
const userIds = ratings.map(rating => rating.userId);
const filteredUsers = Users.findAll({
where: {
userId: { [Op.notIn]: userIds }
}
});
Try incorporating a sequelize literal in the where clause:
const ratings = Ratings.findAll({
attributes: ["userId"],
group: ["userId"],
where: {
$and: [
sequelize.literal(`NOT EXISTS (
SELECT 1 FROM Ratings r
WHERE r.userId = User.id
)`),
],
},
});
Assuming you have a relationship between Users and Ratings in your models, this can be accomplished in a single query by using a left outer join followed by a filter on the client side.
In your model definition:
Users.hasMany(Ratings, { foreignKey: 'user_id' });
Ratings.belongsTo(Users, { foreignKey: 'user_id' });
In your query:
const users = await Users.findAll({
include: [
{
model: Ratings,
required: false // left outer join
}
]
});
const usersWithoutRatings = users.filter(u => u.user_ratings.length === 0);

NODEJS - Perform INNER JOIN sequelize

I want to perform an INNER JOIN using sequelize and Node. The actual SQL query looks like this:
SELECT b.id, b.title, b.author, b.image_url, s.novel_status AS status, g.genre
FROM novels b
INNER JOIN genres g
ON b.genre = g.id
INNER JOIN novel_statuses s
ON b.status = s.id
Which gives the following response:
Using sequelize as my ORM, I have tried to accomplish the above like this:
getNovel: (req, res) => {
novelModel.hasMany(statusModel, {
foreignKey: 'id'
});
statusModel.belongsTo(novelModel, {
foreignKey: 'id'
});
novelModel.hasMany(genreModel, {
foreignKey: 'id'
});
genreModel.belongsTo(novelModel, {
foreignKey: 'id'
});
novelModel
.findAll({
include: [
{
model: genreModel,
required: true,
attributes: ['genre']
},
{
model: statusModel,
required: true,
attributes: ['novel_status']
}
]
})
.then(result => res.json(result))
.catch(err => res.json(err));
},
But then the response is different, i.e. as below:
My DB:
I have tried to search for answers, but without any luck.
You should give the name of the Model Framework you use.

Sequelize Case Sensitive Query -- Using BINARY

this is my query in mysql
i want to use this query in sequelize orm
SELECT
`uid`,
`username`
FROM
`users` AS `users`
WHERE
BINARY
`users`.`username` IN ('hammad', 'sAad')
AND `users`.`status` = 'ACTIVE'
ORDER BY
FIELD(
`username`,
'hammad',
'saad.ahmed'
)
LIMIT 20;
I want sequelize query
this is the solution for finding case sensitive where condition
db.models.users.findAll({
attributes: ['uid', 'username'],
where: {
username: db.sequelize.where(
db.sequelize.literal('BINARY username IN ('),
`'${users.join("', '")}'`,
db.sequelize.literal(')'),
),
status: 'ACTIVE'
},
order: !_.isEmpty(users) ? [[db.sequelize.fn('FIELD', db.sequelize.col('username'), ...users)]] : [],
limit: 20
});
UserModel.findAll({
attributes: ['uid', 'username'],
where : {
username : {
[Op.in]: [ 'hammad' , 'sAad']
},
status : 'active'
},
order : ['username']
});
[Op.and]: where(fn('binary', col('username')), { [Op.in]: ['xxx','xxx2'] })
if you using sequelize.literal, it can lead to SQL Injection.
use this instead.
const query = {
where: {
username: sequelize.where(
sequelize.fn(
'BINARY',
sequelize.col('username')
),
username
)
}
}
Sequelize will do escape on username for you.