Node.js 백엔드 스터디(8) - 몽구스를 사용해 CRUD 만들기
몽구스란?
몽구스를 알아보고 간단한 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 에서 호출했을 때,
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);
})
6번. Postman 에서 회원 정보를 추가했을 때,
7번. Postman 에서 이메일을 키로하여 회원 정보를 수정할 때,
※ 문서 수정 시 하나만 수정하는 경우 findOneAndUpdate()를 사용하거나 updateOne()을 사용할 수 있다. 아래는 updateOne()을 사용한 예시코드이다.
Person.updateOne({ email: req.params.email },
{ $set: req.body})
8번. Postman 에서 이메일을 키로하여 회원 정보를 삭제할 때,
정리
몽구스는 Node.js 애플리케이션에서 몽고 DB를 쉽게 사용할 수 있게 하는 라이브러리이다. 편의 기능(스키마, 유효성 검증 등)이 추가되었다.
- 스키마: 데이터 타입을 정의할 수 있음
- 유효성 검증: 필수값 여부를 추가할 수 있음
몽고 DB에 몽구스를 결합하여 사용하는 방식은 필수인 것 같다. 그리고 REST API를 작성할 때에는 ‘★ 순서 3. 몽구스와 익스프레스로 CRUD API 만들기’코드를 반드시 참고하도록 하자.
참고
다음에 다루게 될 것
- NestJS 시작하기
댓글남기기