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: trueparameter 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
idit 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:
CartItemhas anidas PKCartIdandProductIdare not PKsbelongsToManyand{ through: { model: CartItem, unique: false } }as optionsBoth rows on the
CartItemare referencing the sameCartandProduct, so they’re equal on its references but not necessarely identical (they have aqtycolumn 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 ifat this line in the query.options.hasJoinis set to true if theincludeoptions is set, see Models. Which means thatAbstractQuery._groupJoinDatais never run and it is responsible for grouping the associations by callee.handleSelectQuerymethod we have this condition:Assuming
options.plainis set onModel.findAll(hard to deduce) which returns first row only result, since it is aSELECTquery handled by thequerySelectHandler.Example of results input(see below) for the
handleSelectQuerymethod withraw: trueandplain: trueset. Returns exactly the same output as its input format after executing the logic inside the conditionaloptions.rawstatement. Ifplain: trueis set then only the first item in the array is returned with only a single associating, sincegroupJoinDatawas never run. Which is the result I’m seeing.I’ve seen people complain about association count giving false result for the
has-manyandbelongs-to-manyrelations 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: truefor them, added.removeAttribute('id'), and all includes now works just fineStill no fix?!
Removing
raw:truefrom 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: trueand including (include: 'association') any “to many” association (hasManyorbelongToMany) 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
branchIdinformation is lost, isn’t it?