question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

FindAll and FindAllAndCount with Includes and Limits - [fix proposal for incorrect behavior]

See original GitHub issue

Right now, when you execute a findAll or a findAllAndCount call with includes and add a limit to your options, sequelize will produce something along the lines of

SELECT ... cols ... 
FROM (SELECT ... cols ... FROM `table` AS `table` LIMIT 0, 10) AS `table`
LEFT OUTER JOIN `table2` AS `table2` ON `table`.`col` = `table2`.`col` 
ORDER BY `table2`.`col` DESC;

which is wrong in every single pagination scenario where some sort of filtering and/or sorting needs to be done on the association (i.e. table2). This is not some obscure edge case but a trivial pagination + sorting case. The correct query for any pagination scenario would be

SELECT ... cols ... 
FROM (SELECT ... cols ... FROM `table` AS `table`) AS `table`
LEFT OUTER JOIN `table2` AS `table2` ON `table`.`col` = `table2`.`col` 
ORDER BY `table2`.`col` DESC  LIMIT 0, 10;

I came across this 2 years old thread which seems to have been closed without a solution so I took a quick look at the sequelize source code and while I can’t (and don’t want to) propose an in-depth solution to the query generation logic, I think you can give us a way to work around this problem without major code changes and without forcing us to rely on ugly pure SQL query fixes.

If you take a look at https://github.com/sequelize/sequelize/blob/master/lib/dialects/abstract/query-generator.js#L1329

const limitOrder = this.addLimitAndOffset(options, mainTable.model);
if (limitOrder && !options.groupedLimit) {
	if (subQuery) {
	subQueryItems.push(limitOrder);
	} else {
	mainQueryItems.push(limitOrder);
	}
}

if the findAll or findAllAndCount query has any includes, the subQuery variable will be true and the limit will be added to subQueryItems and thus applied to the subquery.

A very simple workaround would be to just change that if-statement to

if (subQuery && !options.isGlobalLimit) {
	subQueryItems.push(limitOrder);
} else {
	mainQueryItems.push(limitOrder);
}

so that we can simply change our findAll call from

modelA.findAll({ where: {...}, include: [...], order: [ ... ], limit: 10 })

to

modelA.findAll({ where: {...}, include: [...], order: [ ... ], limit: 10, isGlobalLimit: true })

and we would get the correct pagination query with the limit being applied to the main query instead of the subquery.

It’s not a solution to the logical problem but at least it gives us a way to implement correct sorting/filtering behavior using sequelize without any in-depth changes and without introducing any bugs.

Do you think this change could make it into the next release?

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:3
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
radoslavpetranovcommented, Jun 25, 2019

@krazi3 you don’t remove the limit - you move it to the upper level query. That’s exactly what you want to do when you want to do a join correctly and then limit the results of that join.

0reactions
github-actions[bot]commented, Nov 13, 2021

This issue has been automatically marked as stale because it has been open for 14 days without activity. It will be closed if no further activity occurs within the next 14 days. If this is still an issue, just leave a comment or remove the “stale” label. 🙂

Read more comments on GitHub >

github_iconTop Results From Across the Web

Sequelizejs: findAll and count associations at the same time
It is very much possible with findAndCountAll method provided by the sequelize. Once you make a query by Post.findAndCountAll({include: ...
Read more >
sequelize execute a query which would set an environment or ...
This proposal would not fix the PWD variable for commands that explicitly set ... if the findAll or findAllAndCount query has any includes...
Read more >
Model Querying - Basics - Sequelize
Simple SELECT queries​. You can read the whole table from the database with the findAll method: // Find all users
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found