Mongo

Mongo

MongoDB λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ²˜λ¦¬ν•˜λŠ” λ°©λ²•μ—λŠ” 두 κ°€μ§€κ°€ μžˆμŠ΅λ‹ˆλ‹€. MongoDBλ₯Ό μ§€μ›ν•˜λŠ” ORM λ˜λŠ” κ°€μž₯ μΈκΈ°μžˆλŠ” MongoDB 와 Mongooseλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 객체 λͺ¨λΈλ§ 도ꡬ. ORM을 μœ μ§€ν•˜λ €λ©΄ λ‹€μŒ 단계λ₯Ό μˆ˜ν–‰ν•˜μ‹­μ‹œμ˜€. κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ μ „μš© @nestjs/mongoose νŒ¨ν‚€μ§€λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

λ¨Όμ € ν•„μš”ν•œ λͺ¨λ“  쒅속성을 μ„€μΉ˜ν•΄μ•Όν•©λ‹ˆλ‹€.

$ npm install --save @nestjs/mongoose mongoose

μ„€μΉ˜ 과정이 μ™„λ£Œλ˜λ©΄ MongooseModule을 루트 ApplicationModule둜 κ°€μ Έμ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

@@filename(app.module)
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [MongooseModule.forRoot('mongodb://localhost/nest')],
})
export class ApplicationModule {}

forRoot()λ©”μ†Œλ“œλŠ” Mongoose νŒ¨ν‚€μ§€μ—μ„œ mongoose.connect()와 λ™μΌν•œ ꡬ성 객체λ₯Ό λ°›μŠ΅λ‹ˆλ‹€.

Model injection

Mongooseλ₯Ό μ‚¬μš©ν•˜λ©΄ λͺ¨λ“  것이 μŠ€ν‚€λ§ˆμ—μ„œ νŒŒμƒλ©λ‹ˆλ‹€. CatSchemaλ₯Ό μ •μ˜ ν•΄ λ΄…μ‹œλ‹€:

@@filename(schemas/cat.schema)
import * as mongoose from 'mongoose';

export const CatSchema = new mongoose.Schema({
  name: String,
  age: Number,
  breed: String,
});

CatsSchemaλŠ” cats 디렉토리에 μ†ν•©λ‹ˆλ‹€. 이 λ””λ ‰ν† λ¦¬λŠ” CatsModule을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€. μŠ€ν‚€λ§ˆ νŒŒμΌμ„ μœ μ§€ν•  μœ„μΉ˜λŠ” κ²°μ •μž…λ‹ˆλ‹€. 우리의 κ΄€μ μ—μ„œ λ³Ό λ•Œ κ°€μž₯ 쒋은 방법은 μ μ ˆν•œ λͺ¨λ“ˆ 디렉토리에 거의 도메인을 μœ μ§€ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

CatsModule을 λ΄…μ‹œλ‹€:

@@filename(cats.module)
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { CatSchema } from './schemas/cat.schema';

@Module({
  imports: [MongooseModule.forFeature([{ name: 'Cat', schema: CatSchema }])],
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}

이 λͺ¨λ“ˆμ€ forFeature()λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ ν˜„μž¬ λ²”μœ„μ— 등둝할 λͺ¨λΈμ„ μ •μ˜ν•©λ‹ˆλ‹€. 덕뢄에 @InjectModel()λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜μ—¬ CatModel을 CatsService에 μ‚½μž…ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

@@filename(cats.service)
import { Model } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Cat } from './interfaces/cat.interface';
import { CreateCatDto } from './dto/create-cat.dto';

@Injectable()
export class CatsService {
  constructor(@InjectModel('Cat') private readonly catModel: Model<Cat>) {}

  async create(createCatDto: CreateCatDto): Promise<Cat> {
    const createdCat = new this.catModel(createCatDto);
    return await createdCat.save();
  }

  async findAll(): Promise<Cat[]> {
    return await this.catModel.find().exec();
  }
}
@@switch
import { Model } from 'mongoose';
import { Injectable, Dependencies } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';

@Injectable()
@Dependencies(InjectModel('Cat'))
export class CatsService {
  constructor(catModel) {
    this.catModel = catModel;
  }

  async create(createCatDto) {
    const createdCat = new this.catModel(createCatDto);
    return await createdCat.save();
  }

  async findAll() {
    return await this.catModel.find().exec();
  }
}

Testing

μ‘μš© ν”„λ‘œκ·Έλž¨μ„ λ‹¨μœ„ ν…ŒμŠ€νŠΈν•˜λŠ” 경우 일반적으둜 λ°μ΄ν„°λ² μ΄μŠ€ 연결을 ν”Όν•˜μ—¬ ν…ŒμŠ€νŠΈ 슈트λ₯Ό λ…λ¦½μ μœΌλ‘œ λ§Œλ“€κ³  μ‹€ν–‰ ν”„λ‘œμ„ΈμŠ€λ₯Ό κ°€λŠ₯ν•œ ν•œ 빨리 λ§Œλ“­λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ ν΄λž˜μŠ€λŠ” μ—°κ²° μΈμŠ€ν„΄μŠ€μ—μ„œ κ°€μ Έμ˜¨ λͺ¨λΈμ— 따라 λ‹¬λΌμ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€. 그럼 λ­˜κ°€μš”? 해결책은 κ°€μ§œ λͺ¨λΈμ„ λ§Œλ“œλŠ” κ²ƒμž…λ‹ˆλ‹€. 이λ₯Ό λ‹¬μ„±ν•˜κΈ° μœ„ν•΄ custom providerλ₯Ό μ„€μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ‹€μ œλ‘œ, λ“±λ‘λœ 각 λͺ¨λΈμ€ NameModel ν† ν°μœΌλ‘œ ν‘œμ‹œλ˜λ©° μ—¬κΈ°μ„œ Name은 λͺ¨λΈμ˜ μ΄λ¦„μž…λ‹ˆλ‹€.

