sequelize: include on hasMany association only returning one of many results when no primary key
I looked around for this issue and couldn’t find it mentioned exactly as I’m seeing it, so apologies in advance if this is a duplicate. The issue is that when I use include like so:
Project.findAll({ include: [{ model: Task }], where: { ... } })
the query is generated correctly and the correct projects are returned, but each contains an array of Tasks that is always of length one (when the Tasks have no primary key), even though many tasks match. I can confirm this using the raw query and verifying the results. If I add a primary key to Task, it then works correctly.
Here are the related definitions, in case there are some clues there.
sequelize.define('Project', {
...
}, {
timestamps: true,
underscored: true,
createdAt: 'created_at',
updatedAt: 'last_modified',
tableName: 'projects',
classMethods: {
associate: function(models) {
Project.hasMany(models.Task, { foreignKey: 'projectId', onDelete: 'CASCADE' });
}
},
sequelize.define('Task', {
...
}, {
timestamps: true,
underscored: true,
createdAt: 'created_at',
updatedAt: false,
tableName: 'tasks'
});
About this issue
- Original URL
- State: open
- Created 8 years ago
- Reactions: 20
- Comments: 73 (6 by maintainers)
Commits related to this issue
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
- fix(abstract/handleSelectQuery): Disable checkExisting to allow _duplicated_ rows (#5193) — committed to json-schema-faker/sequelize by pateketrueke 6 years ago
Any update on this?
😉
@holmberd I think if you remove the
raw: true
parameter the response will contain all the objects.@rttomlinson If you are still facing this issue the workaround is to add primary key field to the table and include that field in your query or make composite unique key and include them in your select query. for ex:
This is how I got things work.
I’m having the same issue.
Code
Result
Without
id
it only returns the first row.Commenting the
Task.removeAttribute('id')
everything works properly.SQL
The SELECT queries generated (with and without
id
):Identical with the exception of the extra column
id
.Final
I also found that the method
User.getTasks()
works as intended without an Primary Key.Hard to believe… I just added
{ plain: false, raw: true }
and then I got this:This is the SQL generated:
And this is the result if I run the query manually:
Now, if I set only
{ plain: false }
the result of callingfindOne()
will be an array… and without those options it just returns the following:IMHO this is a critical issue because otherwise we can’t be completely confident on this feature, or we’re missing something else?
@mickhansen:
That would be the problem in my case because:
CartItem
has anid
as PKCartId
andProductId
are not PKsbelongsToMany
and{ through: { model: CartItem, unique: false } }
as optionsBoth rows on the
CartItem
are referencing the sameCart
andProduct
, so they’re equal on its references but not necessarely identical (they have aqty
column with a different value).There’s a way to disable that deduplication/uniqueness check?
Thank you!
The best workaround is to not use sequelize
It’s 2019 guys any updates???
Looking into the libraries it seems to stem from the conditional statement
else if
at this line in the query.options.hasJoin
is set to true if theinclude
options is set, see Models. Which means thatAbstractQuery._groupJoinData
is never run and it is responsible for grouping the associations by callee.handleSelectQuery
method we have this condition:Assuming
options.plain
is set onModel.findAll
(hard to deduce) which returns first row only result, since it is aSELECT
query handled by thequerySelectHandler
.Example of results input(see below) for the
handleSelectQuery
method withraw: true
andplain: true
set. Returns exactly the same output as its input format after executing the logic inside the conditionaloptions.raw
statement. Ifplain: true
is set then only the first item in the array is returned with only a single associating, sincegroupJoinData
was never run. Which is the result I’m seeing.I’ve seen people complain about association count giving false result for the
has-many
andbelongs-to-many
relations and I would guess that this might be related too. This is just a quick overview and it would be nice to hear from someone who actually knows the code base if this might be what is affecting the results, and what sort of flow the result is meant to have.I also fix this problem by removing { raw: true} from my Model.findAll function
…So does this mean the “hasMany” functionality doesn’t actually do what it’s supposed to?
any updates ?
any updates?
I just had the same problem. I ended up having to create an useless id column.
by just removing the raw: true - solved my problem
Seems like this one to many mapping has been bugging off a lot of people 😦
Sorry for the notification, Ignore my misclick 🤦♀️
I solved this problem by first fetching as a raw sequelize object, then calling .toJSON() on it.
Example:
const post = await db.Post.findByPk(postId, { include: [ { model: db.Comment, as: "comments" } ], raw: false, plain: true, nest: true }); console.log(await post.toJSON());
The relationship between Post and Comment is shown below:
Post.hasMany(models.Comment, { foreignKey: "post_id", as: "comments" })
I had the same error, added composite pk to multiple columns of model without
id
, also addedprimaryKey: true
for them, added.removeAttribute('id')
, and all includes now works just fineStill no fix?!
Removing
raw:true
from outer level worked for meWhen we process associations we attempt to dedupe each row by either matching primary keys or row uniqueness.
Any chance the task rows are completely equal? Seems like it’s doing row uniqueness check although it shouldn’t necessarily have to do a full check, nto sure.
I still having this issue, tested on latest v6 and v7 ( SQLITE ) .
And problem seems to be bigger, because it happens even you add an id.
Every “find” function using
raw: true
and including (include: 'association'
) any “to many” association (hasMany
orbelongToMany
) give these wrong result.There are a lot of issues related, and since this seems to be the main thread of the issue, it could be renamed to match better the problem. ( ‘raw’ is the main keyword, ‘primary key’ seems not relevant since it happens any ways using it )
Generated SQL statments are the same using raw or not, so is some parsing issue. Have some one some aproach ( with raw: true ) to get the correct data ?? Or some clue to find a fix ?? Or where to look on Sequelize for a fix ??
Not sure if 100% related to this - but we had an issue with a many to many relationship where the solution of using a primary key was found by a coworker in this documentation link https://sequelize.org/master/manual/advanced-many-to-many.html
We defined the ID in the Model as said and it all worked - so maybe it is not exactly an issue, more of a misunderstanding when using sequelize, or how sequelize does things. Just adding it because nobody pointed in the direction of that link and might be helpful.
one-many association query caused a problem that duplicate rows appears from left table, how to fix or config that?
Had the same problem. The actual response (observed when using
{ plain: false, raw: true}
) included all data, so I knew it wasn’t a problem with my query.I had a
A.hasMany(B)
relationship where the B table had a foreign key that referenced the primary key of A. The primary key of A was an unsigned integer. Changing this to a signed int solved my problem.@jpierrep @EdByrnee @BartusZak @jembach @masonjwhite @AmbroiseVuaridel @Relequestual @marcelorl - Can some of you please try the PR created by pateketrueke (#9384) and see if it fixes the problem for you?
You can try it by using
npm install https://github.com/json-schema-faker/sequelize/tarball/bugfix/merge_nested_associations
.Could you help me and try #9384 on your codebase to see if it solves your issue?
So much thanks in advance @masonjwhite 🍻
Is there a way to prevent this behavior? Lets say we have branches and employees. An employee can be associated to multiple branches and have multiple supervisors (other employees) in each branch.
Employee model definition:
Branch model definition:
Join table:
If I want every supervisor for a particular employee, I’d do something like:
However, if an employee has the same supervisor in multiple branches I’d only get the supervisor once, which could be fine in some cases. But the
branchId
information is lost, isn’t it?