본문 바로가기

Mongoose를 활용한 MongoDB 연동

MongoDB의 문서 모델과 Mongoose 스키마를 이해하고 모델 주입부터 기본 데이터 작업까지 NestJS에 연결합니다.

관계형 데이터베이스와 TypeORM 연동에 이어, NestJS에서 NoSQL 데이터베이스인 MongoDB를 사용하는 방법을 다룹니다.

관계형 데이터베이스가 엄격한 스키마와 ACID(원자성, 일관성, 고립성, 지속성)를 통해 정합성을 강조한다면, NoSQL 데이터베이스는 유연한 스키마와 수평 확장성, 대량 비정형 데이터 처리에 강점을 가집니다.

특히 MongoDB는 문서(Document) 기반 NoSQL 데이터베이스로, JSON과 유사한 BSON(Binary JSON) 형식으로 데이터를 저장해 웹 애플리케이션 개발에서 직관적이고 효율적으로 사용할 수 있습니다.

NestJS는 TypeORM을 통한 관계형 데이터베이스 연동만큼이나 MongoDB와의 연동도 매끄럽게 지원합니다.

주로 Mongoose 라이브러리와 NestJS의 @nestjs/mongoose 패키지를 사용하여 MongoDB를 연동합니다.

아래 그림은 MongoDB의 유연한 문서 저장 방식 위에 Mongoose가 스키마와 모델 경계를 얹는 구조를 먼저 정리합니다.

연결과 스키마가 모델을 만들고 서비스가 문서를 다룬다

연결/스키마에서 Model을 만든 뒤 HTTP 값이 service/model을 거쳐 문서로 이동하며 원문에 없는 사전 pipe를 추가하지 않는다.

Nest Mongoose · 모델과 문서

연결과 Schema로 Model을 등록하고, 서비스가 문서를 조회·저장합니다

forRoot는 연결 URI를, forFeature는 모델 이름과 Schema를 등록합니다. 본문의 inline body 타입은 HTTP 런타임 검증이 아니며, Mongoose의 unique 선언은 validator 대신 실제 MongoDB 인덱스의 조건입니다.

연결과 스키마가 모델을 만들고 서비스가 문서를 다룬다 MongoDB 연결과 스키마가 모델을 만들고 HTTP 입력이 서비스를 통해 모델에 전달된다. 원문에는 HTTP 바디·ObjectId 사전 검증 파이프가 없고, 스키마 검증과 데이터베이스 인덱스는 별개다. CONFIG MongoDB 연결 URI BOOTSTRAP Mongoose connection RUNTIME CONTRACT Schema validators index metadata 별도 INJECTED TOKEN Model<User> 쿼리 · 생성 API HTTP BOUNDARY 검증 단계 추가 필요 USE CASE Nest service INSTANCE HydratedDocument <User> save · change tracking MONGODB collection + unique index unique는 validator가 아님 Model 정의 · HydratedDocument 인스턴스 · 실제 unique index를 구분합니다
스키마와 모델 등록 뒤 MongoDB에 쓰는 과정Schema는 필드 규칙과 인덱스 설정을 선언한다. forFeature에서 name으로 등록한 Model을 같은 이름의 InjectModel 토큰으로 서비스에 주입한다. 서비스는 Model로 검증과 DB 쓰기를 실행한다. required 검증 통과와 유일 인덱스의 중복 쓰기 거부는 별도 단계다.
Schema 선언필드 · 검증 · 인덱스
연결 관계Schema 선언 · 필드 · 검증 · 인덱스 → Model 등록 · forFeature의 name · InjectModel 같은 토큰
Model 등록forFeature의 nameInjectModel 같은 토큰
연결 관계Model 등록 · forFeature의 name · InjectModel 같은 토큰 → UsersService · 주입된 Model 호출
UsersService주입된 Model 호출
연결 관계UsersService · 주입된 Model 호출 → Mongoose Model · 검증 뒤 쿼리 실행
Mongoose Model검증 뒤 쿼리 실행
연결 관계Mongoose Model · 검증 뒤 쿼리 실행 → MongoDB · 문서 · 유일 인덱스
MongoDB문서 · 유일 인덱스
  1. 연결

    원문은 예제 URI와 mongo:latest를 사용합니다. 운영에서는 버전과 자격 증명을 별도로 관리해야 합니다.

  2. 스키마와 모델

    forFeature가 모델 이름과 스키마를 등록하고 InjectModel이 모델을 주입합니다. 스키마의 validator와 인덱스 메타데이터가 연결과 합쳐져 Model<User> 토큰이 됩니다.

  3. HTTP 검증

    원문은 바디 필드와 id를 직접 넘깁니다. 런타임 바디 검증과 ObjectId 오류 처리를 별도로 추가해야 합니다.

  4. 문서 실행

    모델 쿼리는 HydratedDocument<User>를 반환할 수 있으며 모델 shape와 문서 타입을 구분합니다.

  5. 인덱스 집행

    unique 선언은 validator가 아니라 MongoDB 인덱스이므로 실제 인덱스 빌드와 중복 키 오류를 관찰합니다.

