ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • nestjs, typeorm-extension을 사용한 seeding
    공부하기/node.js 2023. 2. 22. 03:34

    https://github.com/tsCalm/new-nest-survey/tree/seeder

     

    GitHub - tsCalm/new-nest-survey

    Contribute to tsCalm/new-nest-survey development by creating an account on GitHub.

    github.com


    erd

    위 이미지의 빨간 박스를 친 부분에 대한 seeding 작업을 진행합니다.

     

    개념

    • Seeder
      • 데이터베이스에 데이터를 삽입하는 방법 중 하나
      • 개발자들이 원하는 데이터를 자동으로 생성하고 데이터베이스에 추가할 수 있는 프로그램
      • Seeder는 일반적으로 데이터베이스 구성 파일과 함께 사용
      • 개발자들은 Seeder를 실행하여 데이터를 자동으로 생성 및 삽입할 수 있다
    • Seeding
      • Seeder를 실행하는 프로세스
      • 개발자들은 Seeder를 실행하여 데이터를 자동으로 생성하고 데이터베이스에 삽입
      • 이를 통해 애플리케이션이 실행될 때 일관성 있는 데이터가 생성되며, 개발 및 테스트 작업이 더욱 쉬워짐

    계획

    1. survey(설문지)를 3천개 생성한다.
    2. 하나의 survey(설문지)는 5개의 question(질문)을 갖는다.
    3. 하나의 question(질문)은 4개의 option(선택지)을 갖는다.

     

    1. 먼저 루트 경로에 data-soruce.ts 파일을 선언합니다.

    *2023-02-27 -> data-source.ts 파일을 만들면 dist/main.ts가 존재하지 않음*

    import { ConfigService } from '@nestjs/config';
    import { config } from 'dotenv';
    import { DataSource, DataSourceOptions } from 'typeorm';
    import { SeederOptions } from 'typeorm-extension';
    
    config(
    // 외부 데이터베이스에 연결하려면 아래 주석을 해제하고 .env파일 경로를 입력하세요
    //{ path: 'ENV파일주소' }
    );
    
    
    const configService = new ConfigService();
    const option: DataSourceOptions & SeederOptions = {
      type: 'mysql',
      host: configService.get('DB_HOST'),
      port: configService.get<number>('DB_PORT'),
      username: configService.get('DB_USERNAME'),
      password: configService.get('DB_PASSWORD'),
      database: configService.get('DB_NAME'),
      synchronize: false,
      logging: true,
      entities: ['src/**/*.entity.ts'],
      seeds: ['src/**/seed/*.ts'],
      factories: ['src/**/factory/*.ts'],
      // migrations: ['src/database/migrations/*.ts'],
      // migrationsTableName: 'migrations',
    };
    export default new DataSource(option);

    -> @nestjs/config 모듈을 사용하고 있기 때문에 ConfigService를 호출해서 datasoruce 파일을 만들어 주었습니다.

    만약 @nestjs/config 모듈을 사용하고 있지 않다면 process.env.DB_HOST등으로 바꿔서 사용하시면 됩니다.

     

    2. package.json에 seed 명령을 추가합니다.

    "scripts": {
        ...
        "seed": "ts-node -r tsconfig-paths/register ./node_modules/typeorm-extension/dist/cli/index.js seed",
      	...
      },

     

    3. seed-data/seed/index.ts 

    import { Survey } from 'src/survey/survey.entity';
    import { DataSource } from 'typeorm';
    import { Seeder } from 'typeorm-extension';
    
    export default class RootSeeder implements Seeder {
      async run(dataSource: DataSource): Promise<any> {
        const repository = dataSource.getRepository(Survey);
        await repository.insert([
          {
            name: '테스트 설문지',
            description: '설문지 설명입니다. 성실한 답변 부탁드립니다.',
          },
        ]);
      }
    }

     

    4. 터미널에서 npm run seed 명령을 실행합니다. 아래는 결과입니다.

     

     

    5. 이제 factory를 생성한 후 faker.js를 사용하여 동적으로 데이터를 넣어보도록 하겠습니다.

    seed-data/factory/survey.factory.ts 

    import { setSeederFactory } from 'typeorm-extension';
    import { Survey } from '../../survey/survey.entity';
    
    export default setSeederFactory(Survey, (faker) => {
      const survey = new Survey();
      survey.name = faker.lorem.lines(1);
      survey.description = faker.lorem.lines(3);
      return survey;
    });

     

    6. seed-data/seed/index.ts 

    import { Survey } from 'src/survey/survey.entity';
    import { DataSource } from 'typeorm';
    import { Seeder, SeederFactoryManager } from 'typeorm-extension';
    
    export default class RootSeeder implements Seeder {
      async run(
        dataSource: DataSource,
        factoryManager: SeederFactoryManager,
      ): Promise<any> {
    
        const userFactory = factoryManager.get(Survey);
        // 시드 데이터를 1개만 저장하고 싶은 경우 사용
        // await userFactory.save();
    	
        // 시드 데이터를 여러개 저장하고 싶은 경우 사용
        const surveyList = await userFactory.saveMany(5);
        console.log(surveyList);
      }
    }

     

    결과

     

    7. seed-data/factory/question.factory.ts

    import { setSeederFactory } from 'typeorm-extension';
    import { Question } from '../../question/question.entity';
    
    export default setSeederFactory(Question, (faker) => {
      const question = new Question();
      question.text = faker.lorem.lines(1);
      question.type = 'number';
    
      return question;
    });

     

    8. seed-data/factory/option.factory.ts

    import { setSeederFactory } from 'typeorm-extension';
    import { Option } from '../../option/option.entity';
    
    export default setSeederFactory(Option, (faker) => {
      const option = new Option();
      option.text = faker.lorem.word();
      return option;
    });

     

    9. seed-data/seed/index.ts 

    import { Option } from 'src/option/option.entity';
    import { Question } from 'src/question/question.entity';
    import { Survey } from 'src/survey/survey.entity';
    import { DataSource } from 'typeorm';
    import { Seeder, SeederFactoryManager } from 'typeorm-extension';
    
    export default class RootSeeder implements Seeder {
      async run(
        dataSource: DataSource,
        factoryManager: SeederFactoryManager,
      ): Promise<any> {
        const surveyFactory = factoryManager.get(Survey);
        const questionFactory = factoryManager.get(Question);
        const optionFactory = factoryManager.get(Option);
    
        const surveyList = await surveyFactory.saveMany(3000);
        let questionPendingList = [];
        let optionPendingList = [];
    
        for (const survey of surveyList) {
          [1, 2, 3, 4, 5].forEach((num) => {
            const newQuestion = questionFactory.save({
              survey_id: survey.id,
              question_number: num,
            });
            questionPendingList.push(newQuestion);
          });
        }
    
        const questionList = await Promise.all(questionPendingList);
        for (const question of questionList) {
          [1, 2, 3, 4].forEach((num) => {
            const newOption = optionFactory.save({
              question_id: question.id,
              option_number: num,
            });
            optionPendingList.push(newOption);
          });
        }
    
        await Promise.all(optionPendingList);
      }
    }

     

    결과

     

    survey

     

    question

     

    option

     

Designed by Tistory.