[NodeJS] 몽구스(Mongoose) 사용하여 CRUD 해보기
MySQL에 Sequelize가 있다면 몽고디비에는 Mongoose가 있다. 몽구스는 시퀄라이즈와 달리 ODM(Object Document Mapping)이라고 불린다.
몽고디비 자체가 이미 자바스크립트인데도 굳이 자바스크립트 객체와 매핑하는 이유는 몽고디비에 없어서 불편한 기능들을 몽구스가 보완해주기 때문이다. 먼저 스키마(Schema)라는 것이 생겼다. 몽고디비는 테이블이 없어서 자유롭게 데이터를 넣을 수 있지만, 형식이 자유롭기 때문에 때로는 불편함을 초래한다. 몽구스는 몽고디비에 데이터를 넣기 전에 노드 서버 단에서 데이터를 한 번 필터링 하는 역할을 한다.
프로젝트 생성 및 모듈 설치
express 프로젝트이름
ex) express NodeJS_MongoDB
cd NodeJS_MongoDB
npm install
npm install mongoose
위의 명령어를 차례대로 터미널에서 실행을 하자.
그러면 위와 같은 프로젝트 구조를 볼 수 있을 것이다. 그리고 몽고디비를 사용하기 위해서 schemas 패키지를 하나 만들어서 아래에 index.js users.js, comment.js를 만들어 넣자(유저, 댓글 API를 만들 예정이다)
몽고디비 연결하기
Schemas/index.js
const mongoose = require('mongoose');
const connect = () => {
if (process.env.NODE_ENV !== 'production') {
mongoose.set('debug', true);
}
mongoose.connect('mongodb://root:root@localhost:27017/admin', {
dbName: 'mongo',
useNewUrlParser: true,
userCreateIndex: true,
}, (error) => {
if (error) {
console.log('몽고디비 연결 에러', error);
} else {
console.log('몽고디비 연결 성공');
}
});
}
mongoose.connection.on('error', (error) => {
console.error('몽고디비 연결 에러', error);
});
mongoose.connection.on('disconnected', () => {
console.error('몽고디비 연결이 끊겼습니다. 연결을 재시도 합니다');
connect();
});
module.exports = connect;
전체코드는 위와 같다. 위의 코드는 몽고디비를 연결하는 과정인데 신경 써서 봐야 할 부분은 아래와 같다.
mongoose.connect('mongodb://이름:비밀번호@localhost:27017/admin', {
dbName: '데이터베이스이름',
useNewUrlParser: true,
userCreateIndex: true,
}
위와 같이 몽고디비에 연결하기 위해서는 본인이 설정해두었던 이름, 비밀번호를 넣어주어야 하고, dbName에는 원하는 데이터베이스의 이름을 적어주면 된다. (필자의 경우는 dbName: mongoDB, 이름: root, 비밀번호: root로 했다) 어떤 말인지 이해가 안된다면 아래 사진을 보면서 이해해보자.
MongoDB Compass를 키면 아래와 같은 화면을 볼 수 있다.
위의 Fill in connection fileds individulally를 클릭하자.
그리고 위의 UserName, password, Database가 위에서 말한 이름, 비밀번호, 데이터베이스이름이다. 이것을 index.js 코드에서 입력해주어야 한다.
스키마 정의하기
Schemas/users.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
/**
* 이름, 나이, 결혼여부, 자기소개, 생성일
*/
const userSchema = new Schema({
name: {
type: String, // 자료형
required: true, // 필수 여부
unique: true, // 고유 값
default: true,
},
age: {
type: Number,
required: true,
},
married: {
type: Boolean,
required: true
},
comment: {
type: String
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('User', userSchema);
필자는 users에는 이름, 나이, 결혼여부, 자기소개, 생성일을 담을 것이다. 위와 같이 Schema를 만들어서 자료형, 필수값 등등을 설정해주면 된다.
- type: 자료형
- required: 필수 여부
- unique: 고유 값
Schemas/comment.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
/**
* 작성자, 댓글내용, 생성일
*/
const { Types: ObjectId } = Schema;
const commentSchema = new Schema({
commenter: {
type: ObjectId,
required: true,
ref: 'User' // User Schema의 아이디
},
comment: {
type: String,
requried: true,
},
createdAt: {
type: Date,
default: Date.now,
}
})
module.exports = mongoose.model('Comment', commentSchema);
그리고 이번에는 comment에 작성자, 댓글내용, 생성일을 가지고 스키마를 만들었다. 여기서 봐야할 점은 유저 - 댓글의 관계는 일대다이고 commenter는 외래키라는 것이다. 그리고 몽고디비는 관계디비와는 다르게 ObjectId로 구분을 하기 때문에 User Schema의 ObjectId를 commenter에 넣는 것이다.
app.js
그리고 제일 핵심이라고 할 수 있는 app.js에 위와 같이 코드를 작성해서 스키마를 연결 시키면 된다.
router를 이용해 API 만들기
routes/index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.use('/users', require('./users'));
router.use('/comment', require('./comment'));
module.exports = router;
위와 같이 index.js에서 routes로 사용하기 위해 users와 comment를 연결해주자.
routes/users.js
const express = require('express');
const router = express.Router();
const User = require('../schemas/users');
// 사용자 전체 조회
router.get('/', (req, res, next) => {
User.find()
.then((users) => {
res.json(users);
})
.catch((err) => {
console.error(err);
next(err);
})
});
// 유저 생성
router.post('/', (req, res, next) => {
const user = new User({
name: req.body.name,
age: req.body.age,
married: req.body.married
})
user.save()
.then((result) => {
res.json(result);
})
.catch((err) => {
console.error(err);
next(err);
})
})
module.exports = router;
그리고 유저전체조회, 유저생성하는 API를 만드는 코드를 작성하였다.
- find() : 유저 전체조회
- new 스키마(data).save() : 생성
- findOne() : 유저 한명 조회
위의 메소드를 실행하고 나서의 반환형은 Promise이기 때문에 then, catch를 사용할 수 있다.
routes/comment.js
const express = require('express');
const router = express.Router();
const Comment = require('../schemas/comment');
// 사용자의 댓글 전체 조회
router.get('/:id', (req, res, next) => {
Comment.find({ commenter: req.params.id })
.then((users) => {
res.json(users);
})
.catch((err) => {
console.error(err);
next(err);
})
});
// 댓글 생성
router.post('/', (req, res, next) => {
const post = new Comment({
commenter: req.body.id,
comment: req.body.comment,
})
post.save()
.then((result) => {
res.json(result);
})
.catch((err) => {
console.error(err);
next(err);
})
});
// 댓글 수정
router.patch('/:id', (req, res, next) => {
// id의 댓글을 수정해라
Comment.update({ id: req.params.id }, { comment: req.body.comment })
.then((result) => {
res.json(result);
})
.catch((err) => {
console.error(err);
next(err);
})
});
// 댓글 삭제
router.delete(':/id', (req, res, next) => {
Comment.remove({ id: req.params.id })
.then((result) => {
res.json(result);
})
.catch((err) => {
console.error(err);
next(err);
})
})
module.exports = router;
API는 한명의 사용자가 쓴 댓글 전체조회, 댓글 수정, 삭제, 생성을 만들었다.
- update() : 갱신
- remove : 삭제
사용자의 전체 댓글 조회 API를 보면 params로 사용자의 아이디(commenter)를 받아와서 그 사용자가 썼던 댓글들을 전체조회하라는 의미이다.
PostMan을 이용해서 테스트
유저생성
그리고 POST 방식으로 Request Body에 유저 정보를 넣고 보내보면 200으로 제대로 응답이 오는 것을 확인할 수 있다. MongoDB Compass에서도 확인을 해보자.
그러면 아래와 같이 자신이 설정했던 데이터베이스 이름이 만들어진 것을 확인할 수 있다(필자는 mongo라고 했다.)
PostMan에서 입력했던 값으로 유저가 생성이 된 것을 확인할 수 있다.
댓글 생성
그리고 나서 사용자의 전체 댓글을 조회하는 API를 이용해서 PostMan으로 테스트해도 되지만 필자는 아래와 같이 MongDB Compass에서 제대로 데이터가 들어갔는지 확인을 해보았다.
아래와 같이 포스트맨에서 입력했던 값들이 제대로 들어간 것을 확인할 수 있다.