[Node.js] Database - MongoDB
- 이전글 [Node.js] Express - Router의 코드와 이어집니다.
SQL vs NoSQL
- 흔히 사용되는 Database는 크게 SQL과 NoSQL 두 가지 타입으로 구분한다.
- 우리가 어떤 프로젝트를 진행하고 서비스를 만들든, 어떤 DB를 사용해야하는지는 많은 고민을 하게 만든다.
- 이 두 가지는 반대되는 개념이라기보다는, '다른' 개념이라고 이해하는 것이 좋을 것 같다.
- 각각의 특징을 살펴보고, 어떤 상황에 어떤 DB를 사용해야할 지를 고려하면 될 것 같다.
(1) SQL
- Structured Query Language의 약자
- 데이터가 고정된 열과 행을 가지고 있는 테이블에 저장될 경우, 흔히 SQL 방식이라고 부른다.
- 관계형 데이터베이스(RDB : Relational DataBase)라고 부르기도 한다.
- 대표적으로는 MySQL, Oracle, MsSQL 등이 있다.
- '스키마' 라고 불리는 데이터 테이블의 형태로 관리한다.
- 각 테이블이 담고있는 정보가 비교적 명확한 편이기 때문에, 관리가 용이하고 이해가 쉬운 편이다.
(2) NoSQL
- 관계형 데이터베이스만을 쓰지 않는 방식을 이야기한다.
- 주로 비관계형 데이터베이스라고 하지만, 관계형 데이터베이스 시스템의 방식을 전혀 쓰지 못하는건 아니다.
- SQL의 '스키마' 처럼 정해진 형태가 있는게 아니기 때문에, 데이터를 유동적으로 변경하고 관리할 수 있다.
- 하지만 이 때문에 데이터가 복잡해질 수도 있고, SQL에 비해 데이터베이스에 대한 이해가 어려워질 수 있다.
- 서비스를 유동적으로 변경해야하는 스타트업에서 이 방식을 주로 선호한다.
- 대표적으로는 MongoDB, Hadoop 이 있다.
- 데이터가 주로 Json 형태 {'key' : 'value'} 로 이루어져있다.
MongoDB
- MonboDB는 대표적인 NoSQL 중 하나이다.
- 간단한 프로젝트를 통해, MongoDB의 사용법을 익혀본다.
- MongoDB를 사용하기 위해, MongoDB, Robo3T를 설치하고 Mongoose 라이브러리를 사용할 예정이다.
(1) MongoDB 설치 (Mac)
- 우선, Terminal을 실행한 후, 아래 명령어를 통해 MongoDB를 설치한다.
// 커스텀 홈브루 탭 세팅
brew tap mongodb/brew
// MongoDB 설치
brew install mongodb-community
// MongoDB 실행
brew services start mongodb-community
- 인터넷 브라우저를 켜고 http://localhost:27017 주소로 접속했을 때 아래와 같은 화면이 보인다면 정상적으로 설치와 실행이 완료된 것이다.
- MonboDB는 대표적인 NoSQL 중 하나이다.
- 간단한 프로젝트를 통해, MongoDB의 사용법을 익혀본다.
- MongoDB를 사용하기 위해, MongoDB, Robo3T를 설치하고 Mongoose 라이브러리를 사용할 예정이다.
(1) MongoDB 설치 (Mac)
- 우선, Terminal을 실행한 후, 아래 명령어를 통해 MongoDB를 설치한다.
// 커스텀 홈브루 탭 세팅
brew tap mongodb/brew
// MongoDB 설치
brew install mongodb-community
// MongoDB 실행
brew services start mongodb-community
- 인터넷 브라우저를 켜고 http://localhost:27017 주소로 접속했을 때 아래와 같은 화면이 보인다면 정상적으로 설치와 실행이 완료된 것이다.
(2) Robo 3T 설치
Robo 3T는 MongoDB Database를 직관적으로 확인하고 조작할 수 있는 GUI 프로그램이다.
- Robo 3T 공식 사이트에서 다운로드
- 위 사이트에서, OS에 맞는 버전을 다운로드 후 설치하면 된다.
- 위 화면의 좌측 상단, 컴퓨터 모양 아이콘을 누르면 MongoDB Connections 창이 뜬다.
- Create를 클릭한 후, 'Name'에 원하는 Connection 이름을 작성한다.
- 현재는 Local 환경에 Database를 구축할 것이기 때문에, 주소와 포트는 그대로 둔다.
- 원하는 이름으로 Connection을 생성한 후 Save를 누르면, 위와 같은 화면을 볼 수 있다.
- 이제, 내 Local 환경에서 MongoDB를 통해 데이터를 관리할 준비가 되었다.
(3) Mongoose 설치
- Mongoose는 Node.js 에서 MongoDB 연동 라이브러리 중, 가장 많이 사용되는 것이다.
- NoSQL에는 '스키마' 라는 개념이 없지만, RDB에서 처럼 '스키마' 를 사용할 수 있도록 해준다.
- 설치는, npm을 통해서 진행하면 아주 간단하게 완료할 수 있다.
- 우선, 작성중인 Node.js 프로젝트에서 아래 명령어를 실행한다.
npm i mongoose
- 이제 MongoDB를 사용할 준비가 끝났다.
Mongoose로 데이터 다루기
Mongoose를 통해, MongoDB의 CRUD 기능을 다루어본다.
(1) Database module 생성하기
- Mongoose 라이브러리를 사용하기 위해 require()를 통해 불러온다.
- 위에서 생성한 MongoDB Connection에 접속한다.
- 사용할 Database 이름을 정해준다.
- 외부에서 사용하기 위해 Module을 내보낸다.
- 위 순서대로 간단하게 진행해보도록 하겠다.
- 우선, 프로젝트에서 'schemas' 폴더를 만들고 그 안에 index.js 파일을 생성했다.
// ./schemas/index.js
// mongoose 라이브러리 불러오기
const mongoose = require('mongoose');
// connect 객체 생성
// connect 주소는 항상 mongodb://~~~ 의 형식이어야 한다.
// 주소 뒤의 'mydb' 부분에, Database 이름을 작성해주면 된다.
const connect = () => {
mongoose
.connect('mongodb://localhost:27017/mydb', {
ignoreUndefined: true,
})
.catch(err => console.log(err));
};
// 외부에서 사용하기 위해, 모듈을 내보낸다.
module.exports = connect;
(2) Database 연결하기
- 실행하고자 하는 파일은 app.js 파일이므로, 이 파일에서 모듈을 사용해보도록 한다.
- Express와 함께 사용하면 아래와 같다.
// express
const express = require('express');
const app = express();
const port = 8080;
// mongoose
// index.js 파일은 이름을 생략할 수 있기 때문에, ./schemas 만 입력
const connect = require('./schemas');
// connect mongoose
connect();
- 위와 같이 코드를 작성하고 app.js를 통해 실행하면, ./schema/index.js 파일에서 작성한 내용대로 MongoDB 서버에 연결이 정상적으로 이루어진다.
(3) Schema, Model 만들기
- Mongoose는 RDB처럼 Schema를 만들 수 있다고 했는데, 어떻게 만들 수 있는지 살펴본다.
- schemas 폴더에 'goods.js' 파일을 만들고 아래와 같이 코드를 작성한다.
const mongoose = require('mongoose');
const goodsSchema = new mongoose.Schema({
goodsId: {
type: Number,
required: true,
unique: true,
},
name: {
type: String,
required: true,
unique: true,
},
thumbnailUrl: {
type: String,
},
category: {
type: String,
},
price: {
type: Number,
},
});
// mongoose.model() 의 첫번째 인자 'Goods'가 Collection의 이름이 되는 것이다.
module.exports = mongoose.model('Goods', goodsSchema);
- 아주 직관적이기 때문에, 크게 설명할 것이 없어보인다.
- required는 필수 값, unique는 중복되지 않는 값이어야 한다는 의미이다.
- 마지막 줄의 코드에서 보면 'model'이라는 메서드를 사용했는데, 여기서 model은 우리의 데이터가 어떻게 생겼는지를 Database Collection에 정의하고, JavaScript와 서로 상호작용할 수 있도록 해주는 객체라고 보면 될 것 같다. (여기서 Database Collection은 RDB에서의 Table이라고 보면 되겠다.)
- 즉, 이 model 객체를 이용해서 DB의 해당 Collection에 데이터를 넣고, 수정하고, 삭제할 수 있다.
(4) Router와 연결시켜주기
- 이전 프로젝트에서 Router를 사용했기 때문에, DB에 접근하는 것 역시 이 Router를 통해 이루어질 것이다. 따라서, 우리가 생성해준 Router 파일에서 사용할 수 있도록 코드를 작성해준다.
// ./routes/goods.js
const express = require('express');
const router = express.Router();
// goods에서 exports 한 model 객체를 그대로 'Goods' 변수에 할당한다.
const Goods = require('../schemas/goods');
- 위와 같이 require() 를 사용해서 Model을 받아오면, 바로 사용이 가능하다.
(5) CRUD 구현해보기
- 드디어, DB에 데이터를 읽고, 쓰고, 수정하고, 삭제할 수 있는 상태가 되었다.
- 아래 코드를 통해 간략하게 CRUD 방법을 살펴본다.
// ./routes/goods.js
const express = require('express');
const router = express.Router();
const Goods = require('../schemas/goods');
// 상품 추가 (Create)
router.post('/goods/:goodsId/cart', async (req, res) => {
const { goodsId } = req.params;
const { quantity } = req.body;
// 유의사항: .find()는 Promise 객체를 반환하기 때문에, await/async를 사용한다.
const existsCarts = await Cart.find({ goodsId: Number(goodsId) });
if (existsCarts.length) {
return res.status(400).json({
success: false,
errorMessage: '이미 장바구니에 있는 상품입니다.',
});
}
await Cart.create({ goodsId: Number(goodsId), quantity });
res.json({ success: true });
});
// 전체 목록 조회 (Read)
router.get('/goods', async (req, res) => {
const { category } = req.query;
console.log('category?', category);
// 유의사항: .find()는 Promise 객체를 반환하기 때문에, await/async를 사용한다.
const goods = await Goods.find({ category });
res.json({
// 객체의 이름이 key와 똑같다면, 약식으로 하나만 써주어도 된다.
// 아래 코드는 goods: goods 와 동일하다.
goods,
});
});
// 상품 수량 수정 (Update)
router.put('/goods/:goodsId/cart', async (req, res) => {
const { goodsId } = req.params;
const { quantity } = req.body;
console.log(`goodsId: ${goodsId}`);
console.log(`quantity: ${quantity}`);
// 유의사항: .find()는 Promise 객체를 반환하기 때문에, await/async를 사용한다.
const existsCarts = await Cart.find({ goodsId: Number(goodsId) });
console.log(`existsCarts: ${existsCarts}`);
if (!existsCarts.length) {
return res.status(400).json({
success: false,
errorMessage: '장바구니에 상품이 없습니다.',
});
}
// 유의사항: .updateOne()은 Promise 객체를 반환하기 때문에, await/async를 사용한다.
await Cart.updateOne({ goodsId: Number(goodsId) }, { $set: { quantity } });
res.json({ success: true });
});
// 상품 삭제 (Delete)
router.delete('/goods/:goodsId/cart', async (req, res) => {
const { goodsId } = req.params;
// 유의사항: .find()는 Promise 객체를 반환하기 때문에, await/async를 사용한다.
const existsCarts = await Cart.find({ goodsId: Number(goodsId) });
if (existsCarts.length) {
await Cart.deleteOne({ goodsId: Number(goodsId) });
}
res.json({ success: true });
});
- find(), updateOne() 등의 메서드는 Promise 객체를 반환하기 때문에 꼭 async/await 이나 Promise 구문으로 작성해주어야 한다.
Author And Source
이 문제에 관하여([Node.js] Database - MongoDB), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@_nine/Node.js-Database-MongoDB
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Mongoose를 통해, MongoDB의 CRUD 기능을 다루어본다.
- Mongoose 라이브러리를 사용하기 위해 require()를 통해 불러온다.
- 위에서 생성한 MongoDB Connection에 접속한다.
- 사용할 Database 이름을 정해준다.
- 외부에서 사용하기 위해 Module을 내보낸다.
// ./schemas/index.js
// mongoose 라이브러리 불러오기
const mongoose = require('mongoose');
// connect 객체 생성
// connect 주소는 항상 mongodb://~~~ 의 형식이어야 한다.
// 주소 뒤의 'mydb' 부분에, Database 이름을 작성해주면 된다.
const connect = () => {
mongoose
.connect('mongodb://localhost:27017/mydb', {
ignoreUndefined: true,
})
.catch(err => console.log(err));
};
// 외부에서 사용하기 위해, 모듈을 내보낸다.
module.exports = connect;
// express
const express = require('express');
const app = express();
const port = 8080;
// mongoose
// index.js 파일은 이름을 생략할 수 있기 때문에, ./schemas 만 입력
const connect = require('./schemas');
// connect mongoose
connect();
const mongoose = require('mongoose');
const goodsSchema = new mongoose.Schema({
goodsId: {
type: Number,
required: true,
unique: true,
},
name: {
type: String,
required: true,
unique: true,
},
thumbnailUrl: {
type: String,
},
category: {
type: String,
},
price: {
type: Number,
},
});
// mongoose.model() 의 첫번째 인자 'Goods'가 Collection의 이름이 되는 것이다.
module.exports = mongoose.model('Goods', goodsSchema);
// ./routes/goods.js
const express = require('express');
const router = express.Router();
// goods에서 exports 한 model 객체를 그대로 'Goods' 변수에 할당한다.
const Goods = require('../schemas/goods');
// ./routes/goods.js
const express = require('express');
const router = express.Router();
const Goods = require('../schemas/goods');
// 상품 추가 (Create)
router.post('/goods/:goodsId/cart', async (req, res) => {
const { goodsId } = req.params;
const { quantity } = req.body;
// 유의사항: .find()는 Promise 객체를 반환하기 때문에, await/async를 사용한다.
const existsCarts = await Cart.find({ goodsId: Number(goodsId) });
if (existsCarts.length) {
return res.status(400).json({
success: false,
errorMessage: '이미 장바구니에 있는 상품입니다.',
});
}
await Cart.create({ goodsId: Number(goodsId), quantity });
res.json({ success: true });
});
// 전체 목록 조회 (Read)
router.get('/goods', async (req, res) => {
const { category } = req.query;
console.log('category?', category);
// 유의사항: .find()는 Promise 객체를 반환하기 때문에, await/async를 사용한다.
const goods = await Goods.find({ category });
res.json({
// 객체의 이름이 key와 똑같다면, 약식으로 하나만 써주어도 된다.
// 아래 코드는 goods: goods 와 동일하다.
goods,
});
});
// 상품 수량 수정 (Update)
router.put('/goods/:goodsId/cart', async (req, res) => {
const { goodsId } = req.params;
const { quantity } = req.body;
console.log(`goodsId: ${goodsId}`);
console.log(`quantity: ${quantity}`);
// 유의사항: .find()는 Promise 객체를 반환하기 때문에, await/async를 사용한다.
const existsCarts = await Cart.find({ goodsId: Number(goodsId) });
console.log(`existsCarts: ${existsCarts}`);
if (!existsCarts.length) {
return res.status(400).json({
success: false,
errorMessage: '장바구니에 상품이 없습니다.',
});
}
// 유의사항: .updateOne()은 Promise 객체를 반환하기 때문에, await/async를 사용한다.
await Cart.updateOne({ goodsId: Number(goodsId) }, { $set: { quantity } });
res.json({ success: true });
});
// 상품 삭제 (Delete)
router.delete('/goods/:goodsId/cart', async (req, res) => {
const { goodsId } = req.params;
// 유의사항: .find()는 Promise 객체를 반환하기 때문에, await/async를 사용한다.
const existsCarts = await Cart.find({ goodsId: Number(goodsId) });
if (existsCarts.length) {
await Cart.deleteOne({ goodsId: Number(goodsId) });
}
res.json({ success: true });
});
Author And Source
이 문제에 관하여([Node.js] Database - MongoDB), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@_nine/Node.js-Database-MongoDB저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)