같은 값의 두 문서는 로컬 validate를 모두 통과할 수 있다. unique는 MongoDB 인덱스가 쓰기 시점에 집행하며, 중복 키 오류를 도메인 충돌로 매핑하려면 별도 처리가 필요하다.

이 예의 조건

  • 두 박스는 같은 실행의 진행 정보와 자료·결과를 관찰하는 고정 역할입니다. 박스의 좌우·위아래 위치를 별도 호출 순서로 해석하지 않습니다.
  • 조건별 종료는 대안입니다. 실패 뒤 정상 후속 단계를 실행하거나 독립 비교 사례를 같은 요청으로 연결하지 않습니다.
  • MongoDB 연결과 스키마가 모델을 만들고 HTTP 입력이 서비스를 통해 모델에 전달된다. 원문에는 HTTP 바디·ObjectId 사전 검증 파이프가 없고, 스키마 검증과 데이터베이스 인덱스는 별개다.
  • Schema는 필드 규칙과 인덱스 설정을 선언한다. forFeature에서 name으로 등록한 Model을 같은 이름의 InjectModel 토큰으로 서비스에 주입한다. 서비스는 Model로 검증과 DB 쓰기를 실행한다. required 검증 통과와 유일 인덱스의 중복 쓰기 거부는 별도 단계다.
단계별 상태·값과 전환 이유
장면관찰 값전환 이유
모델 조립

Mongo 연결과 스키마에서 Model을 만듭니다.

입력: 연결·schema · 산출물: Model문서 접근 역할이 준비됩니다.
service 입력

HTTP 값을 service를 통해 Model에 전달합니다.

사전 ObjectId pipe: 현재 없음 · 입력: HTTP 값없는 사전 검증을 추가하지 않고 경계를 넘습니다.
문서 처리

Model이 문서를 다룹니다.

검증: schema · index: DB 별도 제약모델 검증과 저장소 제약을 구분합니다.

연결과 스키마가 모델을 만들고 서비스가 문서를 다룬다

연결/스키마에서 Model을 만든 뒤 HTTP 값이 service/model을 거쳐 문서로 이동하며 원문에 없는 사전 pipe를 추가하지 않는다.

Nest Mongoose · 모델과 문서

연결과 Schema로 Model을 등록하고, 서비스가 문서를 조회·저장합니다

forRoot는 연결 URI를, forFeature는 모델 이름과 Schema를 등록합니다. 본문의 inline body 타입은 HTTP 런타임 검증이 아니며, Mongoose의 unique 선언은 validator 대신 실제 MongoDB 인덱스의 조건입니다.

