Skip to content
Open
53 changes: 53 additions & 0 deletions docs/associations/belongs-to-many.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,59 @@ class Toot extends Model<InferAttributes<Toot>, InferCreationAttributes<Toot>> {
In TypeScript, you need to declare the typing of your foreign keys, but they will still be configured by Sequelize automatically.
You can still, of course, use any [attribute decorator](../models/defining-models.mdx) to customize them.

### Associations with extra attributes on through table

When creating an N:M association, for example, with User and Project through UserProject you might want extra attributes on the junction table like the "role" attribute.
This relationship can be set up like this:

```ts
class UserProject extends Model<InferAttributes<UserProject>, InferCreationAttributes<UserProject>> {
@Attribute(DataTypes.STRING)
declare role: string;

declare projectId: number;
declare userId: number;
}

class Project extends Model<InferAttributes<Project>, InferCreationAttributes<Project>> {
@Attribute(DataTypes.STRING)
declare name: string;

declare UserProject?: NonAttribute<UserProject>;
}

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
@Attribute(DataTypes.STRING)
declare username: string;

@BelongsToMany(() => Project, {
through: () => UserProject,
})
declare projects?: NonAttribute<Project[]>;

declare getProjects: BelongsToManyGetAssociationsMixin<Project>;
declare setProjects: BelongsToManySetAssociationsMixin<Project, number>;
declare addProjects: BelongsToManyAddAssociationsMixin<Project, number>;
}
```

Creating multiple associations with the same extra attributes is possible by passing a single object on the through attribute:
```ts
user1.setProjects([project1, project2, project3], { through: { role: 'admin' }})
```

With the [set](#association-setter-setx) and [add](#association-adder-addx) mixins, different extra attributes per association can be set by passing an array of objects of the same length as the number of associations:
```ts
user1.setProjects([project1, project2, project3], {
through: [
{ role: 'admin' },
{ role: 'manager' },
{ role: 'designer' },
]
})
(await user1.getProjects()).map(x => x.UserProject?.role) // [ 'admin', 'manager', 'designer' ]
```

## Inverse Association

The `BelongsToMany` association automatically creates the inverse association on the target model, which is also a `BelongsToMany` association.
Expand Down
Loading