> For the complete documentation index, see [llms.txt](https://jakekwak.gitbook.io/nestjs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jakekwak.gitbook.io/nestjs/techniques/mongo.md).

# Mongo

## Mongo

MongoDB 데이터베이스를 처리하는 방법에는 두 가지가 있습니다. MongoDB를 지원하는 [ORM](https://github.com/typeorm/typeorm) 또는 가장 인기있는 [MongoDB](https://www.mongodb.org/) 와 [Mongoose](http://mongoosejs.com)를 사용할 수 있습니다. 객체 모델링 도구. **ORM**을 유지하려면 다음 단계를 수행하십시오. 그렇지 않으면 전용 `@nestjs/mongoose` 패키지를 사용합니다.

먼저 필요한 모든 종속성을 설치해야합니다.

```bash
$ npm install --save @nestjs/mongoose mongoose
```

설치 과정이 완료되면 `MongooseModule`을 루트 `ApplicationModule`로 가져올 수 있습니다.

```typescript
@@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](http://mongoosejs.com) 패키지에서 `mongoose.connect()`와 동일한 구성 객체를 받습니다.

## Model injection

Mongoose를 사용하면 모든 것이 [스키마](http://mongoosejs.com/docs/guide.html)에서 파생됩니다. `CatSchema`를 정의 해 봅시다:

```typescript
@@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`을 봅시다:

```typescript
@@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`에 삽입할 수 있습니다.

```typescript
@@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](https://app.gitbook.com/fundamentals/custom-providers)를 설정해야 합니다. 실제로, 등록된 각 모델은 `NameModel` 토큰으로 표시되며 여기서 `Name`은 모델의 이름입니다.

`@nestjs/mongoose` 패키지는 주어진 모델 이름을 기반으로 준비된 토큰을 반환하는 `getModelToken()`함수를 제공합니다.

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

이제 하드 코드 된 `catModel`이 `Model<Cat>`로 사용됩니다. 공급자가 `@InjectModel()`데코레이터를 사용하여`Model<Cat>`를 요청할 때마다 Nest는 등록 된 `catModel` 객체를 사용합니다.

## Async configuration

모듈 옵션을 미리 전달하는 대신 비동기식으로 전달하려는 경우가 종종 있습니다. 이 경우 비동기 데이터를 처리하는 몇가지 다양한 방법을 제공하는 `forRootAsync()`메서드를 사용하십시오.

가능한 첫 번째 방법은 팩토리 기능을 사용하는 것입니다.

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

분명히, 우리 팩토리는 다른 모든 것처럼 행동합니다 ( `async`일 수도 있고 `inject`을 통해 의존성을 주입할 수도 있습니다).

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

또는 팩토리 대신 클래스를 사용할 수 있습니다.

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

위의 구성은 `MongooseModule`내에서 `MongooseConfigService`를 인스턴스화 하고이를 활용하여 옵션 개체를 만듭니다. `MongooseConfigService`는 `MongooseOptionsFactory` 인터페이스를 구현해야 합니다.

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

`MongooseModule` 내에 `MongooseConfigService`가 생성되는 것을 막고 다른 모듈에서 가져온 공급자를 사용하기 위해 `useExisting` 문법을 사용할 수 있습니다.

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

하나의 중요한 차이점을 가진 `useClass`와 동일하게 작동합니다. `MongooseModule`은 가져온 모듈을 조회하여 이미 생성된 `ConfigService`를 자체적으로 인스턴스화하는 대신 재사용합니다.

## Example

실제 사례는 [여기](https://github.com/nestjs/nest/tree/master/sample/14-mongoose-base)에서 확인할 수 있습니다.
