관리 메뉴

거니의 velog

(12) mongoose를 이용한 MongoDB 연동 실습 1 본문

React/React_백엔드 프로그래밍

(12) mongoose를 이용한 MongoDB 연동 실습 1

Unlimited00 2024. 2. 20. 16:35

* 이 장에서는 우리가 만들 Node.js 서버와 MongoDB를 연동할 수 있도록 MongoDB 기초 지식을 알아보자. 그리고 mongoose를 이용하여 서버에서 직접 데이터를 추가, 조회, 삭제, 수정하는 방법도 알아보자.

* 이번 실습은 다음 흐름으로 진행한다.


1. 소개하기

* 서버를 개발할 때 데이터베이스를 사용하면 웹 서비스에서 사용되는 데이터를 저장하고, 효율적으로 조회하거나 수정할 수 있다. 기존에는 MySQL, OracleDB, PostgreSQL 같은 RDBMS(관계형 데이터베이스)를 자주 사용했다.

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

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

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

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

* 우리는 MongoDB를 사용하여 서버를 개발할 것이다. 그렇다고 MongoDB가 무조건 기존의 RDBMS 보다 좋은 것은 아니다. 상황별로 적합한 데이터베이스가 다를 수 있다. 예를 들어 데이터의 구조가 자주 바뀐다면 MongoDB가 유리하다. 그러나 까다로운 조건으로 데이터를 필터링해야 하거나, ACID 특성을 지켜야 한다면 RDBMS가 더 유리할 수 있다.

* ACID 특성은 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 지속성(Durability)의
  앞 글자를 따서 만든 용어로, 데이터베이스 트랜잭션이 안전하게 처리되는 것을 보장하기 위한
  성질을 의미한다.

* 우리가 구현할 서버는 RDBMS로 만들 수도 있고, MongoDB로 만들 수도 있다. MongoDB를 사용한 이유는 무엇보다 조금만 배워도 유용하게 활용할 수 있기 때문이다. RDBMS는 설정해야 할 것도 많고, 배워야 할 것도 많다. 만약 서버 개발에 관심이 있다면 반드시 나중에 RDBMS도 사용해 볼 것을 권장한다.


(1) 문서란?

* 여기서 말하는 '문서(document)'는 RDBMS의 레코드(Record)와 개념이 비슷하다. 문서의 데이터 구조는 한 개 이상의 키-값의 쌍으로 구성되어 있다.

* MongoDB에서 사용하는 문서 예시를 하나 살펴보자.

{
    "_id" : ObjectId("5099803df3f4948bd2f98391"),
    "username" : "unlimited00",
    "name" : { first: "G.J.", last: "Lee" }
}

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

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

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

* 반면 MongoDB는 다른 스키마를 가지고 있는 문서들이 한 컬렉션에서 공존할 수 있다. 다음 예시를 한 번 보자.

{
    "_id" : ObjectId("5099803df3f4948bd2f98391"),
    "username" : "unlimited00"
}

{
    "_id" : ObjectId("5099803df3f4948bd2f98396"),
    "username" : "unlimited001",
    "phone" : "010-1234-1234"
}

* 처음에는 데이터에 전화번호가 필요 없었는데, 나중에 필요해졌다고 가정해 보자. RDBMS에서는 한 테이블의 모든 데이터가 같은 스키마를 가져야 하므로, 기존 데이터 전체를 일일이 수정해야 한다. 하지만 MongoDB에서는 컬렉션 안의 데이터가 같은 스키마를 가질 필요가 없으므로 그냥 넣어 주면 된다.


(2) MongoDB 구조

* MongoDB 구조는 다음과 같다. 서버 하나에 데이터베이스를 여러 개 가지고 있을 수 있다. 각 데이터베이스에는 여러 개의 컬렉션이 있으며, 컬렉션 내부에는 문서들이 들어 있다.


(3) 스키마 디자인

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

* RDBMS에서 데이터베이스를 설계한다면 그 구조는 다음과 유사하다.

* 하지만 NoSQL에서는 그냥 모든 것을 문서 하나에 넣는다. 문서 예시의 형식을 한번 살펴보자.

{
	_id : ObjectId,
    title : String,
    body : String,
    username : String,
    createdDate : Date,
    comments: [
    	{
        	_id : ObjectId,
            text : String,
            createdDate : Date
        },
    ],
};

* 이런 상황에서 보통 MongoDB는 댓글을 포스트 문서 내부에 넣는다. 문서 내부에 또 다른 문서가 위치할 수 있는데, 이를 서브다큐먼트(subdocument)라고 한다. 서브다큐먼트 또한 일반 문서를 다루는 것처럼 쿼리할 수 있다.

* 문서 하나에는 최대 16MB만큼 데이터를 넣을 수 있는데, 100자 댓글 데이터라면 대략 0.24KB를 차지한다. 16MB는 16.384KB이니 문서 하나에 댓글 데이터를 약 68,000개 넣을 수 있다.

* 서브다큐먼트에서 이 용량을 초과할 가능성이 있다면 컬렉션을 분리시키는 것이 좋다.