연결과 스키마가 모델을 만들고 서비스가 문서를 다룬다 MongoDB 연결과 스키마가 모델을 만들고 HTTP 입력이 서비스를 통해 모델에 전달된다. 원문에는 HTTP 바디·ObjectId 사전 검증 파이프가 없고, 스키마 검증과 데이터베이스 인덱스는 별개다. CONFIG MongoDB 연결 URI BOOTSTRAP Mongoose connection RUNTIME CONTRACT Schema validators index metadata 별도 INJECTED TOKEN Model<User> 쿼리 · 생성 API HTTP BOUNDARY 검증 단계 추가 필요 USE CASE Nest service INSTANCE HydratedDocument <User> save · change tracking MONGODB collection + unique index unique는 validator가 아님 Model 정의 · HydratedDocument 인스턴스 · 실제 unique index를 구분합니다
스키마와 모델 등록 뒤 MongoDB에 쓰는 과정Schema는 필드 규칙과 인덱스 설정을 선언한다. forFeature에서 name으로 등록한 Model을 같은 이름의 InjectModel 토큰으로 서비스에 주입한다. 서비스는 Model로 검증과 DB 쓰기를 실행한다. required 검증 통과와 유일 인덱스의 중복 쓰기 거부는 별도 단계다.
Schema 선언필드 · 검증 · 인덱스
연결 관계Schema 선언 · 필드 · 검증 · 인덱스 → Model 등록 · forFeature의 name · InjectModel 같은 토큰
Model 등록forFeature의 nameInjectModel 같은 토큰
연결 관계Model 등록 · forFeature의 name · InjectModel 같은 토큰 → UsersService · 주입된 Model 호출
UsersService주입된 Model 호출
연결 관계UsersService · 주입된 Model 호출 → Mongoose Model · 검증 뒤 쿼리 실행
Mongoose Model검증 뒤 쿼리 실행
연결 관계Mongoose Model · 검증 뒤 쿼리 실행 → MongoDB · 문서 · 유일 인덱스
MongoDB문서 · 유일 인덱스
  1. 연결

    원문은 예제 URI와 mongo:latest를 사용합니다. 운영에서는 버전과 자격 증명을 별도로 관리해야 합니다.

  2. 스키마와 모델

    forFeature가 모델 이름과 스키마를 등록하고 InjectModel이 모델을 주입합니다. 스키마의 validator와 인덱스 메타데이터가 연결과 합쳐져 Model<User> 토큰이 됩니다.

  3. HTTP 검증

    원문은 바디 필드와 id를 직접 넘깁니다. 런타임 바디 검증과 ObjectId 오류 처리를 별도로 추가해야 합니다.

  4. 문서 실행

    모델 쿼리는 HydratedDocument<User>를 반환할 수 있으며 모델 shape와 문서 타입을 구분합니다.

  5. 인덱스 집행

    unique 선언은 validator가 아니라 MongoDB 인덱스이므로 실제 인덱스 빌드와 중복 키 오류를 관찰합니다.

같은 값의 두 문서는 로컬 validate를 모두 통과할 수 있다. unique는 MongoDB 인덱스가 쓰기 시점에 집행하며, 중복 키 오류를 도메인 충돌로 매핑하려면 별도 처리가 필요하다.

이 예의 조건

  • 두 박스는 같은 실행의 진행 정보와 자료·결과를 관찰하는 고정 역할입니다. 박스의 좌우·위아래 위치를 별도 호출 순서로 해석하지 않습니다.
  • 조건별 종료는 대안입니다. 실패 뒤 정상 후속 단계를 실행하거나 독립 비교 사례를 같은 요청으로 연결하지 않습니다.
  • MongoDB 연결과 스키마가 모델을 만들고 HTTP 입력이 서비스를 통해 모델에 전달된다. 원문에는 HTTP 바디·ObjectId 사전 검증 파이프가 없고, 스키마 검증과 데이터베이스 인덱스는 별개다.
  • Schema는 필드 규칙과 인덱스 설정을 선언한다. forFeature에서 name으로 등록한 Model을 같은 이름의 InjectModel 토큰으로 서비스에 주입한다. 서비스는 Model로 검증과 DB 쓰기를 실행한다. required 검증 통과와 유일 인덱스의 중복 쓰기 거부는 별도 단계다.
단계별 상태·값과 전환 이유
장면관찰 값전환 이유
모델 조립

Mongo 연결과 스키마에서 Model을 만듭니다.

입력: 연결·schema · 산출물: Model문서 접근 역할이 준비됩니다.
service 입력

HTTP 값을 service를 통해 Model에 전달합니다.

사전 ObjectId pipe: 현재 없음 · 입력: HTTP 값없는 사전 검증을 추가하지 않고 경계를 넘습니다.
문서 처리

