Sequelize-typescript: Unable to get many to many working

Created on 6 Jun 2018  路  10Comments  路  Source: RobinBuschmann/sequelize-typescript

Been trying to get my Many to Many association to work, but unable to do so. I looked at the example code, but it's not working for me.

// user.model.ts
import { Table, Model, Column, BelongsToMany } from 'sequelize-typescript';
import { Room, UserRoom } from './index';

@Table
class User extends Model<User> {
    @PrimaryKey
    @AutoIncrement
    @Column
    id: number;

    @Column
    spotify_id: number;

    @BelongsToMany(() => Room, () => UserRoom)
    rooms: Room[];
}

export default User;
// room.model.ts
import { Table, Model, Column, BelongsToMany } from 'sequelize-typescript';
import { User, UserRoom } from './index';

@Table
class Room extends Model<Room> {
    @PrimaryKey
    @AutoIncrement
    @Column
    id: number;

    @Column
    name: string;

    @Column
    image: string;

    @BelongsToMany(() => User, () => UserRoom)
    users: User[];
}

export default Room;
// user_room.model.ts
import { Table, Model, Column, ForeignKey, PrimaryKey } from 'sequelize-typescript';
import { Room, User } from './index';

@Table
class UserRoom extends Model<UserRoom> {
    @ForeignKey(() => User)
    @PrimaryKey
    @Column
    user_id: number;

    @ForeignKey(() => Room)
    @PrimaryKey
    @Column
    room_id: number;
}

export default UserRoom;

This results in the following error:

[...]/node_modules/sequelize-typescript/lib/models/association/BaseAssociation.js:55
throw new Error("Foreign key for \"" + relatedClass.name + "\" is missing " +
      ^
Error: Foreign key for "Room" is missing on "User_Room".

Is there something I'm missing? It's basically a 1-1 copy of the example code.

Most helpful comment

Hi @RobinBuschmann, I have a same issue:

My code:

//role.model.ts
@Table
export default class Role extends Model<Role> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.INTEGER)
    id: number;

    @Column(DataType.TEXT)
    name: string;

    @BelongsToMany(() => Permission, () => PermissionRole)
    permissions: Permission[];

    @HasMany(() => User)
    users: User[];
}
//permission.model.ts
@Table
export default class Permission extends Model<Permission> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.INTEGER)
    id: number;

    @Column(DataType.TEXT)
    name: string;

    @Column(DataType.TEXT)
    method: string;

    @BelongsToMany(() => Role, () => PermissionRole)
    roles: Role[];
}
//permission-role.model.ts
@Table
export default class PermissionRole extends Model<PermissionRole> {

    @ForeignKey(() => Permission)
    @PrimaryKey
    @Column
    permission_id: number;

    @BelongsTo(() => Permission)
    permission: Permission;

    @ForeignKey(() => Role)
    @PrimaryKey
    @Column
    role_id: string;

    @BelongsTo(() => Role)
    role: Role;

}

This results in the following error:
Error: Foreign key for "Role" is missing on "Permission".

I did fix this issue setting manually the foreign key and other key on BelongsToMany annotation:

//role.model.ts
Table
export default class Role extends Model<Role> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.INTEGER)
    id: number;

    @Column(DataType.TEXT)
    name: string;

    @BelongsToMany(() => Permission, () => PermissionRole, "permission_id", "role_id")
    permissions: Permission[];

    @HasMany(() => User)
    users: User[];
}

All 10 comments

Restarting the development server seemed to have fixed it somehow.

My next problem is querying though. I want to get all rooms from a user with his id.

My query:

const rooms = await models.UserRoom
    .findAll<models.UserRoom>({
        include: [models.Room],
        where: {
            userId: id,
        },
    });

The error:
SequelizeEagerLoadingError: Room is not associated to UserRoom!

Why isn't it associated? I don't get what I'm missing.

Hey @sandervspl, this is because the association exists between User and Room, not UserRoom and User or Room. So you either need to define an additional relation (one-to-many between UserRoom and Room) if you want to retrieve the data like you did or you implement it like:

const rooms = await models.Room
    .findAll({
        include: [{
          model: models.User,
          where: {id}
        }],
    });

@sandervspl Is this still an issue for you or can this be closed?

Close this issue due to inactivity

Hi @RobinBuschmann, I have a same issue:

My code:

