DB 두 개 사용 환경설정 (With Prisma)

백수만·2023년 3월 11일

프로젝트

목록 보기
1/6
post-thumbnail

toquiz 프로젝트에서 RDB(MySQL)과 NoSQL(MongoDB)를 같이 사용하고자 한다. 이유는 다음과 같다.

  • RDB를 사용하는 이유
    • User, Panel, Question, Answer
    • 정합성이 중요한 정보는 Transaction을 활용하여 RDB에 안전하게 저장하기 위해서
  • NoSQL을 사용하는 이유
    • toquizUser
    • 익명 유저의 경우 계속 생성되므로 데이터가 많을 수 있다고 판단함
    • 익명 유저 정보는 쿠키에 1년의 만료기한을 주고 유지할 것
      • → 만료기한 지날 시 MongoDB의 TTL인덱스를 이용해 지우기 위해

Prisma에서 DB 2개 적용

  1. mongodb, mysql schema를 각각 생성한다.

    • .env.dev에 MONGODB_DATABASE_URL, MYSQL_DATABASE_URL을 각각 다음과 같은 형식으로 생성
      • db://USERNAME:PASSWORD@HOST/DATABASE
    • mongodb.schema.ts
      generator client {
        provider = "prisma-client-js"
      	output   = "./generated/mysql"
      }
      
      datasource db {
        provider = "mongodb"
        url      = env("MONGODB_DATABASE_URL")
      }
      
      model ToquizModel {
        id        String   @id @default(auto()) @map("_id") @db.ObjectId
        pannelId  Int
        createdAt DateTime @default(now())
        updatedAt DateTime @updatedAt
      }
    • mysql.schema.ts
      generator client {
        provider = "prisma-client-js"
      	output   = "./generated/mongodb"
      }
      
      datasource db {
        provider = "mysql"
        url      = env("MYSQL_DATABASE_URL")
      }
      
      model User {
        id String @id @default(uuid())
      
        pannels         Pannel[]
        answers         Answer[]
        scrappedPannels Scrap[]
      
        username  String
        password  String
        nickname  String
        provider  String
        createdAt DateTime  @default(now())
        updatedAt DateTime  @updatedAt()
        deletedAt DateTime?
      }
      
      model Scrap {
        user     User   @relation(fields: [userId], references: [id])
        userId   String
        pannel   Pannel @relation(fields: [pannelId], references: [id])
        pannelId Int
      
        createdAt DateTime  @default(now())
        updatedAt DateTime  @updatedAt()
        deletedAt DateTime?
      
        @@id([userId, pannelId])
      }
      
      model Pannel {
        id Int @id @default(autoincrement())
      
        user   User   @relation(fields: [userId], references: [id])
        userId String
      
        scrappedUsers Scrap[]
        questions     Question[]
      
        describe   String
        isArchived Boolean   @default(false)
        scrapNum   Int       @default(0)
        createdAt  DateTime  @default(now())
        updatedAt  DateTime  @updatedAt
        deletedAt  DateTime?
      }
      
      model Question {
        id Int @id @default(autoincrement())
      
        pannel   Pannel @relation(fields: [pannelId], references: [id])
        pannelId Int
      
        answers Answer[]
      
        content   String
        answerNum Int       @default(0)
        likeNum   Int       @default(0)
        createdAt DateTime  @default(now())
        updatedAt DateTime  @updatedAt
        deletedAt DateTime?
      }
      
      model Answer {
        id Int @id @default(autoincrement())
      
        User       User     @relation(fields: [userId], references: [id])
        userId     String
        Question   Question @relation(fields: [questionId], references: [id])
        questionId Int
      
        content   String
        createdAt DateTime  @default(now())
        updatedAt DateTime  @updatedAt
        deletedAt DateTime?
      }
      
  2. yarn generate를 통해 ./prisma/client 생성

    • yarn generate —schema ./prisma/mysql.schema.prisma
    • yarn generate —schema ./prisma/mongodb.schema.prisma
    • 위에서 generator client의 output에 ./generated/{db이름} 으로 설정했기 때문에 다음과 같이 생성된다.
  3. PrismaService 생성

    • libs/prisma-service에 다음과 같이 설정했다.
    • mongodb-prisma.service.ts
      import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
      import { PrismaClient } from '../../prisma/generated/mongodb';
      
      @Injectable()
      export class MongodbPrismaService extends PrismaClient implements OnModuleInit {
        async onModuleInit() {
          await this.$connect();
        }
      
        async enableShutdownHooks(app: INestApplication) {
          this.$on('beforeExit', async () => {
            await app.close();
          });
        }
      }
    • mysql-prisma.service.ts
      import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
      import { PrismaClient } from '../../prisma/generated/mysql';
      
      @Injectable()
      export class MysqlPrismaService extends PrismaClient implements OnModuleInit {
        async onModuleInit() {
          await this.$connect();
        }
      
        async enableShutdownHooks(app: INestApplication) {
          this.$on('beforeExit', async () => {
            await app.close();
          });
        }
      }
  4. module에서 import 후 사용

    • user.module.ts
      import { Module } from '@nestjs/common';
      import { MysqlPrismaService, MongodbPrismaService } from 'libs/prisma-service';
      import { UserController } from './user.controller';
      import { UserService } from './user.service';
      
      @Module({
        imports: [],
        controllers: [UserController],
        providers: [UserService, **MysqlPrismaService**, **MongodbPrismaService**],
      })
      export class UserModule {}

추가)

0개의 댓글