All Articles

mongoose를 이용한 MongoDB 연동 실습


mongoDB

기존에는 MySQL, OracleDB, PostgreSQL 같은 RDBMS(관계형 데이터베이스)를 자주 사용했습니다.

그런데 관계형 데이터베이스는 몇 가지 한계가 있습니다.

첫 번째는 데이터 스키마가 고정적이라는 것입니다. 여기에서 스키마란 데이터베이스에 어떤 형식의 데이터를 넣을지 정보를 가리킵니다. 예를 들어 회원정보 스키마라면 계정 이름, 이메일, 이름 등이 되겠지요. 새로 등록하는 데이터 형식이 기존에 있던 데이터들과 다르다면? 기존 데이터를 모두 수정해야 새 데이터를 등록할 수 있습니다. 그래서 데이터양이 많을 때는 데이터베이스의 스키마를 변경하는 작업이 매우 번거로워질 수 있습니다.

두 번째는 확장성입니다. RDBMS는 저장하고 처리해야 할 데이터양이 늘어나면 여러 컴퓨터에 분산시키는 것이 아니라, 해당 데이터베이스 서버의 성능을 업그레이드하는 방식으로 확장해 주어야 했습니다.

MongoDB는 이런 한계를 극복한 문서 지향적 NoSQL 데이터베이스입니다. 이 데이터베이스에 등록하는 데이터들은 유동적으로 스키마를 지닐 수 있습니다. 종류가 같은 데이터라고 하더라도, 새로 등록해야 할 데이터 형식이 바뀐다고 하더라도 기존 데이터까지 수정할 필요는 없습니다. 서버의 데이터양이 늘어나도 한 컴퓨터에서만 처리하는 것이 아니라 여러 컴퓨터로 분산하여 처리할 수 있도록 확장하기 쉽게 설계되어 있습니다.


문서란?

“문서(document)“는 RDBMS의 record와 개념이 비슷합니다. 문서의 데이터 구조는 한 개 이상의 key-value 쌍으로 되어 있습니다.

문서는 BSON(바이너리 형태의 JSON) 형태로 저장합니다. 그렇기 때문에 나중에 JSON 형태의 객체를 데이터베이스에 저장할 때 큰 공수를 들이지 않고도 데이터를 데이터베이스에 등록할 수 있어 매우 편합니다.

새로운 문서를 만들면 _id라는 고유 값을 자동으로 생성하는데, 이 값은 시간, 머신 아이디, 프로세스 아이디, 순차 번호로 되어 있어 값의 고유함을 보장합니다.

여러 문서가 들어 있는 곳을 컬렉션이라고 합니다. 기존 RDBMS에서는 테이블 개념을 사용하기에 각 테이블마다 같은 스키마를 가지고 있어야 합니다. 새로 등록해야 할 데이터가 다른 스키마를 가지고 있다면 기존 데이터들의 스키마도 모두 바꾸어 주어야 하지요.

반면 MongoDB는 다른 스키마를 가지고 있는 문서들이 한 컬렉션에 공존할 수 있습니다.


MongoDB 구조

서버 하나에 데이터베이스를 여러 개 가지고 있을 수 있습니다. 그리고 각 데이터베이스에는 컬렉션이 여러 개 있으며, 컬렉션 내부에는 문서들이 들어 있습니다.

스키마 디자인

MongoDB에서 스키마를 디자인하는 방식은 기존 RDBMS에서 스키마를 디자인하는 방식과 사뭇 다릅니다. RDBMS에서 블로그용 데이터 스키마를 설계한다면 각 포스트, 댓글마다 테이블을 만들어 필요에 따라 JOIN해서 사용하는 것이 일반적입니다.

하지만 NoSQL에서는 그냥 모든 것을 Document 하나에 넣습니다.

덧글들을 포스트 문서 내부에 넣습니다. 문서 내부에 또 다른 문서들이 위치할 수 있는데, 이를 서브다큐먼트라고 합니다. 서브다큐먼트 또한 일반 문서를 다루는 것처럼 쿼리할 수 있습니다.

