Count subquery in a select - mongoDB - mysql

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
)

Related

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

TypeORM select alias of column name

this.sampleRepo.find(
{
order: {
id: "DESC"
},
select: ['id','group']
}
);
this returns the id and group as expected, but how to return id as user_id ?
and also how to select distinct values from group?
Just add an alias in you select string, e.g.:
select: ['id AS user_id','group AS user_group']
If the previous option didn't work, it should work in queryBuilder:
this.sampleRepo
.createQueryBuilder('user')
.orderBy('user.id', 'DESC')
.select(['id AS user_id','group AS user_group'])
.getRawMany() // or .getMany()
I've made smth as you need with one of my examples (last one here) but wrote this (upd. fixed with getRawMany and distinct):
getMany(): Promise<UserEntity[]> {
return this.userRepo.createQueryBuilder('user')
.where({ username: 'breckhouse0' })
.select(['DISTINCT (user.username) AS user_name', 'user.id AS user_id'])
.getRawMany();
}
and this works as you expect - results

Spring Boot: How to create dynamic query involving 'join' and 'group by' using predicate

My post request body will be like
{
"queryCondition":[
{
"filter":"status",
"filterlist":["Closed","New","Resolved"...]
},
{
"filter":"assigned_team",
"filterlist":["A","B","C"...]
},
{
"filter":"assigned_to",
"filterlist":["ram","govind","ajith"...]
},
{
"filter":"duration",
"filterlist":["2020-02-01","2020-05-01"....]
}
....
....
],
"durationField":"created_date"
}
I receive the columns(filter) and values(filterlist) dynamically with which I need to build this query.
SELECT * FROM tickets
WHERE ticket_id IN (SELECT ticket_id FROM Tickets WHERE created_date >= '2020-02-01') AND created_date '2020-05-01'
AND status IN ('Closed','Resolved','New')
AND assigned_team IN ('A' , 'B', 'C')
AND assigned_to IN ('ram','govind','ajith');
I built this query dynamically using Predicate and it is working fine.
#Override
public List<Tickets> conditionedQuery(QueryCondition queryCondition) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tickets> query = cb.createQuery(Tickets.class);
Root<Tickets> ticket = query.from(Tickets.class);
List<Predicate> predicatessub = new ArrayList<>();
for(FilterConditions fc:queryCondition.getQueryCondition()) {
if(fc.getFilter().equals("duration")) {
Predicate ps = cb.greaterThanOrEqualTo(ticket.get(queryCondition.getDurationField()), fc.getFilterlist()[0]);
Predicate pe = cb.lessThan(ticket.get(queryCondition.getDurationField()), fc.getFilterlist()[1]);
predicatessub.add(cb.and(ps,pe));
}else
{
List<Predicate> predicates = new ArrayList<>();
for(int i=0; i<fc.getFilterlist().length; i++) {
Predicate p = cb.equal(ticket.get(fc.getFilter()),fc.getFilterlist()[i]);
predicates.add(p);
}
predicatessub.add(cb.or(predicates.toArray(new Predicate[predicates.size()])));
}
}
query.select(ticket)
.where(cb.and(predicatessub.toArray(new Predicate[predicatessub.size()])));
return entityManager.createQuery(query)
.getResultList();
}
QueryCondition.class
public class QueryCondition {
private List<FilterConditions> filterCondition;
private String durationField;
}
FilterConditions.class
public class FilterConditions {
private String filter;
private String[] filterlist;
}
Now I would like to build a quite more complex query involving joins and group by. Below is the sample query like what I would like to build using predicate.
SELECT
YEAR(pt.created_date),
MONTH(pt.created_date),
pt.assigned_team,
COUNT(tk.ticket_id)
FROM
(SELECT
*
FROM
tickets
WHERE
ticket_id IN (SELECT
ticket_id
FROM
Tickets
WHERE
resolved_date >= '2020-02-01')
AND resolved_date < '2020-05-01'
and assigned_team IN ('A' , 'B', 'C')) pt
LEFT JOIN
(SELECT
*
FROM
tickets
WHERE
status IN ('Closed','Resolved','New')
AND assigned_to IN ('ram','govind','ajith')) tk ON tk.ticket_id = pt.ticket_id
GROUP BY YEAR(pt.created_date) , MONTH(pt.created_date), pt.assigned_team order by
pt.assigned_team,YEAR(pt.created_date),MONTH(pt.created_date) asc;
Kindly advise how this can be achieved with Predicate or is there any other simpler way than Predicate.
Maybe this works:
First create a list with all field your model but removing associations. After pass this list in CriteriaQuery.
List<Expression<?>> groupByList = new ArrayList<>();
// ticket => Root<Tickets>
ticket.getModel().getAttibutes().stream()
.filter(a -> !a.isAssociation())
.forEach(a -> groupByList.add(ticket.get(a.getName())));
query.select(ticket)
.where(cb.and(predicatessub.toArray(new Predicate[predicatessub.size()])))
.groupBy(groupByList); // <== add group by
If you have join just do the same thing creating a cast with object EntityTypeImpl<?>. ex:
// import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl
// join => Join<?,?>
((EntityTypeImpl<MyEntity>) join.getModel())
.getDeclaredAttributes().stream()
.filter(a -> !a.isAssociation())
.forEach(a -> groupByList.add(join.get(a.getName())));

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

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.