NestJS에서 TypeORM, Mysql을 사용하는 방법에 대해 알아보자.
nest new 프로젝트명
명령어로 프로젝트를 생성하면 여러 파일들이 만들어진다. 그 중 app.module.ts
파일을 기억해두자.
NestJS 초기세팅에 대해 자세히 알고 싶다면 이 포스팅을 참고하면 된다.
이제 우리가 사용할 DB인 Mysql과 NestJS를 연동해줄 것이다. ORM은 TypeORM을 사용한다.
우선 TypeORM을 설치하자.
npm install --save @nestjs/typeorm typeorm mysql2
NestJS에서 제공하는 TypeORM 패키지를 설치한다. DB로는 Mysql를 사용할 것이기 때문에 mysql2
를 선택했다. 다른 DB를 선택하는 것도 가능하다.
Mysql은 이미 설치되어 있어야 한다. 만약 설치가 안 되어 있다면 이 포스팅을 참고해서 설치하자.
설치가 완료되었으면 본격적으로 데이터베이스 연동을 시도헤보자.
공식문서에 따르면 데이터베이스 연동하는 방법은 2가지이다.
1.app.module.ts
파일에 설정하는 방법
2. 프로젝트 루트 디렉토리에 ormconfig.json
파일을 생성해서 설정하는 방법
// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
entities: [User, Product], // 사용할 entity의 클래스명을 넣어둔다.
synchronize: true, // false로 해두는 게 안전하다.
}),
],
})
export class AppModule {}
app.module.ts에서 TypeOrmModule을 import해서 사용할 수 있다. TypeOrmModule의 forRoot()
메서드 인자로 DB 정보를 넣어두면 연동이 된다.
여기서 forRoot()
가 TypeORM에서 DB 연동할 때 사용하는 createConnection()
함수 역할을 해주고 있다고 보면 된다.
synchronize
Setting
synchronize: true
shouldn't be used in production - otherwise you can lose production data.
app.module.ts 파일의 forRoot()
에 설정값을 직접 입력하지 않고, 루트 디렉토리에 ormconfig.json
파일을 만들어서 설정하는 방법이다.
// ormconfig.json
{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "root",
"password": "root",
"database": "test",
"entities": ["dist/**/*.entity{.ts,.js}"],
"synchronize": true
}
// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [TypeOrmModule.forRoot()],
})
export class AppModule {}
forRoot()
에서 DB 접근 정보를 주지 않으면, 루트 경로의 ormconfig.json
의 파일에서 설정 값을 자동으로 찾아 사용한다.
DB 비밀번호라던지 민감한 정보들이 있으므로 파일을 따로 만들어 보관하는 편이 보안 측면에 좋다. 나중에 gitignore에 추가해서 이 파일만 빼고 깃허브에 올릴 수도 있다.
forRoot()
메소드를 통해 사용할 수 있었던 추가적인 설정들을 바로 사용할 수 없다.
추가적인 설정 속성에는 autoLoadEntities
, retryDelay
등이 있다.
예를 들어 첫 번째 방법에서는 이렇게 설정을 추가해주기만 하면 된다.
// app.module.ts
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
entities: [],
synchronize: true,
autoLoadEntities: true, // 추가!!
}),
],
})
다행히도 두 번째 방법에서도 답이 없는 건 아니다. 바로 getConnectionOptions
을 사용하면 된다.
// app.module.ts
TypeOrmModule.forRootAsync({
useFactory: async () =>
Object.assign(await getConnectionOptions(), {
autoLoadEntities: true,
}),
})
ormconfig.json
파일을 사용한다면 내가 사용할 entity를 경로
로 설정할 수밖에 없다. "entities": ["dist/**/*.entity{.ts,.js}"]
이렇게 말이다. 이렇게 되면 모든 entity가 실제 DB상의 테이블로 만들어진다. 하지만, entity 중에서 실제 테이블로 만들면 안 되는 것들이 있다. 예를 들어 그저 다른 테이블에서 참고하기 위해 만들어진 entity 말이다.
https://github.com/typeorm/typeorm/issues/1654
이 사이트에 따르면 아래와 같은 식으로 내가 원하는 파일을 제외할 수 있다고 한다.
{
entities: ['src/entity/**/!(*.test.ts)']
}
(2021.04.16 추가)
실제로 데이터베이스에 테이블을 만들고 싶지 않은 클래스는 @entity 데코레이터를 달아주지 않으면 된다!
이런 식으로 추상 클래스를 선언한 다음 확장해서 사용할 수 있다.
export abstract class Content {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
description: string
}
@Entity()
export class Photo extends Content {
@Column()
size: string
}
참고사이트 : https://yangeok.github.io/orm/2020/12/14/typeorm-decorators.html