//role.model.ts
@Table
export default class Role extends Model<Role> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.INTEGER)
    id: number;

    @Column(DataType.TEXT)
    name: string;

    @BelongsToMany(() => Permission, () => PermissionRole)
    permissions: Permission[];

    @HasMany(() => User)
    users: User[];
}
//permission.model.ts
@Table
export default class Permission extends Model<Permission> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.INTEGER)
    id: number;

    @Column(DataType.TEXT)
    name: string;

    @Column(DataType.TEXT)
    method: string;

    @BelongsToMany(() => Role, () => PermissionRole)
    roles: Role[];
}
//permission-role.model.ts
@Table
export default class PermissionRole extends Model<PermissionRole> {

    @ForeignKey(() => Permission)
    @PrimaryKey
    @Column
    permission_id: number;

    @BelongsTo(() => Permission)
    permission: Permission;

    @ForeignKey(() => Role)
    @PrimaryKey
    @Column
    role_id: string;

    @BelongsTo(() => Role)
    role: Role;

}

This results in the following error:
Error: Foreign key for "Role" is missing on "Permission".

Hi @RobinBuschmann, I have a same issue:

My code:

//role.model.ts
@Table
export default class Role extends Model<Role> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.INTEGER)
    id: number;

    @Column(DataType.TEXT)
    name: string;

    @BelongsToMany(() => Permission, () => PermissionRole)
    permissions: Permission[];

    @HasMany(() => User)
    users: User[];
}
//permission.model.ts
@Table
export default class Permission extends Model<Permission> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.INTEGER)
    id: number;

    @Column(DataType.TEXT)
    name: string;

    @Column(DataType.TEXT)
    method: string;

    @BelongsToMany(() => Role, () => PermissionRole)
    roles: Role[];
}
//permission-role.model.ts
@Table
export default class PermissionRole extends Model<PermissionRole> {

    @ForeignKey(() => Permission)
    @PrimaryKey
    @Column
    permission_id: number;

    @BelongsTo(() => Permission)
    permission: Permission;

    @ForeignKey(() => Role)
    @PrimaryKey
    @Column
    role_id: string;

    @BelongsTo(() => Role)
    role: Role;

}

This results in the following error:
Error: Foreign key for "Role" is missing on "Permission".

I did fix this issue setting manually the foreign key and other key on BelongsToMany annotation:

//role.model.ts
Table
export default class Role extends Model<Role> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.INTEGER)
    id: number;

    @Column(DataType.TEXT)
    name: string;

    @BelongsToMany(() => Permission, () => PermissionRole, "permission_id", "role_id")
    permissions: Permission[];

    @HasMany(() => User)
    users: User[];
}

I just had the same issue. @albinojunior 's solution solved it for me though.

Perhaps this should be in the docs since the example is incomplete and results in this error?

I am experiencing different problem with many-to-many:

@BelongsToMany(() => Role, () => UserRole) roles: Role[];

The error is

(node:41692) UnhandledPromiseRejectionWarning: TypeError: Cannot read property
'prototype' of undefined
    at Sequelize.model (...\node_modules\sequelize-typescript\dist\sequelize\
        sequelize\sequelize.js:25:61)

Via poor man's debugger (i.e. console) I get

BelongsToManyAssociation {
  associatedClassGetter: [Function],
  options:
   { foreignKey: undefined,
     otherKey: undefined,
     through: [Function],
     as: 'roles' } }

and the through function is returning undefined.

Can anybody help?

Thanks, Karel

For anyone running into this issue, the problem was with "smart" import of all models from one file

import User from "./user.model";
import Role from "./role.model";
import UserRole from "./userRole.model";

export { Role, User, UserRole };

and importing them as import { Role, UserRole } from "./index"; which resulted in Role and UserRole being undefined. Changing that to import Role from './role.model' fixed the problem.

I guess, I have to study JavaScript exports more ... (the problem was in importing completely different file through paths style import and not using the path).

Try this article, it may help you
https://medium.com/@eth3rnit3/sequelize-relationships-ultimate-guide-f26801a75554

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fareshan picture fareshan  路  4Comments

libvirtadept picture libvirtadept  路  4Comments

KAMAELUA picture KAMAELUA  路  4Comments

chanlito picture chanlito  路  3Comments

bschveitzer picture bschveitzer  路  5Comments