개인공부/TIL(Today I Learned)

TIL 93일차_Mongoose 사용하기

soon327 2021. 4. 21. 22:26

마지막 H.A도 끝났겠다,
이제 2주 프로젝트 준비를 시작해야한다.. 비!장!

아마 2주 프로젝트에서는 혼자 백단을 맡게될 것 같으니,
미리미리 준비를 많이 해둬야할 것 같다.
오늘은 몽구스의 사용법에대해 조금 정리해보려고한다.
이외에도 할게 많다.. schema나 api등 미리 생각해놔야할 것도 많고 잡다한 tool도 공부해야하고 .. 느아아아아😱

What is mongoose ?

mongoose는 MongoDB의 ODM 중 하나이다.
ODM은 Object Document Mapping, 즉 문서를 DB에서 조회할 대 자바스크립트 객체로 바꿔주는 역할을 한다.

mongoose의 장점으로는 강제 스키마의 부활, populate, 프로미스와 콜백 사용가능, 편리한 쿼리 빌더 등을 꼽을 수 있다.
'뭐?? nosql은 테이블과 join이 없는 DB아니야?'
라고 할 수 있지만, 몽구스는 오히려 그 기능을 부활시켰다.
schema를 통해 DB에 다큐먼트를 넣을 때 값과 타입, 그리고 필드를 검사하며,
populate를 통해 SQL의 join과 비슷한 기능을 수행한다.

이럴거면 왜 nosql을 쓰냐고 할 수 있지만,
sql의 장점을 유지하면서, 필요한 nosql의 기능들을 추가했다고 생각하면 된다.

Schema

스키마는 sql의 테이블과 비슷한 역할을 한다. 기본값을 설정해주기도하고 인덱스를 넣을 수도 있다.
스키마를 만들어보자. 보통 한 파일에 하나의 스키마를 작성한다.

const mongoose = require('mongoose');


const userSchema = mongoose.Schema({
  email: { type: String, required: true, unique: true, lowercase: true, maxlength: 30 },
  password: { type: String, required: true, minlength:8, trim: true },
  nickname: String,
  birth: { type: Date, default: Date.now },
  point: { type: Number, default: 0, max: 50, index: true },
  image: { width: Number, height: Number },
  likes: [String],
  any: [mongoose.Schema.Types.Mixed ], //배열안에 아무거나 넣어도 되는 필드
  id: mongoose.Schema.Types.ObjectId, // Objectid를 넣을 수 있는 필드
});
userSchema.index({ email: 1, nickname: 1 }); // 이렇게 스키마에 직접 필드를 추가할 수도 있다.

//mongoose.model()을 호출할 때, 스키마가 등록된다.
const User = mongoose.model('User', userSchema); 
module.exports = {User}

mongoose.model에서 첫번째 인자가 컬레션 이름이 된다.
User이면 소문자화 후, 복수형으로 바뀌어서 users컬렉션이 된다.
이런 강제 개명이 싫다면 세번째 인자로 컬렉션 이름을 줄 수 있다.
mongoose.model('User', userSchema, 'user')

위와 같이 스키마를 만든후에, controller에서 require하여 사용하면 된다.

const mongoose = require('mongoose');
const { User } = require('./models/User');

pre, post 메소드

스키마에 붙여서 사용하는 메소드이며,
각각 특정 동작 이전, 이후에 어떤 행동을 취할 지를 정의할 수 있다.

userSchema.pre('save', function(next) {
  if (!this.email) { // email 필드가 없으면 에러 표시 후 저장 취소
    throw '이메일이 없습니다';
  }
  if (!this.createdAt) { // createdAt 필드가 없으면 추가
    this.createdAt = new Date();
  }
  next();
});
userSchema.post('find', function(result) {
  console.log('저장 완료', result);
});

위의 것은 save하기 전에 호출된다.
next를 실행하지 않으면 save가 되지 않기 때문에 다큐먼트 저장 전 최종 검증으로 쓸 수 있다.
아래 것은 find를 호출한 다음에 실행된다.
보통 pre메소드를 많이쓴다.

이외에 사용자 정의 메소드나 다른메소드 들은
다음글에서 정리해야겠다!


Reference

zerocho