본문 바로가기

프로그래밍/Javascript

TypeORM + MongoDB 적용 및 사용하지 않게 된 이유

TypeORM, MongoDB 적용 및 사용하지 않게 된 이유

 

TypeORM을 사용할 때 왜 Mongodb는 잘안쓰는지에 대해 궁금해서 직접 알아보기 위해 적용해본 내용을 기록 하였습니다.

 

진행하던 프로젝트의 포함되는 패키지는 다음과 같습니다.

  1. Nestjs : v8 (
    1. @nestjs/core": "^8.0.7"
  2. Mongodb(+4 Native) + Mongodb Package(4.1.2)
  3. TypeORM : v0.2.37
    1. @nestjs/typeorm": "^8.0.2

 


 

적용 전 지원 여부 알아보기

 

먼저 TypeORM을 지원하는 Platform은 다음과 같습니다.
TypeORM - Supported platforms

TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.

 

두번째로 TypeORM의 Mongodb Support입니다.
TypeORM - MongoDB support

TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.

TypeORM has basic MongoDB support. Most of TypeORM functionality is RDBMS-specific, this page contains all MongoDB-specific functionality documentation.

TypeORM은 기본 MongoDB를 지원합니다. TypeORM 기능의 대부분은 RDBMS에 고유하며 이 페이지에는 모든 MongoDB 관련 기능 설명서가 포함되어 있습니다.

 

지원하는 version은 공식 문서에 작성되어있지 않지만, TypeORM을 사용하지 않게 된 이유가 여기에 있습니다.( 글 작성일 기준으로 Typeorm은 Mongdb version3까지만 지원합니다.)

(적용 당시에는 지원 버전을 몰랐기 때문에 계속 진행하였습니다.)

 

 


 

 

Nest Framework 위에 TypeORM 적용하기

  1. TypeORM Modulize

database.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';

/**
 * 데이터베이스 모듈
 */
@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      useFactory: async () => ({
        type: 'mongodb',
        host: '--------',
        port: 27017,
        username: '--------',
        password: '--------',
        database: 'databaseName',
        entities: ['**/*.entity{.ts,.js}'],
      }),
    }),
  ],
  providers: [DatabaseService],
  exports: [TypeOrmModule],
})
export class DatabaseModule {
  constructor(connection: Connection) {}
}

 

2. Inject Database Module on AppModule

app.module.ts

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: '.env.local',
      // ignoreEnvFile: process.env.NODE_ENV !== 'local',
      validationSchema: Joi.object({
        MONGODB_HOST: Joi.string().required(),
      }),
    }),
    DatabaseModule,
    TypeOrmModule.forFeature([Parameter]),
  ],
  controllers: [AppController],
  providers: [
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
    {
      provide: APP_INTERCEPTOR,
      useClass: HttpResponseInterceptor,
    },
    AppService,
  ],
})
export class AppModule {}

3. Project Hierarchy

4. Run Application

$ nest start

 

여기까지 진행을 하고 실행을 하니 아래 에러가 발생하였습니다.

{ProjectPath}/src/parameters/parameters.entity.ts:1
import { Column, Entity, ObjectID, ObjectIdColumn } from 'typeorm';
^^^^^^

SyntaxError: Cannot use import statement outside a module

에러 내용은 SyntaxError였습니다.

Cannot use import statement outside a module

 

원인은 프로젝트가 Typescript프로젝트여서 였습니다.

TypeORM은 어플리케이션 실행시 Entity를 초기화하는 작업을 수행합니다.

이때 Entity가 작성된 파일은 Javascript여야하며, 이유는 TypeORM이 초기화하는 작업이 수행되는 코어가 Javascript Base이기 때문입니다.

 

구글링해보니 몇가지 해결법들이 공유되고 있었습니다.

TypeORM Entity in NESTJS - Cannot use import statement outside a module

    1. TypeORM Module Configuration의 entities 설정 path를 다음과 같이 수정하세요.
      entities: ['src/**/*.entity.{ts,js}']​
       
    2. TypeORM Module Configuration의 entities 설정 path를 다음과 같이 수정하세요.
      entities: ['../**/*.entity.{ts,js}']​
    3. The error you are getting is because you are attempting to import a ts file in a js context. So long as you aren't using webpack you can use this instead so that you get the correct files (가져오는 오류는 js 컨텍스트에서 ts 파일을 가져오려고 하기 때문입니다. webpack을 사용하지 않는 한 올바른 파일을 얻기 위해 이것을 대신 사용할 수 있습니다.)
      entities: [join(__dirname, '**', '*.entity.{ts,js}')]​

시도해본 결과 1,2,3번 모두 계속해서 문제가 해결되지 않았습니다.

그러나 3번에서 말하듯 webpack이나 별도 transpiling(ts to js)을 할 수 있다면, js로 Entity를 load하면 되기 때문에 문제가 해결될 것 같아 Nest가 BuildTime을 지나고. 만들어내는 dist 폴더의 Entity(js file)로 연결하는 방법을 시도 하였습니다.

 

최종적으로 아래 형태의 코드로 수정했습니다.

수정한 코드로 실행해보니 Database 연결까지 정상적으로 됬습니다.

마지막으로 구성해둔 Database의 데이터를 조회하는 것을 테스트해보겠습니다.

import { Controller, Get, HttpCode } from '@nestjs/common';
import { AppService } from './app.service';
import { InjectRepository } from '@nestjs/typeorm';
import { MongoRepository } from 'typeorm';
import { Parameter } from './parameters/parameters.entity';

@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    @InjectRepository(Parameter)
    private readonly parametersRepository: MongoRepository<Parameter>,
  ) {}

  @Get('/')
  async test() {
    const result = await this.parametersRepository.find({});
    console.log(result);
    return 'ok';
  }
}

간단하게 AppController에 / Endpoint로 GET요청시 find된 data를 반환하는 코드입니다.

 

시도해보니 아래 에러가 발생했습니다.

TypeError: Cannot read property 'prototype' of undefined

 

검색해보니 TypeORM은 Mongodb v4를 지원하지 않는다고 합니다.

TypeORM and MongoDB and Repositories: Cannot read property 'prototype' of undefined

 

제가 사용했던 버전은 v4였기 때문에 발생한 문제였고, 잘못된 정보가 아닌가 싶어 공식 문서를 찾아보니

버전에 대한 내용은 존재하지 않았습니다. 그래서 TypeORM Github에서 확인한 결과 저와 동일한 이슈들에 대해 다른 사람들도 겪고있었으며, Mongodb를 사용하기 위해서는 현재(작성일 2021.09.30)는 버전을 내리는 방법밖에 없다고 합니다.

 

이슈 링크

find() throws error while using mongodb · Issue #8146 · typeorm/typeorm

 

Nestjs 공식 문서에도 테스트 코드가 Mongodb는 Mongoose로 되어있고,

TypeORM의 버전도 0.2인걸로 보아 TypeORM + Mongodb는 아직 쓰기엔 시기상조인 것 같아 보입니다.

그래서 TypeORM + Mongodb의 실험은 여기서 종료를 하고, Mongoose로 개발을 진행할 계획입니다.