I am using sequelize with sequelize-typescript library, and am trying to achieve the following relationship:
Team.ts
@Scopes({
withPlayers: {
include: [{model: () => User}]
}
})
@Table
export default class Team extends Model<Team> {
@AllowNull(false)
@Column
name: string;
@BelongsToMany(() => User, () => TeamPlayer)
players: User[];
}
User.ts
@Scopes({
withTeams: {
include: [{model: () => Team, include: [ () => User ]}]
}
})
@Table
export default class User extends Model<User> {
@AllowNull(false)
@Column
firstName: string;
@AllowNull(false)
@Column
lastName: string;
@BelongsToMany(() => Team, () => TeamPlayer)
teams: Team[];
}
TeamPlayer.ts
@DefaultScope({
include: [() => Team, () => User],
attributes: ['number']
})
@Table
export default class TeamPlayer extends Model<TeamPlayer> {
@ForeignKey(() => User)
@Column
userId: number;
@ForeignKey(() => Team)
@Column
teamId: number;
@Unique
@Column
number: number;
}
Now when querying for player, you get the object with the following data:
{
"id": 1,
"name": "Doe's Team",
"players": [
{
"id": 1,
"firstName": "John",
"lastName": "Doe",
"TeamPlayer": {
"userId": 1,
"teamId": 1,
"number": 32
}
}]
}
Now there are couple of things that I cannot get done..
1) I want to rename the TeamPlayer
to something like "membership"; but not by changing the name of the class
2) the content of TeamPlayer
should not have the id`s, but I want it to contain the data of the team, for example:
{
"firstName": "John",
"lastName": "Doe"
"membership": {
"number": 32
}
In the above classes, I tried to set a scope to the TeamPlayer
class to only include number
inside the TeamMember
inclusion, but no effect.
I used to have the TeamPlayer
class have direct memberships to team
and player
, but that solution added redundant id
to the TeamPlayer
class, and also did not prevent duplicate memberships in the team. I could indeed manually (= in code) prevent duplicates in these situations, but that does not feel elegant.
I ended up solving this by adding one-to-many relationships from TeamPlayer
to User
and Team
, and also figured out the way to make the teamId
+ userId
pair unique by adding two more fields with @ForeignKey
like this:
TeamPlayer.ts
@Table
export default class TeamPlayer extends Model<TeamPlayer> {
@BelongsTo(() => Team)
team: Team;
@ForeignKey(() => Team)
@PrimaryKey
@Column
teamId: number;
@BelongsTo(() => User)
user: User;
@ForeignKey(() => User)
@PrimaryKey
@Column
userId: number;
@Column
number: number;
}
User.ts
@Table
export default class User extends Model<User> {
@AllowNull(false)
@Column
firstName: string;
@AllowNull(false)
@Column
lastName: string;
@HasMany(() => TeamPlayer)
teams: TeamPlayer[];
}
Team.ts
export default class Team extends Model<Team> {
@AllowNull(false)
@Column
name: string;
@HasMany(() => TeamPlayer)
players: TeamPlayer[];
}
This solution allows me to control the included query attributes via scopes, and gives me proper object output.