몽구스란?

몽구스를 알아보고 간단한 CURD 예제를 만들어보겠다. 몽구스는 네이티브 드라이버인 몽고DB 보다 조금 더 편리한 기능을 제공하는 라이브러리이다. 대표적으로 객체를 도큐먼트로 매핑하는 기능이 있다. 몽고DB 자체에는 스키마를 지정하는 기능이 없지만, 몽구스를 사용하면 스키마를 지정할 수 있다. 스키마가 있으니 필드 타입 지정 및 유효성 검증 등을 추가로 편하게 할 수 있다.

순서 1. 몽구스 설치하기

npm i mongoose

순서 2. 몽구스로 스키마 만들기

아래 코드는 스키마와 모델을 생성한 코드이다. 스키마는 몽고디비의 컬렉션과 매핑된다.

let mongoose = require('mongoose');
let Schema = mongoose.Schema;

const personSchema = new Schema({ // 1. 스키마 객체 생성
    name: String,
    age: Number,
    email: { type: String, required: true },
});

module.exports = mongoose.model('Person', personSchema); // 2. 모델 객체 생성

1번. 스키마 객체를 생성한다. 스키마를 생성할 때 선언 가능한 타입은 아래와 같다.

타입 설명과 예시 코드
String 속성을 문자열로 선언
const schema = new Schema({ name: String })
Number 속성을 숫자로 선언
const schema = new Schema({ age: Number })
Date 속성을 날짜 타입으로 선언. 자바스크립트 기본 Date 메서드는 값을 변경 시에 몽구스에서 변경 사항을 추적하지 않으므로 몽구스에 변경 사항을 명시적으로 알려주어야 함
Buffer 속성을 버퍼로 선언
const binData = new Schema({ binData: Buffer })
Boolean 속성을 부울로 선언
const test = new Schema({ b: Boolean })
Mixed Mixed는 무엇이든 가능한 타입
const Any = new Schema({ any: { } })
ObjectId ObjectId는 몽고디비에서 고유한 식별자로 사용되는 값
const keySchema = new Schema({ key: mongoose.ObjectId });
Array 배열은 [ ] 기호를 사용해 선언
const names = new Schema({ names: [String] })
다른 문서를 배열의 값으로 사용
const address = new Schema({ addr: String });
const addresses = new Schema( addrs: [address] );
Decimal128 128비트 10진수 부동소수점을 사용 시에 선언
const f = new Schema({ f: Decimal128 })
Map 자바스크립트의 Map의 하위 클래스인 MongooseMap 타입으로 선언
const site = new Schema({
url: {
type: Map,
of: String
}
});
Shcema 특정 스키마 타입으로 타입을 선언
const subSchema = new Schema({
// 스키마 선언
});

const schema = new Schema({
data: {
type: subSchema,
default: { }
}
});

2번. 타입 외에 부가적인 속성(필수 여부)을 추가할 수 있다.

속성 타입 설명과 예시 코드
required boolean 또는 function 해당 속성이 필수인지 여부
email: { type: String, required: true }
default Any 또는 function 기본값 설정. 함수인 경우 함수의 반환값
email: { type: String, default: ‘no email’ }
select boolean 쿼리 수행 시 기본적으로 선택되는 값인지 여부
email: { type: String, select: true }
validate function 유효성 검증 함수 추가 기능
email: { type: String, validate: () => {
return this.email.indexOf(‘@’) > 0; } }
get function 커스텀 get 함수 설정
name: { type: String, get: v => v.toLowerCase() }
set function 커스텀 set 함수 설정
name: { type: String, get: v => v.toLowerCase(),
set: v => v.toUpperCase() }
alias String 속성으로 주어진 이름이 아닌 별칭 사용 시 사용
name: { type: String, alias: ‘n’ }
immutable boolean true로 설정 시 값을 변경할 수 없음
age: { type: Number, immutable: true }
transform function Document#toJSON()를 호출하면 transform에 지정된 함수 실행. JSON.stringfy() 시에도 실행
name: { type: String, transform: (v) => v.toLowerCase() }
index boolean 해당 속성에 인덱스를 정의할지 여부
name: { type: String, index: true }
unique boolean 해당 속성에 유니크 인덱스를 정의할지 여부
name: { type: String, unique: true }
sparse boolean 해당 속성에 희소 인덱스를 정의할지 여부
name: { type: String, sparse: true }