문서 하나에는 최대 16MB만틈 데이터를 넣을 수 있는데요. 100자 댓글 데이터라면 대략 0.24KB를 차지합니다. 16MB는 1만 6,384KB이니 문서 하나에 댓글 데이터를 6만 8,000개 넣을 수 있다는 소리가 되지요. 이 용량을 초과할 가능성이 있다면 컬렉션을 분리시키는 것이 좋습니다.



MongoDB 서버 준비

$ brew update
$ brew install mongodb

# 서버 실행
$ brew services start mongodb

# 설치 확인 (새로운 터미널 열기)
$ mongo
> version()

mongoose 설치 및 적용

mongoose는 Node.js 환경에서 사용하는 MongoDB 기반 ODM(Object Data Modeling) 라이브러리 입니다. 이 라이브러리는 데이터베이스 문서들을 자바스크립트 객체처럼 사용할 수 있게 합니다.

koa 프레임워크 프로젝트를 이어서 진행하겠습니다.

$ yarn add mongoose dotenv

dotenv는 환경변수들을 파일에 넣고 사용할 수 있게 하는 개발 도구입니다. mongoose를 연결할 때, 서버 계정과 비밀번호를 입력하게 되는데요. 민감한 정보는 코드에 직접 작성하지 않고, 환경 변수로 설정하는 것이 좋습니다. 프로젝트를 오픈 소스로 공개할 때는 .gitignore를 작성하여 환경변수가 들어 있는 파일을 제외시키면 되지요.

.env 환경변수 파일 생성

환경변수에는 서버에서 사용할 포트와 MongoDB 주소를 넣어 주겠습니다. 프로젝트 루트 경로에 .env 파일을 만들고 다음과 같이 입력하세요.

.env

PORT=4000
MONGO_URI=mongodb://localhost/blod

여기에서 blog는 우리가 사용할 데이터베이스 이름입니다. 데이터베이스가 없다면 자동으로 만드므로 사전에 따로 생성할 필요는 없습니다.

그 다음에는 src/index.js 파일 맨 위쪽에 다음과 같이 dotenv를 적용하세요. Node.js에서 환경변수는 process.env 파일로 조회할 수 있습니다.

src/index.js

require('dotenv').config();

const Koa = require('koa');
const Router = require('koa-router');
const bodyParser = require('koa-bodyparser');
(...)

const {
  PORT: port = 4000,
  MONGO_URI: mongoURI
} = process.env;

const app = new Koa();
const router = new Router();

app.listen(port, () => {
  console.log('listening to port', port);
});

그리고 비구조화 할당 문법을 사용하여 process.env 파일 내부 값에 대한 레퍼런스를 만들고, port에는 기본 값이 없으면 4000을 사용하도록 작성하세요.


mongoose로 데이터베이스에 연결

src/index.js

const mongoose = require('mongoose');

const {
    PORT: port = 4000,
    MONGO_URI: mongoURI
} = process.env;

mongoose.Promise = global.Promise; // Node의 Promise를 사용하도록 설정
mongoose.connect(mongoURI).then(() => {
    console.log('connected to mongodb');
}).catch((e) => {
    console.error(e);
});

mongoose 에서 데이터베이스에 요청할 때, 이를 Promise 기반으로 처리할 수 있는데, 이 때 어떤 형식의 Promise를 사용할지 정해야 합니다. (Node v7 이전에는 공식적인 Promise가 없어 bluebird, Promise/A+ 등 여러 구현체가 있었습니다. 이제는 Node.js 자체에 Promise를 내장하고 있으므로, 내장된 Promise를 사용하도록 설정해 주어야 합니다.)

MongoDB 주소는 process.env 파일에 적어 놓았던 MONGO_URI 값이며, 이 주소를 사용하여 접속하도록 설정했습니다.

서버를 실행하는 터미널에서 다음과 같이 출력하면 성공적으로 연결된 것입니다.

[nodemon] starting `node src/index.js`
listening to port 4000
connected to mongodb

이제 mongoose를 사용할 준비가 되었습니다.