@nestjs/mongoose νŒ¨ν‚€μ§€λŠ” μ£Όμ–΄μ§„ λͺ¨λΈ 이름을 기반으둜 μ€€λΉ„λœ 토큰을 λ°˜ν™˜ν•˜λŠ” getModelToken()ν•¨μˆ˜λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.

@Module({
  providers: [
    CatsService,
    {
      provide: getModelToken('Cat'),
      useValue: catModel,
    },
  ],
})
export class CatsModule {}

이제 ν•˜λ“œ μ½”λ“œ 된 catModel이 Model<Cat>둜 μ‚¬μš©λ©λ‹ˆλ‹€. κ³΅κΈ‰μžκ°€ @InjectModel()λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜μ—¬Model<Cat>λ₯Ό μš”μ²­ν•  λ•Œλ§ˆλ‹€ NestλŠ” 등둝 된 catModel 객체λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

Async configuration

λͺ¨λ“ˆ μ˜΅μ…˜μ„ 미리 μ „λ‹¬ν•˜λŠ” λŒ€μ‹  λΉ„λ™κΈ°μ‹μœΌλ‘œ μ „λ‹¬ν•˜λ €λŠ” κ²½μš°κ°€ μ’…μ’… μžˆμŠ΅λ‹ˆλ‹€. 이 경우 비동기 데이터λ₯Ό μ²˜λ¦¬ν•˜λŠ” λͺ‡κ°€μ§€ λ‹€μ–‘ν•œ 방법을 μ œκ³΅ν•˜λŠ” forRootAsync()λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ‹­μ‹œμ˜€.

κ°€λŠ₯ν•œ 첫 번째 방법은 νŒ©ν† λ¦¬ κΈ°λŠ₯을 μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

MongooseModule.forRootAsync({
  useFactory: () => ({
    uri: 'mongodb://localhost/nest',
  }),
});

λΆ„λͺ…νžˆ, 우리 νŒ©ν† λ¦¬λŠ” λ‹€λ₯Έ λͺ¨λ“  κ²ƒμ²˜λŸΌ ν–‰λ™ν•©λ‹ˆλ‹€ ( async일 μˆ˜λ„ 있고 inject을 톡해 μ˜μ‘΄μ„±μ„ μ£Όμž…ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€).

MongooseModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    uri: configService.getString('MONGODB_URI'),
  }),
  inject: [ConfigService],
});

λ˜λŠ” νŒ©ν† λ¦¬ λŒ€μ‹  클래슀λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

MongooseModule.forRootAsync({
  useClass: MongooseConfigService,
});

μœ„μ˜ ꡬ성은 MongooseModuleλ‚΄μ—μ„œ MongooseConfigServiceλ₯Ό μΈμŠ€ν„΄μŠ€ν™” ν•˜κ³ μ΄λ₯Ό ν™œμš©ν•˜μ—¬ μ˜΅μ…˜ 개체λ₯Ό λ§Œλ“­λ‹ˆλ‹€. MongooseConfigServiceλŠ” MongooseOptionsFactory μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄μ•Ό ν•©λ‹ˆλ‹€.

@Injectable()
class MongooseConfigService implements MongooseOptionsFactory {
  createMongooseOptions(): MongooseModuleOptions {
    return {
      uri: 'mongodb://localhost/nest',
    };
  }
}

MongooseModule 내에 MongooseConfigServiceκ°€ μƒμ„±λ˜λŠ” 것을 막고 λ‹€λ₯Έ λͺ¨λ“ˆμ—μ„œ κ°€μ Έμ˜¨ κ³΅κΈ‰μžλ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄ useExisting 문법을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

MongooseModule.forRootAsync({
  imports: [ConfigModule],
  useExisting: ConfigService,
});

ν•˜λ‚˜μ˜ μ€‘μš”ν•œ 차이점을 κ°€μ§„ useClass와 λ™μΌν•˜κ²Œ μž‘λ™ν•©λ‹ˆλ‹€. MongooseModule은 κ°€μ Έμ˜¨ λͺ¨λ“ˆμ„ μ‘°νšŒν•˜μ—¬ 이미 μƒμ„±λœ ConfigServiceλ₯Ό 자체적으둜 μΈμŠ€ν„΄μŠ€ν™”ν•˜λŠ” λŒ€μ‹  μž¬μ‚¬μš©ν•©λ‹ˆλ‹€.

Example

μ‹€μ œ μ‚¬λ‘€λŠ” μ—¬κΈ°μ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

Last updated

Was this helpful?