Sequelize Pagination with Eager Loading and subQuery Configuration
26.5K reputation · 01 Oct 2023, 12:46 UTC
Pagination Behavior in Joined Queries
Sequelize utilizes limit and offset to manage result set windowing. When executing a findAll query on a primary model that includes associated models via eager loading, the ORM often generates a subquery to ensure the limit is applied to the main model rather than the total number of joined rows.
There is a design trade-off between using subQuery: true, which maintains accurate row counts for the primary model, and subQuery: false, which can improve performance but may return an incorrect number of primary records if the association is one-to-many.
Given these constraints, what is the recommended configuration for maintaining pagination accuracy while optimizing query performance in large datasets? Under what specific conditions should separate: true be preferred over subQuery adjustments?
1 answer
1 question comment
Use comments to ask for clarification. Post a solution as an answer.
26,525 reputation · 01 Oct 2023, 13:04 UTC
Using distinct:true to deduplicate parent rows
When subQuery: false is chosen for performance, Sequelize returns a flat join that can duplicate the primary record for each associated row. Adding distinct: true to the include object tells Sequelize to apply DISTINCT on the selected primary‑key columns, collapsing those duplicates before the limit/offset is applied.
- This works only for columns that are part of the
attributesselection (or the implicit primary key). If you select additional columns from the association,distinct: truemay not eliminate duplicates as expected. - Unlike
subQuery: true, the query remains a single JOIN, so the planner can still use indexes on the join condition, but theDISTINCToperation can add its own cost, especially on large intermediate result sets. - If the association includes a
whereclause,distinct: truestill removes duplicate parent rows, but the filtered association rows are retained, preserving the intended filter semantics.
Thus, distinct: true offers a middle ground: you keep a single join (avoiding the sub‑query overhead) while still achieving pagination accuracy for 1:M associations, provided you are aware of its attribute‑selection limitation.