본문 바로가기

Mongo

Mongoose 편의 기능 정리

아래에서 사용할 Tour 스키마 예시

const tourSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: [true, 'A tour must have a name'],
      unique: true,
      trim: true,
      maxlength: [40, 'A tour name must have less or equal then 40 characters'],
      minlength: [10, 'A tour name must have more or equal then 10 characters'],
    },
    slug: String,
    duration: {
      type: Number,
      required: [true, 'A tour must have a duration'],
    },
    maxGroupSize: {
      type: Number,
      required: [true, 'A tour must have a group size'],
    },
    difficulty: {
      type: String,
      required: [true, 'A tour must have a difficulty'],
      enum: {
        values: ['easy', 'medium', 'difficult'],
        message: 'Difficulty is either: easy, medium, difficult',
      },
    },
    ratingsAverage: {
      type: Number,
      default: 4.5,
      min: [1, 'Rating must be above 1.0'],
      max: [5, 'Rating must be below 5.0'],
    },
    ratingsQuantity: {
      type: Number,
      default: 0,
    },
    price: {
      type: Number,
      required: [true, 'A tour must have a price'],
    },
    priceDiscount: {
      type: Number,
      validate: {
        validator: function (val) {
          // this only points to current doc on NEW document creation
          return val < this.price;
        },
        message: 'Discount price ({VALUE}) should be below regular price',
      },
    },
    summary: {
      type: String,
      trim: true,
      required: [true, 'A tour must have a description'],
    },
    description: {
      type: String,
      trim: true,
    },
    imageCover: {
      type: String,
      required: [true, 'A tour must have a cover image'],
    },
    images: [String],
    createdAt: {
      type: Date,
      default: Date.now(),
      select: false,
    },
    startDates: [Date],
    secretTour: {
      type: Boolean,
      default: false,
    },
  },
  {
    toJSON: { virtuals: true },
    toObject: { virtuals: true },
  }
);

1. virtual

  • 스키마를 선언 할 때 타입을 고정으로 할 수 도 있지만, virtual을 이용하면 스키마에 선언되어 있지 않은 가상 필드를 만들어 준다.

    tourSchema.virtual('durationWeek').get(function() {
      return this.duration / 7
    })
  • 여기에서 화살표 함수를 사용하지 않고, function 키워드를 사용한 이유는 this 를 접근하기 위함이다.

  • this 를 통해 tour 모델 인스턴스에 접근 할 수 있다.

    {
      ...
      durationWeek: 1
    }

2. methos

  • 인스턴스에서 접근할 수 있는 메소드를 선언 할 수 있다.

  • 코드 재활용면에서 굉장히 효과적이다.

  • 가격이 N원 이상인 여행일 경우 예외처리를 한다면...

    tourSchema.methods.checkPrice = function(price, cb) {
      if (this.price > price) {
          return cb('요청한 가격보다 높게 책정되어 있습니다.')
      }
      cb(null, true)
    }
    tour.checkPrice(30000, function(err, result) {
      if (err) {
        throw err
      }
      // ...do something with result
    })

3. pre / post

  • 특정 동작 이전, 이후에 어떤 행동을 취할 지 정의 할 수 있습니다.

  • pre는 미들웨어 같은 느낌으로 생각하면 됩니다.

    tourSchema.pre('save', function(next) {
      // 가격이 30000원이 넘으면 저장하지 않기
      if (this.price > 30000) {
        throw '30000원이 넘습니다.'
      }
      next()
    })
    
    tourSchema.post('save', function(doc, next) {
      console.log('저장 완료')
      next()
    })