I have the following DB structure in Kysely:
export type User = {
id: string;
name: string;
};
export type UserToTeam = {
userId: string;
teamId: string;
};
export type Team = {
id: string;
name: string;
};
and I'm trying to create a query that returns users with their teams in a nested structure:
const result = await db
.selectFrom("User")
.select(["id", "name"])
.select((eb) => [withTeams(eb)])
.execute();
function withTeams(eb: ExpressionBuilder<DB, "User">) {
return jsonArrayFrom(
eb
.selectFrom("UserToTeam")
.select((eb) => [
jsonArrayFrom(
eb
.selectFrom("Team")
.select(["id", "name"])
.whereRef("Team.id", "=", "UserToTeam.teamId"),
).as("teams"),
])
.whereRef("UserToTeam.userId", "=", "User.id"),
).as("teams");
}
This works, but there is a redundant teams
object in the result:
[
{
"id": "1fd0a910-8871-41b2-9a42-303e82a47713",
"name": "Jane Doe",
"teams": []
},
{
"id": "c7d86c73-091f-44c1-b89a-6f6cb6ba9ed0",
"name": "John Doe",
"teams": [
{
"teams": [
{
"id": "07dc9a2c-52c1-4d1d-8c07-ba21dc98f733",
"name": "Team 1"
}
]
}
]
}
]
Is there a way to flatten this into a single teams
object with an array of my selected Team
s?
In this case, it looks like you want to select the Team
data associated to each User
, and not the association itself, which you only need so you're able to know how to join a user to it's teams.
So, with that in mind, you could adjust withTeams
like so:
function withTeams(eb: ExpressionBuilder<DB, "User">) {
return jsonArrayFrom(
eb
.selectFrom("Team")
.innerJoin("UserToTeam", "UserToTeam.teamId", "Team.id")
.select(["Team.id", "Team.name"])
.whereRef("UserToTeam.userId", "=", "User.id")
).as("teams");
}