Sequelize Case Sensitive Query -- Using BINARY - mysql

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.

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 generate raw query to sequelize in node js?

i want to generate SELECT * from iqrosantris GROUP BY santriId DESC to sequelize,
in this code cannot display what i want
try {
const data = await Iqrosantri.findAll({
group: ["santriId"],
order: ["DESC"],
include: [
{
all: true,
},
],
});
res.status(200).json({ data });
SELECT * FROM (SELECT * FROM iqrosantris ORDER BY iqrosantris.id DESC LIMIT 18446744073709551615)AS test JOIN santris ON santris.id=test.santriId GROUP BY santriId;
solved

Convert SQL query to Sequelize Query Format

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)=>
{
})
});

Sequelize multi-table OR statement unknown column error

I'm trying to do a search on my models, I want to get all users where either the email, firstName, or lastName are like the search string, or where the UsersSecondaryEmails table (related model) includes an email like that string.
Because the parts of the OR statement are in different tables, this is getting a little tricky, and I can only find other StackOverflow answers to help me.
Here is my query (simplified):
const companiesUsersParams = {
where: {
companyId: req.params.companyId,
roleId: role.id
},
include: [{
model: models.Users,
attributes: ['id', 'firstName', 'lastName', 'email'],
where: req.query.s ? {
[Op.or]: [{
firstName: {
[Op.like]: `%${req.query.s}%`
}
}, {
lastName: {
[Op.like]: `%${req.query.s}%`
}
}, {
email: {
[Op.like]: `%${req.query.s}%`
}
}, {
'$usersSecondaryEmails.email$': {
[Op.like]: `%${req.query.s}%`
}
}]
} : null,
include: [{
model: models.UsersSecondaryEmails,
attributes: ['id', 'email'],
as: 'usersSecondaryEmails'
}]
}]
}
When req.query.s is not defined, the query runs as expected (No OR statement), so I know it is not an issue with my associations.
When I run this query WITH req.query.s defined, I get
Unknown column 'usersSecondaryEmails.email' in 'on clause'
And here is the SQL being generated (formatted as best as possible):
SELECT `companiesUsers`.`id`,
`companiesUsers`.`company_id` AS `companyId`,
`companiesUsers`.`user_id` AS `userId`,
`companiesUsers`.`role_id` AS `roleId`,
`companiesUsers`.`created_at` AS `createdAt`,
`companiesUsers`.`updated_at` AS`updatedAt`,
`user`.`id` AS `user.id`,
`user`.`first_name` AS `user.firstName`,
`user`.`last_name` AS `user.lastName`,
`user`.`email` AS `user.email`,
`user->usersSecondaryEmails`.`id` AS `user.usersSecondaryEmails.id`,
`user->usersSecondaryEmails`.`email` AS
`user.usersSecondaryEmails.email`
FROM `CompaniesUsers` AS `companiesUsers`
INNER JOIN `Users` AS `user`
ON `companiesUsers`.`user_id` = `user`.`id` AND
(`user`.`first_name` LIKE '%bob%' OR
`user`.`last_name` LIKE '%bob%' OR
`user`.`email` LIKE '%bob%' OR
`usersSecondaryEmails`.`email` LIKE '%bob%')
LEFT OUTER JOIN `UsersSecondaryEmails` AS `user->usersSecondaryEmails`
ON `user`.`id` = `user->usersSecondaryEmails`.`user_id`
WHERE `companiesUsers`.`company_id` = '1'
AND `companiesUsers`.`role_id` = 20;
Any any advice or links to documentation on multi-table OR statements in Sequelize would be great (I couldn't find anything this advanced in the documentation).
I am not sure how to modify Sequelize code for companiesUsersParams, but your final query should look like below to get desired output. This may help you to rewrite Sequelize code.
Left join on users instead of inner join.
You should move last OR option usersSecondaryEmails.email LIKE '%bob%' to UsersSecondaryEmails join condition
In the where clause, check for the condition (atleast one row should exists in either user table or usersSecondaryEmails for the userid)
SELECT companiesUsers.id,
companiesUsers.company_id AS companyId,
companiesUsers.user_id AS userId,
companiesUsers.role_id AS roleId,
companiesUsers.created_at AS createdAt,
companiesUsers.updated_at ASupdatedAt,
user.id AS user.id,
user.first_name AS user.firstName,
user.last_name AS user.lastName,
user.email AS user.email,
user->usersSecondaryEmails.id AS user.usersSecondaryEmails.id,
user->usersSecondaryEmails.email AS
user.usersSecondaryEmails.email
FROM CompaniesUsers AS companiesUsers
LEFT OUTER JOIN Users AS user ---- #1
ON companiesUsers.user_id = user.id AND
(user.first_name LIKE '%bob%' OR
user.last_name LIKE '%bob%' OR
user.email LIKE '%bob%' OR)
LEFT OUTER JOIN UsersSecondaryEmails AS user->usersSecondaryEmails
ON companiesUsers.user_id = user->usersSecondaryEmails.user_id
AND user->usersSecondaryEmails.email LIKE '%bob%' ---- #2
WHERE companiesUsers.company_id = '1'
AND companiesUsers.role_id = 20
AND (user.email is Not null OR user->usersSecondaryEmails.user_id is Not Null); ---- #3

Count subquery in a select - mongoDB

I want to make a query to get a kind of ranking of users with more tweets in my database mongoDB:
var TeewtSchema = new Schema({
userId: Number,
twweetId : Number,
createdAt: Date,
cuerpo: String,
nameUser: String,
location: String,
avatar: String,
user: String
});
MySql that output something similar to:
SELECT *, (SELECT COUNT(*) FROM `TABLE 1` WHERE userId = t.userId ) rank FROM `TABLE 1` t GROUP BY t.userId ORDER BY rank DESC
but in mongoDB i have no idea how to do
Yes, as JohnnyHK suggests, you should use the aggregation framework for this. Something like the following should do it:
db.collection.aggregate(
{ $group : { _id : "$userId", numTweets = { $sum : 1 } }, // sum tweets over each user
{ $sort : { numTweets : -1 } } // sort by numTweets in descending order
)