Model이 문서를 다룹니다.

검증: schema · index: DB 별도 제약모델 검증과 저장소 제약을 구분합니다.

MongoDB와 Mongoose란?

MongoDB는 데이터를 컬렉션(Collection)이라는 개념 안에 문서(Document) 형태로 저장하는 NoSQL 데이터베이스입니다.

각 문서는 필드-값 쌍으로 구성되며, JSON 객체와 유사한 구조를 가집니다.

관계형 데이터베이스의 테이블이 컬렉션에, 행(Row)이 문서에, 그리고 컬럼(Column)이 문서의 필드에 해당한다고 볼 수 있습니다.

Mongoose는 Node.js 환경에서 MongoDB를 더 쉽게 사용하도록 돕는 객체 데이터 모델링(ODM: Object Data Modeling) 라이브러리입니다.

TypeORM이 관계형 데이터베이스를 위한 ORM이라면, Mongoose는 MongoDB를 위한 ODM이라고 보면 됩니다.

Mongoose는 스키마 정의, 데이터 유효성 검사, 쿼리 빌더, 미들웨어 기능을 제공해 MongoDB 작업을 더 구조적이고 효율적으로 수행하게 해줍니다.

MongoDB를 선택한다는 것이 원자성을 포기한다는 뜻은 아닙니다. MongoDB는 한 문서의 쓰기를 원자적으로 처리하며, 여러 문서의 변경을 한 단위로 묶는 트랜잭션은 replica set 또는 sharded cluster 등 지원되는 구성에서 사용합니다. SQL과 NoSQL이라는 이름만으로 트랜잭션 유무를 판단하지 말고, 함께 바뀌어야 할 데이터와 실제 DB 구성을 먼저 확인하세요.

MongoDB와 Mongoose 사용의 주요 장점
  • 유연한 스키마: 데이터 구조가 고정적이지 않아 변화하는 요구사항에 빠르게 대응할 수 있습니다. (물론 Mongoose를 통해 스키마를 정의하여 구조를 강제할 수도 있습니다.)
  • 수평 확장성: 샤딩(Sharding)을 통해 대량의 데이터를 효율적으로 분산 저장하고 처리할 수 있습니다.
  • 개발 생산성: JSON 형태의 문서 사용은 프론트엔드와 백엔드 간 데이터 전달을 용이하게 하고, JavaScript 개발자에게 익숙한 데이터 형식을 제공합니다.
  • 풍부한 기능: Mongoose는 유효성 검사, 미들웨어(Pre/Post 훅), 쿼리 헬퍼 등 다양한 편의 기능을 제공합니다.

NestJS에서 MongoDB 연동하기: 핵심 개념

Mongoose MongoDB 연동은 schema 정의, model 주입, 쿼리 책임, validation/인덱스 기준으로 읽습니다.

NestJS에서 MongoDB를 연동할 때는 주로 다음과 같은 개념들을 사용합니다.

스키마 (Schema): Mongoose에서 스키마는 컬렉션에 저장될 문서의 구조와 데이터 타입, 유효성 규칙, 기본값 등을 정의합니다.

관계형 데이터베이스의 테이블 스키마와 유사한 역할을 하지만, NoSQL의 유연성을 유지하면서 데이터의 일관성을 확보하는 데 도움을 줍니다.

@Schema() 데코레이터를 사용하여 정의합니다.

예시
src/users/schemas/user.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';

export type UserDocument = HydratedDocument<User>; // Mongoose 문서 타입 정의

@Schema() // 이 클래스가 Mongoose 스키마임을 나타냅니다.
export class User {
  @Prop({ required: true, unique: true }) // 필수 필드, 유니크 제약 조건
  username: string;

  @Prop({ required: true })
  email: string;

  @Prop({ default: Date.now }) // 기본값 설정
  createdAt: Date;
}

export const UserSchema = SchemaFactory.createForClass(User); // 스키마 객체 생성

@Prop() 데코레이터를 사용하여 문서의 필드를 정의하고, 각 필드의 타입, 필수 여부, 유니크 제약 조건, 기본값 등을 설정할 수 있습니다.

