Convert SQL query to Sequilize - sql

This is my SQL query, I want to convert this query to sequelize query:
SELECT
`users`.`uId`, `users`.*,
COUNT(`tasks`.`userUId`) AS 'tasksCount'
FROM
`users` AS `users`
LEFT OUTER JOIN
`tasks` AS `tasks` ON `users`.`uId` = `tasks`.`userUId`
GROUP BY
`users`.`uId`;

You can use Sequelize.fn in the attrubutes option and indicate users.id in group option:
const users = await Users.findAll({
attributes: {
include:[[Sequelize.fn('SUM', Sequelize.col('tasks.userId')), 'tasksCount']]
},
include: [{
model: Tasks,
attributes: ['userId']
}],
group: [Sequelize.col('tasks.userId')]
})

Related

Sequelize - Subselect association to filter parent model

I've recently started to use Sequelize 6. Currently trying to express the following query unsuccessfully.
SELECT u.*
FROM users u
JOIN requests r
ON u.id = r.user_id
WHERE (r.status = true AND r.created_at IN (SELECT
MAX(r.created_at)
FROM users u
INNER JOIN requests r ON r.user_id = u.id
GROUP BY u.id))
GROUP BY u.id, r.id
What I have tried so far:
const result = await User.findAll({
offset: page,
subQuery: false,
limit: rowsPerPage,
where: {
'$requests.status$': true,
},
include: [{
as: 'requests',
model: Request,
separate: true,
required: true,
order: [['createdAt', 'desc']],
limit: 1, // problem is here -> error: missing FROM-clause entry for table "requests"
}],
});
In other words, I'm trying to load the parent model only when the association's status value is true on the last record, and return each individual user row alongside with its latest association.
Regarding the limit problem on my comment, this thread might be useful
https://github.com/sequelize/sequelize/issues/11617
I had to change original SQL a little bit to work with Sequelize because a certain combination of required, where didn't work well.
So, I went off from your description.
I'm trying to load the parent model only when the association's status
value is true on the last record
If I understand this correctly, I think you can use having query to achieve this.
const result = await User.findAll({
offset: page,
subQuery: false,
limit: rowsPerPage,
include: [{
as: 'requests',
model: Request,
required: true
}],
having: {
'$requests.createdAt$': [sequelize.fn('MAX', sequelize.col('`requests`.`createdAt`'))],
'$requests.status$': true
},
group: ['users.id'],
});
This will produce a following SQL. Please try this SQL and let me know if this is what you are looking for or not.
SELECT ... FROM `users` AS `users`
INNER JOIN `requests` AS `requests`
ON `users`.`id` = `requests`.`userId`
GROUP BY `users`.`id`
HAVING `requests`.`createdAt` IN (MAX(`requests`.`createdAt`)) AND `requests`.`status` = 1
LIMIT 0, 5;

Sequelize a raw query, with COUNT, SUM, INNER JOIN, WHERE etc

