sequelize: Columns of join table are always selected, which breaks aggregation in PostgresSQL
Dialect: PostgresSql Sequelize version: 3.19.3
I have two tables that are n:m associated with a joining table. Whenever I use .findAll
and include the other table, all fields in the joining table would also be selected in the generated SQL queries. The fields in the joining table would cause problems when I try to use the aggregate functions.
include[].through.attributes: []
does not stops the columns from going into the SQL query.
The example below is modified from the one in #3938.
Setup:
// MODELS
var Group = sequelize.define('Group', {
name: sequelize.Sequelize.STRING
});
var Person = sequelize.define('Person', {
name: sequelize.Sequelize.STRING
});
var GroupPerson = sequelize.define('GroupPerson', {
status: sequelize.Sequelize.STRING
});
// RELATIONS
Group.belongsToMany(Person, {through: GroupPerson, as: 'Persons'});
Person.belongsToMany(Group, {through: GroupPerson, as: 'Groups'});
sequelize.sync({force: true}).then(function(){
// EXAMPLE
Person.findAll({
attributes: [[sequelize.fn('ARRAY_AGG', sequelize.col('Groups.id')), 'groupIds']],
include: [{
model: Group,
as: 'Groups',
through:{
attributes: [],
where: {status: 'done'}
},
attributes: []
}],
group: [sequelize.col('Person.id')]
});
})
Expected SQL generated:
SELECT ARRAY_AGG("Groups"."id") AS "groupIds"
FROM "People" AS "Person"
LEFT OUTER JOIN (
"GroupPeople" AS "Groups.GroupPerson"
INNER JOIN
"Groups" AS "Groups" ON "Groups"."id" = "Groups.GroupPerson"."GroupId" AND "Groups.GroupPerson"."status" = 'done'
) ON "Person"."id" = "Groups.GroupPerson"."PersonId"
GROUP BY "Person"."id";
Actual SQL generated:
SELECT "Person"."id", ARRAY_AGG("Groups"."id") AS "groupIds",
"Groups.GroupPerson"."status" AS "Groups.GroupPerson.status", "Groups.GroupPerson"."createdAt" AS "Groups.GroupPerson.createdAt",
"Groups.GroupPerson"."updatedAt" AS "Groups.GroupPerson.updatedAt", "Groups.GroupPerson"."PersonId" AS "Groups.GroupPerson.PersonId",
"Groups.GroupPerson"."GroupId" AS "Groups.GroupPerson.GroupId"
FROM "People" AS "Person"
LEFT OUTER JOIN (
"GroupPeople" AS "Groups.GroupPerson"
INNER JOIN
"Groups" AS "Groups" ON "Groups"."id" = "Groups.GroupPerson"."GroupId" AND "Groups.GroupPerson"."status" = 'done'
) ON "Person"."id" = "Groups.GroupPerson"."PersonId"
GROUP BY "Person"."id";
…which gives the following error:
Unhandled rejection SequelizeDatabaseError: column "Groups.GroupPerson.status" must appear in the GROUP BY clause or be used in an aggregate function
at Query.formatError (/Users/mrorz/workspace/gis-inner/node_modules/sequelize/lib/dialects/postgres/query.js:443:14)
at null.<anonymous> (/Users/mrorz/workspace/gis-inner/node_modules/sequelize/lib/dialects/postgres/query.js:118:19)
at emitOne (events.js:77:13)
at emit (events.js:169:7)
at Query.handleError (/Users/mrorz/workspace/gis-inner/node_modules/pg/lib/query.js:108:8)
at null.<anonymous> (/Users/mrorz/workspace/gis-inner/node_modules/pg/lib/client.js:171:26)
at emitOne (events.js:77:13)
at emit (events.js:169:7)
at Socket.<anonymous> (/Users/mrorz/workspace/gis-inner/node_modules/pg/lib/connection.js:109:12)
at emitOne (events.js:77:13)
at Socket.emit (events.js:169:7)
at readableAddChunk (_stream_readable.js:146:16)
at Socket.Readable.push (_stream_readable.js:110:10)
at TCP.onread (net.js:523:20)
About this issue
- Original URL
- State: open
- Created 8 years ago
- Reactions: 19
- Comments: 43 (8 by maintainers)
Found a Fix!
By changing the query to add
{includeIgnoreAttributes: false}
, I now get the correct result:SQL generated
Result
2017-03-14T00:28:11.000Z
Hope this helps someone else! I found the clue to (the undocumented feature)
includeIgnoreAttributes
in #6711, grepped the source and found it was being set tofalse
in Model.count.EDIT:
includeIgnoreAttributes: false
makesattributes: []
superfluous, but if you do need any attributes from included Models, include them explicitly in theattributes
array.Keep it open.
I can confirm the flag of
includeIgnoreAttributes: false
works.If you have a User table and Team table both linked with a belongsToMany and thus a join table. Doing…
teams = await currentUser.getTeams({raw: true, includeIgnoreAttributes: false});
will return you the flat array of teams that belong to that user.
Easy as pie… however, its not documented!
this problem still stands there in Sequelize V4.2.1 #5590
Having the same problem as @idrisadetunmbi
had to spend some time to get here. +1 for keeping this issue open, v4.42
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this is still an issue, just leave a comment 🙂
Can also confirm this for postgres on a belongsTo relationship, so definitely not just for through attributes
Same problem, got saved by the above workaround of
includeIgnoreAttributes: false
. I too believe this workaround should be documented until the issue is resolved! Between rootattributes
, includeattributes
andthrough
attributes (plus trying outexclude
magic) on top of group/aggregate it was a pain to debug and search a correct workaround.It’s 2021, i use Version
6.5.0
and this is still an issueThis is still an issue for me, however I have found a workaround if you are using a Model definition for your join table.
Using: sequelize@5.21.7
The following is a stripped down example of what I have (using Typescript):
This ends up generating the following SQL:
Which gives me a single row only with ‘Tenancy.id’ and ‘activeUsers’.
I found this previously merged PR which appeared to fix it in the event you use
raw:true
https://github.com/sequelize/sequelize/pull/4029However, at a guess, the test is bad because it didn’t define the joining table to have a primary column in the definition. =/
Thanks @papb, It’s really heartwarming to see this level of responsibility.
Hi @sassanh, I have this concern on my radar, hopefully in the near future I will be reopening all these wrongfully closed issues!
same issue here, sequelize 4
Any solutions so far? the problem is a big pain in Postgres too
ditto for mysql