여기서 required는 Mongoose의 검증 규칙이지만, unique: true는 검증기가 아니라 MongoDB의 유일 인덱스를 만드는 설정입니다. 인덱스가 실제로 만들어진 상태에서 같은 값을 저장하면 DB의 duplicate-key 오류가 발생합니다. 이를 Mongoose ValidationError와 같은 오류로 처리해서는 안 됩니다. 테스트에서 중복을 검사할 때도 인덱스 준비가 끝났는지 확인해야 합니다. Mongoose 검증 문서는 이 차이를 별도로 설명합니다.

모델 (Model): 모델은 특정 스키마에 정의된 컬렉션에 대한 인터페이스 역할을 합니다.

모델을 통해 데이터베이스에 쿼리를 실행하거나 새 문서를 생성할 수 있습니다.

TypeORM의 리포지토리와 유사하게, 실제 데이터베이스 작업을 수행하는 주체라고 할 수 있습니다.

NestJS에서는 @InjectModel() 데코레이터를 사용하여 모델을 주입받습니다.

예시
src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './schemas/user.schema'; // 스키마 및 문서 타입 임포트

@Injectable()
export class UsersService {
  constructor(
    @InjectModel(User.name) private userModel: Model<UserDocument>, // User 모델 주입
  ) {}

  async create(username: string, email: string): Promise<User> {
    const createdUser = new this.userModel({ username, email });
    return createdUser.save(); // 새 문서 생성 및 저장
  }

  async findAll(): Promise<User[]> {
    return this.userModel.find().exec(); // 모든 사용자 조회
  }

  async findOne(id: string): Promise<User | null> {
    return this.userModel.findById(id).exec(); // ID로 사용자 한 명 조회
  }

  async delete(id: string): Promise<any> {
    return this.userModel.deleteOne({ _id: id }).exec(); // ID로 사용자 삭제
  }
}

InjectModel(User.name)에서 User.name을 사용하는 이유는 Mongoose가 모델을 등록할 때 스키마 클래스의 이름을 사용하기 때문입니다.


NestJS와 MongoDB 연동 설정

NestJS 애플리케이션에 MongoDB를 통합하는 기본적인 단계는 다음과 같습니다.

필요한 패키지 설치: MongoDB 드라이버와 NestJS의 Mongoose 통합 모듈을 설치합니다.

npm install @nestjs/mongoose mongoose

MongoDB 서비스 실행: 로컬에 MongoDB가 설치되어 있지 않다면 Docker를 사용하거나 MongoDB Atlas와 같은 클라우드 서비스를 이용하는 것이 편리합니다.

로컬에서 MongoDB를 실행하는 가장 간단한 방법 중 하나는 Docker Compose를 사용하는 것입니다.

docker-compose.yml 예시
version: '3.8'
services:
  mongodb:
    image: mongo:latest
    container_name: nestjs-mongo
    ports:
      - "27017:27017"
    volumes:
      - mongo-data:/data/db # 데이터 영속성을 위해 볼륨 마운트
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: example

volumes:
  mongo-data:

docker-compose up -d 명령어로 MongoDB 컨테이너를 실행할 수 있습니다.

MongooseModule 설정: 루트 모듈(AppModule)의 imports 배열에 MongooseModule.forRoot()를 사용하여 MongoDB 연결 정보를 설정합니다.

그리고 특정 모듈(UsersModule)에서 사용할 스키마를 MongooseModule.forFeature()를 통해 등록합니다.

src/app.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose'; // Mongoose 모듈 임포트
import { UsersModule } from './users/users.module'; // 사용자 모듈 임포트

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://root:example@localhost:27017/nest_mongo_db?authSource=admin'), // MongoDB 연결 URI
    UsersModule, // 사용자 모듈
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

주의: mongodb://username:password@host:port/database_name?authSource=admin 형식으로 연결 URI를 작성합니다.

authSource=admin은 인증 데이터베이스를 지정하는 것으로, Docker 환경에서 루트 사용자 인증을 위해 주로 사용됩니다.

실제 운영 환경에서는 보안에 유의하여 자격 증명을 관리해야 합니다.