I'm trying to change this raw query in sequelize.
I have trying many things but nothing works like expected.
For the moment i'm here :
ItemModel.findAndCountAll({
attributes: ['count', [sequelize.fn('sum', sequelize.col('rating')), 'sum']],
include: [{
model: models.ReviewModel,
required: true,
where: [``]
}],
where : [{`items.connector->'SOLD'->>'name' = '${itemName}'`}],
})
And the raw query that i'm tring to transform is :
`SELECT COUNT(*) AS count, SUM(reviews.rating) AS sum
FROM items
INNER JOIN reviews ON reviews.id = items.review_id
WHERE items.connector->'SOLD'->>'name' = '${itemName}'`,
);
I'm really a beginner in sql req and sequelize ... Sorry if it's look ugly...
Sequelize is not intended to construct such aggregations. It's more about CRUD.
It's better to use plain SQL query like this:
const results = await Sequelize.query(`SELECT COUNT(*) AS count, SUM(reviews.rating) AS sum
FROM items
INNER JOIN reviews ON reviews.id = items.review_id
WHERE items.connector->'SOLD'->>'name' = $itemName`, {
type: Sequelize.QueryTypes.SELECT,
bind: {
itemName
},
}

Sequelize nested include with required: true generates invalid join

I apologise for the lengthy post in advance!
I am trying to use sequelize in nodeJs to query a Wordpress mysql database with a required: true in a nested include.
However, the generated query includes a bad join (I'd expect the join to be nested like the nested where clause). I don't seem to be able to figure out if I've configured my schema incorrectly or whether I am just doing something else silly.
Any help would be greatly appreciated!
In essence, my schema is:
const Post = sequelize.define('wp_posts', {
ID: {
type: DataType.BIGINT,
primaryKey: true
}
});
const TermRelationship = sequelize.define('wp_term_relationships', {
object_id: {
type: DataType.BIGINT,
primaryKey: true,
allowNull: false
},
term_taxonomy_id: {
type: DataType.BIGINT,
primaryKey: true,
allowNull: false
}
});
const TermTaxonomy = sequelize.define('wp_term_taxonomy', {
term_taxonomy_id: {
type: DataType.BIGINT,
primaryKey: true
}
});
const Term = sequelize.define('wp_terms', {
term_id: {
type: DataType.BIGINT,
primaryKey: true
}
});
The relationships I have defined are:
Post.belongsToMany(TermTaxonomy, {
through: TermRelationship,
otherKey: 'term_taxonomy_id',
foreignKey: 'object_id',
as: 'termTaxonomies'
});
TermTaxonomy.belongsTo(Term, {
foreignKey: 'term_id',
as: 'term'
});
The query I am executing is
const query = {
limit: 1,
include: [
{
model: TermTaxonomy,
required: true,
as: 'termTaxonomies',
include: [
{
model: Term,
as: 'term',
required: true,
}
]
}
]
};
However, the generated query includes a bad join. Here is the generated query. I have included comments where I see the errors:
SELECT
`wp_posts`.*,
`termTaxonomies`.`term_taxonomy_id` AS `termTaxonomies.term_taxonomy_id`,
`termTaxonomies`.`term_id` AS `termTaxonomies.term_id`,
`termTaxonomies`.`taxonomy` AS `termTaxonomies.taxonomy`,
`termTaxonomies`.`description` AS `termTaxonomies.description`,
`termTaxonomies`.`parent` AS `termTaxonomies.parent`,
`termTaxonomies`.`count` AS `termTaxonomies.count`,
`termTaxonomies->wp_term_relationships`.`object_id` AS `termTaxonomies.wp_term_relationships.object_id`,
`termTaxonomies->wp_term_relationships`.`term_taxonomy_id` AS `termTaxonomies.wp_term_relationships.term_taxonomy_id`,
`termTaxonomies->wp_term_relationships`.`term_order` AS `termTaxonomies.wp_term_relationships.term_order`
FROM
(
SELECT
`wp_posts`.`ID`,
`wp_posts`.`post_author`,
`wp_posts`.`post_date_gmt`,
`wp_posts`.`post_content`,
`wp_posts`.`post_title`,
`wp_posts`.`post_excerpt`,
`wp_posts`.`post_status`,
`wp_posts`.`comment_status`,
`wp_posts`.`ping_status`,
`wp_posts`.`post_password`,
`wp_posts`.`post_name`,
`wp_posts`.`to_ping`,
`wp_posts`.`pinged`,
`wp_posts`.`post_modified_gmt`,
`wp_posts`.`post_content_filtered`,
`wp_posts`.`post_parent`,
`wp_posts`.`guid`,
`wp_posts`.`menu_order`,
`wp_posts`.`post_type`,
`wp_posts`.`post_mime_type`,
`wp_posts`.`comment_count`,
-- ERROR
-- wp_terms cannot be joined to wp_posts
`termTaxonomies->term`.`term_id` AS `termTaxonomies.term.term_id`,
`termTaxonomies->term`.`name` AS `termTaxonomies.term.name`,
`termTaxonomies->term`.`slug` AS `termTaxonomies.term.slug`,
`termTaxonomies->term`.`term_group` AS `termTaxonomies.term.term_group`
FROM
`wp_posts` AS `wp_posts`
-- ERROR: bad join!
-- wp_terms cannot be joined to wp_posts
INNER JOIN `wp_terms` AS `termTaxonomies->term` ON `termTaxonomies`.`term_id` = `termTaxonomies->term`.`term_id`
WHERE
(
SELECT
`wp_term_relationships`.`object_id`
FROM
`wp_term_relationships` AS `wp_term_relationships`
INNER JOIN `wp_term_taxonomy` AS `wp_term_taxonomy` ON `wp_term_relationships`.`term_taxonomy_id` = `wp_term_taxonomy`.`term_taxonomy_id`
INNER JOIN `wp_terms` AS `wp_term_taxonomy->term` ON `wp_term_taxonomy`.`term_id` = `wp_term_taxonomy->term`.`term_id`
WHERE
(
`wp_posts`.`ID` = `wp_term_relationships`.`object_id`
)
LIMIT
1
) IS NOT NULL
LIMIT
1
) AS `wp_posts`
INNER JOIN (
`wp_term_relationships` AS `termTaxonomies->wp_term_relationships`
INNER JOIN `wp_term_taxonomy` AS `termTaxonomies` ON `termTaxonomies`.`term_taxonomy_id` = `termTaxonomies->wp_term_relationships`.`term_taxonomy_id`
) ON `wp_posts`.`ID` = `termTaxonomies->wp_term_relationships`.`object_id`;
The error I get is 'Unknown column 'termTaxonomies.term_id' in 'on clause' due to the incorrect join.
The generated query is valid if I either remove required: true or the limit option since it no longer does the strange inner join. However, I just can't seem to get this to work with a required nested include.
FYI: I am using sequelize 4.37.10 with 1.5.3 mysql2 1.5.3.
Thank you very much!
When eager loading, we can force the query to return only those records which have an associated model, effectively converting the query from the default OUTER JOIN to an INNER JOIN. Just remove required:true it will work fine generally this happens when we eager load, probably in your case we are eagerloading.
I hope you find this explanation beneficial.

How can inner join like this can be converted Sequelize?

I'm primarily trying to see how would you perform inner join here.
SELECT * From "Users" as biz
INNER JOIN "Deals" as d
ON biz.id = d."UserId"
WHERE (biz.latitude BETWEEN 18 AND 21)
AND (biz.longitude BETWEEN -78 AND -73);
this is what I got from documentation... but not sure how to proceed further
Deals.find({ where: { }, include: [User]})
For inner join all you need is required : true :
Deals.find({
where: { },
include: [{
model : User ,
required : true // This will make your inner join
}]})
NOTE : Use findAll or findOne instead of just find

Is this SQL possible in Sequelize?

I've just started with sequelize and am trying to reproduce the below query.
I have the following Model structure: Review, Entity, ReviewThank
Each Entity can have many Reviews, and each Review can have many ReviewThanks.
An attribute of each review is a 'thumbUp' (boolean) rating.
I'm trying to generate the below query to get a 'thankCount' for each review, along with the Entity rating - thumbUpCount and totalCount - for each Review:
SELECT * FROM (
SELECT COUNT("Review"."id") AS "totalCount", "Review"."EntityId", COUNT(CASE WHEN "Review"."thumbUp" THEN 1 END) AS "thumbUpCount"
FROM "Reviews" AS "Review" GROUP BY "Review"."EntityId"
) AS "EntityRatingTable" LEFT JOIN (
SELECT "Review"."id", "Review"."EntityId", "Review"."uid", "Review"."thumbUp", "Review"."caption", COUNT("ReviewThanks"."id") AS "thankCount"
FROM "Reviews" AS "Review" LEFT OUTER JOIN "ReviewThanks" AS "ReviewThanks" ON "Review"."id" = "ReviewThanks"."ReviewId"
WHERE "Review"."UserId" IN (1) GROUP BY "Review"."id"
) AS "ReviewsTable" ON "ReviewsTable"."EntityId" = "EntityRatingTable"."EntityId";
Is it possible to produce this in sequelize? I've got the "ReviewsTable" query working ok, but unsure how (or if possible) I can join this with the "EntityRatingTable"?
This is what I've got so far:
models.Review.findAll({
attributes: {
include: [
[models.sequelize.fn('COUNT', models.sequelize.col('ReviewThanks.id')), 'thankCount'],
[models.sequelize.fn('COUNT', models.sequelize.col('Review.id')), 'reviewCount'],
],
exclude: ["EntityId", "UserId"],
},
include: [
{
model: models.ReviewThank,
attributes: [],
}, {
model: models.Entity,
}
],
group: ['"Review"."id"', '"Entity.id"'],
})