-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Description
Issue description
Combining a join table with skip and take only returns a single entity of the join table if the primary key is not selected.
Expected Behavior
Assuming this setup of entites:
Organization {
id, name
}
Workspace {
id, name
}
OrganizationWorkspaceAssignment {
organizationId, workspaceId, meta
}
and this QueryBuilder:
const qb = this.repo.createQueryBuilder("organization")
.leftJoin("organization.workspaceAssignments", "workspaceAssignments")
.leftJoin("workspaceAssignments.workspace", "workspace")
.addSelects([
"organization.id", "organization.name",
"workspaceAssignments.meta",
"workspace.id", "workspace.name"
])
.skip(0)
.take(20)
const result = qb.getMany();
I expected this result:
[
{
id: "o1",
name: "Organization 1",
workspaceAssignments: [
{ meta, workspace: { id: "w1", name: "Workspace 1 } },
{ meta, workspace: { id: "w2", name: "Workspace 2 } },
{ meta, workspace: { id: "w3", name: "Workspace 3 } }
]
},
...
]
Actual Behavior
Instead of correctly pulling multiple OrganizationWorkspaceAssignment entities, the output only contained one:
[
{
id: "o1",
name: "Organization 1",
workspaceAssignments: [
{ meta, workspace: { id: "w1", name: "Workspace 1 } }
]
},
...
]
Steps to reproduce
- Setup entities and join table:
@Entity("entity1")
class Entity1 {
@PrimaryColumn({
type: "uuid",
})
id!: string;
@Column({
type: "varchar",
nullable: false,
})
name!: string;
@OneToMany(
() => JoinTable,
(jt) => jt.entity1,
{
eager: false,
},
)
assignments?: JoinTable[];
}
@Entity("entity2")
class Entity2 {
@PrimaryColumn({
type: "uuid",
})
id!: string;
@Column({
type: "varchar",
nullable: false,
})
name!: string;
@OneToMany(
() => JoinTable,
(jt) => jt.entity2,
{
eager: false,
},
)
assignments?: JoinTable[];
}
@Entity("join_table")
class JoinTable {
@PrimaryColumn({
type: "uuid",
})
entity1Id!: string;
@PrimaryColumn({
type: "uuid",
})
entity2Id!: string;
@Column({
type: "jsonb",
nullable: true,
})
meta!: AssignmentAttributes | null;
@ManyToOne(() => Entity1, {
onDelete: "CASCADE",
eager: false,
})
@JoinColumn({
name: "entity1Id",
referencedColumnName: "id",
})
readonly entity1?: Entity1;
@ManyToOne(() => Entity2, {
onDelete: "CASCADE",
eager: false,
})
@JoinColumn({
name: "entity2Id",
referencedColumnName: "id",
})
readonly entity2?: Entity2;
}
Add data, so that there's one Entity1 row and multiple Entity2 rows, all assigned via JoinTable to entity1.
Create a QueryBuilder on Entity1 repo, and use .leftJoin, with skip and take without selecting the join_table.entity2Id:
const qb = this.repo.createQueryBuilder("entity1")
.leftJoin("entity1.assignments", "assignments")
.leftJoin("assignments.entity2", "entity2")
.addSelects([
"entity1.id", "entity1.name",
"assignments.meta",
"entity2.id", "entity2.name"
])
.skip(0)
.take(20)
const result = qb.getMany();
Notice that despite there being multiple assignments, result only shows one element in assignments array.
My Environment
| Dependency | Version |
|---|---|
| Operating System | macOs 15.6.1 |
| Node.js version | 22.11.0 |
| Typescript version | 5.5.4 |
| TypeORM version | 0.3.25 |
Additional Context
- if I remove
skipandtakeit does produce the correct result (excluding pagination) - if I manually add
"workspaceAssignments.workspaceId"select, it produces the correct result - if I change
.leftJointo.leftJoinAndSelectit produces the correct result (but pulls extra fields)
Running the query that i got from qb.getQueryAndParams() returns the same number of rows, regardless of presence of the "workspaceAssignments.workspaceId" select, so the base query is not a problem here.
Relevant Database Driver(s)
- aurora-mysql
- aurora-postgres
- better-sqlite3
- cockroachdb
- cordova
- expo
- mongodb
- mysql
- nativescript
- oracle
- postgres
- react-native
- sap
- spanner
- sqlite
- sqlite-abstract
- sqljs
- sqlserver
Are you willing to resolve this issue by submitting a Pull Request?
Yes, I have the time, but I don't know how to start. I would need guidance.