★ 순서 3. 몽구스와 익스프레스로 CRUD API 만들기

아래 코드는 위에서 생성한 스키마로 CRUD를 테스트하기 위해, 익스프레스로 API를 만든다.

const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
// 스키마 임포트
const Person = require("./person-model");

mongoose.set("strictQuery", false); // 1. 설정해줘야 경고가 뜨지 않음

const app = express();
app.use(bodyParser.json()); // 2. HTTP에서 Body를 파싱하기 위한 설정
app.listen(3000, async () => {
    console.log("Server started");
    const mongodbURL
        = "mongodb+srv://<userName>:<password>@cluster0.vbpuhau.mongodb.net/?retryWrites=true&w=majority";

    // 3. 몽고 디비에 커넥션 하기
    mongoose
        .connect(mongodbURL, { useNewUrlParser: true })
        .then(console.log("Connected to MongoDB"));
});

// 4. 모든 person 데이터 출력
app.get("/person", async (req, res) => {
    const person = await Person.find({});
    res.send(person);
})

// 5. 특정 이메일로 person 찾기
app.get("/person/:email", async (req, res) => {
    const person = await Person.findOne({ email: req.params.email });
    res.send(person);
})

// 6. person 데이터 추가하기
app.post("/person", async (req, res) => {
    const person = new Person(req.body);
    await person.save();
    res.send(person);
})

// 7. person 데이터 수정하기
app.put("/person/:email", async (req, res) => {
    const person = await Person.findOneAndUpdate(
        { email: req.params.email },
        { $set: req.body },
        { new: true }
    );
    console.log(person);
    res.send(person);
})

// 8. person 데이터 삭제하기
app.delete("/person/:email", async (req, res) => {
    await Person.deleteMany({ email: req.params.email });
    res.send({ success: true });
})

1번. (교재에 있는 설명 그대로 작성하겠음) 몽구스에서 쿼리에 필터를 빈 객체인 { }로 넣으면 모든 값을 불러오게 되어서 문제가 되는 경우가 있다. 이 경우 에러를 내도록 하는 설정이 strictQuery 설정이다. 명시적으로 설정해주지 않으면 서버 기동 시 경고가 발생하므로 예제용 코드이기에 false로 설정.

2번. bodyParser.json() 미들웨어를 추가해야만 HTTP에서 Body를 파싱할 수 있다.

3번. mongoose에서 몽고DB와 커넥션을 맺을 때 connect(uri, option)함수를 사용한다. useNewUrlParser는 생략해도 상관없다.

4번. Postman 에서 호출했을 때,

image-20230818134541856

5번. Postman 에서 찾는 회원 정보가 없을 때, 클라이언트에 알리는 코드를 추가했다.

app.get("/person/:email", async (req, res) => {
    const person = await Person.findOne({ email: req.params.email });

    if (!person) {
        return res.send("찾으시는 회원 정보가 없습니다.");
    }

    res.send(person);
})

image-20230818135004581

6번. Postman 에서 회원 정보를 추가했을 때,

image-20230818135102333

7번. Postman 에서 이메일을 키로하여 회원 정보를 수정할 때,

image-20230818135243492

※ 문서 수정 시 하나만 수정하는 경우 findOneAndUpdate()를 사용하거나 updateOne()을 사용할 수 있다. 아래는 updateOne()을 사용한 예시코드이다.

Person.updateOne({ email: req.params.email },
	{ $set: req.body})

8번. Postman 에서 이메일을 키로하여 회원 정보를 삭제할 때,

image-20230818135556779

정리

몽구스는 Node.js 애플리케이션에서 몽고 DB를 쉽게 사용할 수 있게 하는 라이브러리이다. 편의 기능(스키마, 유효성 검증 등)이 추가되었다.

  • 스키마: 데이터 타입을 정의할 수 있음
  • 유효성 검증: 필수값 여부를 추가할 수 있음

몽고 DB에 몽구스를 결합하여 사용하는 방식은 필수인 것 같다. 그리고 REST API를 작성할 때에는 ‘★ 순서 3. 몽구스와 익스프레스로 CRUD API 만들기’코드를 반드시 참고하도록 하자.

참고

다음에 다루게 될 것

  • NestJS 시작하기

댓글남기기