피처(Feature) 모듈에 스키마 등록: 각 도메인(예: users)에 해당하는 모듈에서는 MongooseModule.forFeature()를 사용하여 해당 모듈에서 사용할 스키마와 모델을 등록합니다.

src/users/users.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { User, UserSchema } from './schemas/user.schema'; // 스키마 임포트

@Module({
  imports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), // User 모델 등록
  ],
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService], // 다른 모듈에서 UsersService를 사용하려면 export
})
export class UsersModule {}

forFeature()는 현재 모듈에서 사용할 컬렉션과 그에 해당하는 스키마를 정의합니다.

Mongoose를 Nest 모듈에 붙일 때는 스키마 정의, 모듈 등록, 모델 주입이 같은 컬렉션과 스키마를 가리키는지 먼저 확인해야 합니다.


실제 데이터 작업 예시 (간략)

이제 MongoDB와 연동된 서비스를 사용하여 컨트롤러에서 데이터를 처리하는 간단한 예를 보겠습니다.

src/users/users.controller.ts
import { Controller, Get, Post, Body, Param, Delete } from '@nestjs/common';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  async create(@Body() createUserDto: { username: string; email: string }) {
    return this.usersService.create(createUserDto.username, createUserDto.email);
  }

  @Get()
  async findAll() {
    return this.usersService.findAll();
  }

  @Get(':id')
  async findOne(@Param('id') id: string) {
    return this.usersService.findOne(id);
  }

  @Delete(':id')
  async delete(@Param('id') id: string) {
    return this.usersService.delete(id);
  }
}

NestJS는 @nestjs/mongoose 패키지를 통해 Mongoose를 통합하고, TypeScript의 타입 안전성과 MongoDB의 유연성을 함께 활용할 수 있게 합니다.

생성한 ID로 같은 문서를 확인하기

DB 연결과 위 모듈 등록이 끝난 뒤 POST /users에 {"username":"Alice","email":"[email protected]"}를 보내고 응답의 _id를 기록합니다. GET /users/<기록한 ID>의 이름과 이메일이 같은지 확인한 뒤 삭제 요청을 보내세요. _id와 생성 시각은 실행마다 달라지므로 교재의 고정값을 찾는 방식으로 확인하지 않습니다.

위 컨트롤러의 본문 타입 표기는 런타임 DTO 검증을 실행하지 않습니다. 또한 findOne()이 없는 문서에 null을 반환하는 것과 HTTP 404를 응답하는 것은 별개입니다. 잘못된 ObjectId 형식의 변환 오류, 유효한 ID지만 문서가 없는 경우, 삭제 결과의 deletedCount를 각각 확인해 API 정책을 정해야 합니다. 현재 발췌가 그 오류 변환까지 구현했다고 생각하지 마세요.

검증과 인덱스를 구분하는 연습

위 스키마의 username 유일 인덱스가 준비된 DB에서, 필수 이름과 이메일이 모두 있는 문서 두 개를 같은 username: 'Alice'로 차례대로 저장합니다. required 검증이 둘 다 통과하면 두 문서가 모두 저장될까요? 실패를 HTTP 409로 전달하려면 어느 경계를 추가로 구현해야 할까요?

검증 통과 뒤에도 실패하는 이유

필수 값이 있다는 검증과 값의 유일성은 다른 조건입니다. 첫 문서가 저장된 뒤 두 번째 쓰기는 유일 인덱스에 걸려 duplicate-key 오류로 실패합니다. 서비스나 예외 필터가 해당 DB 오류를 식별하고 공개할 HTTP 오류로 변환해야 하며, unique: true나 TypeScript 타입 표기만으로 409 응답이 만들어지지는 않습니다.


MongoDB는 비정형 데이터가 많거나 스키마 변경이 잦은 서비스에서 검토할 만한 선택지입니다.

NestJS와 함께 사용할 때는 스키마 정의, 인덱스, 검증 위치를 명확히 정해 두는 것이 중요합니다.

컨트롤러에서 MongoDB 컬렉션까지 요청이 이동하는 흐름은 앞의 다이어그램과 연결해 확인할 수 있습니다.