Sequelize-typescript: One to Many association issue

Created on 12 Dec 2017  路  5Comments  路  Source: RobinBuschmann/sequelize-typescript

I'm really new with typescript and sequelize, I follow Nestjs Sequelize guideline. Everything works fine for one model but when I want to associate between two model, there is an error while loading model.

users.entity.ts file

import { Table, Column, Model, DataType, Default, CreatedAt, UpdatedAt, DeletedAt, HasMany } from 'sequelize-typescript';
import { Token } from '../tokens/tokens.entity';

@Table
export class User extends Model<User> {
    @Column({
        type: DataType.CHAR(255),
        allowNull: false
    })
    name: string;

    @Column({
        type: DataType.CHAR(255),
        allowNull: false
    })
    email: string;

    @Column({
        type: DataType.CHAR(255),
        allowNull: false
    })
    imageUrl: string;

    @Column({
        type: DataType.ENUM('male', 'female'),
        allowNull: false
    })
    gender: string;

    @Column({
        type: DataType.CHAR(255),
        allowNull: false
    })
    ageRange: string;

    @Default(false)
    @Column({
        type: DataType.BOOLEAN
    })
    isAdmin: boolean;

    @Default(false)
    @Column({
        type: DataType.BOOLEAN
    })
    isDeleted: boolean;

    @CreatedAt
    createdAt: Date;

    @UpdatedAt
    updatedAt: Date;

    @DeletedAt
    deletedAt: Date;

    @HasMany(() => Token, 'userId')
    tokens: Token[];
};

tokens.entity.ts

import { Table, Column, Model, DataType, Default, CreatedAt, UpdatedAt, ForeignKey, BelongsTo } from 'sequelize-typescript';
import { User } from '../users/users.entity';

@Table
export class Token extends Model<Token> {
    @Column({
        type: DataType.TEXT('medium'),
        allowNull: false
    })
    accessToken: string;

    @Column({
        type: DataType.TEXT('medium'),
        allowNull: false
    })
    refreshToken: string;

    @ForeignKey(() => User)
    @Column
    userId: number;

    @BelongsTo(() => User, 'userId')
    user: User;

    @CreatedAt
    createdAt: Date;

    @UpdatedAt
    updatedAt: Date;
};

error log

TypeError: Cannot read property 'userId' of undefined
    at new HasMany (/Users/win/sr-api/node_modules/sequelize/lib/associations/has-many.js:76:39)
    at Function.hasMany (/Users/win/sr-api/node_modules/sequelize/lib/associations/mixin.js:26:25)
    at Function._target.(anonymous function) [as hasMany] (/Users/win/sr-api/node_modules/sequelize-typescript/lib/models/BaseModel.js:35:41)
    at Object.processAssociation (/Users/win/sr-api/node_modules/sequelize-typescript/lib/services/association.js:183:32)
    at /Users/win/sr-api/node_modules/sequelize-typescript/lib/models/BaseSequelize.js:80:80
    at Array.forEach (<anonymous>)
    at /Users/win/sr-api/node_modules/sequelize-typescript/lib/models/BaseSequelize.js:80:26
    at Array.forEach (<anonymous>)
    at Sequelize.BaseSequelize.associateModels (/Users/win/sr-api/node_modules/sequelize-typescript/lib/models/BaseSequelize.js:76:16)
    at Sequelize.BaseSequelize.addModels (/Users/win/sr-api/node_modules/sequelize-typescript/lib/models/BaseSequelize.js:62:14)
    at Object.<anonymous> (/Users/win/sr-api/src/modules/database/database.providers.ts:18:23)
    at Generator.next (<anonymous>)
    at /Users/win/sr-api/src/modules/database/database.providers.ts:7:71
    at Promise (<anonymous>)
    at __awaiter (/Users/win/sr-api/src/modules/database/database.providers.ts:3:12)
    at Object.useFactory [as metatype] (/Users/win/sr-api/src/modules/database/database.providers.ts:9:32)
    at Injector.<anonymous> (/Users/win/sr-api/node_modules/@nestjs/core/injector/injector.js:82:59)
    at Generator.next (<anonymous>)
    at /Users/win/sr-api/node_modules/@nestjs/core/injector/injector.js:7:71
    at Promise (<anonymous>)
    at __awaiter (/Users/win/sr-api/node_modules/@nestjs/core/injector/injector.js:3:12)
    at resolveConstructorParams (/Users/win/sr-api/node_modules/@nestjs/core/injector/injector.js:77:98)
 1: node::Abort() [/usr/local/bin/node]
 2: node::Chdir(v8::FunctionCallbackInfo<v8::Value> const&) [/usr/local/bin/node]
 3: v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) [/usr/local/bin/node]
 4: v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/usr/local/bin/node]
 5: v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/usr/local/bin/node]
 6: 0x2c597d3040dd
 7: 0x2c597d3f35e9

I know that it's similar to #144 but I can't seem to fix it

Another thing I'm curious modelPaths Can i exclude some folder in that command?

Most helpful comment

Ah ok, this is the issue. You need to add them at once like sequelize.addModels([User, Token]). When addModels is called, sequelize tries to resolve all associations related to the passed models.

But of course, this is not a sufficient error message.

All 5 comments

Hey @thestrayed, can you show me how you added the models to the seuqelize instance? Do you use a path or a class reference?

In case of a path you either need to use the same filename as model name (User.ts) or if using another file name, you need to default export your model (export default class User {...})

Excluding is currently not possible, but you can use globs https://github.com/RobinBuschmann/sequelize-typescript/blob/master/README.md#globs

@RobinBuschmann
This is how I add model in provider

import { Sequelize } from 'sequelize-typescript';
import { Token } from '../tokens/tokens.entity';
import { User } from '../users/users.entity';

export const databaseProviders = [
    {
        provide: 'SequelizeInstance',
        useFactory: async () => {
            const sequelize = new Sequelize({
                dialect: 'mysql',
                host: process.env.DB_HOST,
                port: parseInt(process.env.DB_PORT),
                username: process.env.DB_USERNAME,
                password: process.env.DB_PASSWORD,
                database: process.env.DB_NAME,
            });
            sequelize.addModels([User]);
            sequelize.addModels([Token]);
            await sequelize.sync();
            return sequelize;
        }
    }
];

Ah ok, this is the issue. You need to add them at once like sequelize.addModels([User, Token]). When addModels is called, sequelize tries to resolve all associations related to the passed models.

But of course, this is not a sufficient error message.

It works now with sequelize.addModels([User, Token]); Thank you

HI @RobinBuschmann
is it possible to add this use case in examples which you have shared. I also struggled quite a few hours & might be same case with many others

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lilling picture lilling  路  4Comments

JustGreg picture JustGreg  路  4Comments

chanlito picture chanlito  路  3Comments

josecolella picture josecolella  路  4Comments

fareshan picture fareshan  路  3Comments