MongoDB 소개

DB/MongoDB 2013. 1. 7. 17:54


Mongodb는 NO-SQL DB중 하나이다. NoSQL은 문자그대로 'No SQL'이라고도 하고 'Not Only SQL'의 약어라고도 한다.
개인적으로 'No SQL'은 제품 자체의 특성, Game Changer로서의 'NoSQL'을 강조하는 의미로 강한 도전감을 내포하고 있고
'Not Only SQL'은 RDBMS의 Alternative로서의 'NoSQL'의 존재론적 의미를 내포하고 있다고 생각한다.
MongoDB는 NoSQL제품군중 국내에서 가장 많이 활용된 프러덕트이기도 하다.[1]
경쟁제품으로 카산드로, HBASE등이 있다. NoSQL 솔루션이 각광 받으면서 여러 제품군들이 나오면서 각 제품의 효용성에 대한 찬반이 격화되고 있고 몽고 디비도 성능에 대한 이슈[2]와 이에 대한 반박[3]이 대두되고 있다.

NoSQL제품군은 DB성격에 따라 Key-Value Database, Document Database, BigTable Database, Graph Database로 분류하는데 MongoDB는 Document 데이터 베이스로 분류된다. MongoDB와 경쟁제품으로 많이 비교되는 HBase와 Cassandra는 BigTable제품군으로 분류되는데, 사실 용도가 전혀 다른 성격을 가진 NoSQL제품군들로 경쟁상대가 아니라 상호보완적인 제품으로 봐야한다. 흔히 이쪽 계열의 엔지니어들이 벌이는 불필요한 논쟁중 하나가 프로그래밍 랭귀지 우열에 대한 것이다. 
혹자는 이 문제가 철학/신념의 문제라고 하지만 실상은 헤게모니싸움. 더 솔직히 말하면 밥그릇 싸움에 불과하다.
프로그래밍 언어는 그 어떤 범용 언어도 모든일을 최고로 효율적으로 해결해낼수 없다. 각각 특성에 맞게 사용하면 되는게 정답이다. 시장에서 많이 쓰이는 언어들이라면 차이와 장단점이 존재할뿐 우열같은건 애초에 없다. NoSQL제품군도 마찬가지다. 차이에 따라 용도에 맞는 사용을 하면 되는것이다. 어떤일이든 최적의 방법으로 해결해주는 Silver Bullet같은건 존재하지도 존재할수도 없기때문이다.
MongoDB는 Document-Oriented NoSQL솔루션으로 Schema-Free, Full Text Indexing을 지원한다. 
이쯤하면 생각나는 솔루션이 있다. 바로 Lotus Domino Notes. Domino Notes라... 
Document Database가 가장 적합한 용도는 어디일까? 한장 한장 비슷해보이지만 들여다 보면 다른, 그래서 RDBMS로 일반화시키긴 어려운, 그리고 데이터들이 서로 연관관계가 적은 독립적인 데이터셋이 많은 응용 프로그램. 
그룹웨어나 이런 블로그 같은것들. 웹 서비스 데이터의 1차 저장소로 사용하면 좋을듯하다. 
게다가 유연한 데이터 구조와 중복데이터를 허용하는 특성때문에 빈번한 필드 추가와 삭제/변경이 일어날수 있는 웹서비스에 적합한 솔루션으로 보인다.

몽고디비의 공식 홈페이지는 http://www.mongodb.org/ 이다. 설치파일및 관련 도큐멘트를 모두 얻을수 있다.

구글 트렌드로 본 MongoDB / Cassandra / HBase 관심도 - 카산드라의 경우에는 동일한 이름의 사람의 검색이 더많아 부득이하게 cassandra db로 하였다. 이에 결과가 상당히 부정확하다. 


- MySQL에 비해선 아직 턱없이 부족한 관심도. 하지만 MySQL의 관심도 하락 추세가 무엇을 의미하는지는 생각해봐야한다.

[1] "Hadoop과 MongoDB를 이용한 로그분석시스템 구축사례" http://blog.naver.com/PostView.nhn?blogId=nts_story&logNo=50116614473&categoryNo=15&viewDate=&currentPage=1&listtype=0
"몽고DB Daum MyAgora 도입사례" http://rockfactory.tistory.com/119

[2]“몽고DB 쓰지 마세요”…왜?  http://www.bloter.net/archives/103400 
    위 기사의 Base가된 포스트 http://pastebin.com/raw.php?i=FD3xe6Jt
[3]위 기사에 대한 반박  http://news.ycombinator.com/item?id=3202959



출처 - http://garden.egloos.com/10000179/post/233269






요즘 대용량 데이타 처리 때문에, NoSQL을 머릿속에만 올려놓고, 근래에나 되서 이래서는 안되겠다 해서 직접 자료를 찾아보고 있습니다.

NoSQL은 Cassandra, HBase, Mongo, Riak등을 후보군으로 뒀는데,

Cassandra는 FaceBook에서 Donation해서 만든 분산 DB로 개인적으로는 가장 신뢰가 가기는 했지만, 국내의 많은 블로그 포스팅등을 읽어보면, 안정성이나 사용성이 떨어진다는 것이다. 즉 제품은 좋은데 야생마처럼 잘 쓰지 못하면 모쓰는 제품이라는 이야기. 일단 후보로 남겨놓고 패스.

HBase는 Hadoop File System (HDFS)를 기반으로 설계되었는데, 검색해보니 생각보다 많이 사용이 안되는 것 같아서 패스
Riak도 신생이라서 패스

결국은 Mongo와 Cassandra에서 고민하게 되었는데,
신생 MongoDB가 얼마전부터 사람들 입에 많이 입에 오르내리고 있다. 검색을 해봐도 많이 나오고
이는 즉 사용이 쉽다는 것을 의미하고 또한 10gen이라는 회사에서 제품에 대한 Ownership을 지고 서포트와 컨설팅 그리고 라이센스를 제공하고 있다. 둘다 오픈소스(?)이긴 하지만 자기네들만이 사용하기 위해 만든 Cassandra와는 태생 자체가 다르다는 사실

요즘 분산 아키텍쳐를 보면 대부분 비슷한것이 앞단에 Load Balancing을 해주는 Proxy 를 두고, 뒤에 데이타 처리를 하는 Processing Node를 두는 것이 일반적인데, SWIFT도 글코, MogileFS도 글코, 분산 처리 환경인 Gearman이나 Hadoop도 결국은 비슷하다. 아니나 다를까, MongoDB도 유사한 구조를 갖는다.

일단 기능적인 특징을 보면

Indexing이 가능하다.
이말은 즉 빠른 Search가 가능하다는 이야기인데, 문서를 찾아보니, Index는 메모리에 저장되기 때문에, 메모리 크기에 영향을 많이 받는다. 즉 Deployment설계할때, 하드웨어의 Memory 사이즈가 중요한 Factor 라는 것

GridFS 기반의 Blob 데이타 저장 지원
GridFS라는 분산 파일 시스템을 사용하여 Binary 데이타 저장이 가능하다. 일반적인 아키텍쳐에서 meta 정보를 DBMS에, binary를 File System에 나눠서 저장할때, 이로 인해서 발생되는 데이타 일관성에 불일치를 방지할 수 있다는 점에서는 혁신적인데.. 문제는...
국내의 어느 블로거가 테스트한 데이타 http://symplog.tistory.com/entry/MongoDB-MongoDB-GridFS-%EB%B6%80%ED%95%98%ED%85%8C%EC%8A%A4%ED%8A%B8 를 보면, 파일 업로드 다운로드 성능이 그리 뛰어나지 않은 듯 하다.
큰 파일을 저장할때, 파일을 Chunk 단위로 나눠서 다운로드, 업로드 하는데 이는 메모리 사용면에서 효율성을 제공한다. (한꺼번에 다 읽거나 쓸때 한꺼번에 Flush를 하면 파일을 메모리에 가지고 있는 동안, 파일 사이즈가 크면 Out Of Memory를 유발할 수 있기 때문에..) 1.7 버전 이하에서는 4M, 1.7 이상에서는 16M의 Chunk Size를 제공하는 것 같은데. 
문제는 Opendedup에서도 테스트해봤지만, 이 Chunk 단위로 파일을 나누는 작업이 보통 일이 아니라는, 일단 태생 자체가 작은 Blob 데이타를 저장하기 위함이지 대용량 파일을 저장하기 위함은 아닌 것 같은데,
http://blog.wordnik.com/12-months-with-mongodb 블로그를 보면 12billion (약 120억개)의 레코드를 저장하고, 여기에 음악 파일을 저장하는 것을 보면 가능하다고도 볼 수 있다. 보통 음악 파일이 4M 안팍인것을 감안하면 괜찮은 시나리오인 듯 하나 500GB가 넘어가는 비디오 파일을 저장할때는 어느정도 성능을 감당할 수 있을지는 미지수 이다.
만약에 안정적으로 GridFS가 대용량 파일을 저장할 수 있는 구조를 제공한다면 사람들이 SWIFT,MogileFS,GlusterFS를 사용하지 않고 모두 MongoDB를 사용해야 하지 않을까? 
이 부분은 나름 테스트가 필요한 부분으로 남겨놓고 넘어간다.

Querying
아울러 RDBMS 와 같은 Query를 제공한다. (물론 RDBMS보다 한참 못 미치기는 하지만)
Key/Value Store만 지원하는 다른 NoSQL에 비하면 매력 적인 기능

Replication
http://www.mongodb.org/display/DOCS/Master+Slave
Master-Slave Replication도 지원하네, Query Off Loading 구현도 가능하겠다.

Sharding
그외에 자체적으로 데이타 Sharding 아키텍쳐를 지원한다. 요즘 이게 유행인지 MySQL 최신 버전도 자체적으로 Sharding을 지원한다. Sharding을 사용하면 1000개의 Shard까지는 거뜬히 지원할 수 있는 것 처럼 나오는데, 이건 테스트 하기는 어려울테고, 성능 데이타를 레퍼런스 하는 수 밖에

일단 완성도나 기능들이 높아 보이는 것 같은데..
깔아서 테스트해보고, 10gen 에서 컨설팅 불러서 직접 들여다 봐야 몬가 나오지 않을까?
=== 첨언 ===
구조를 살펴보니, 앞에서 언급했던 것처럼 SWIFT나 MogileFS와 상당히 유사하다
앞단에 Load Balancing 역할을 해주는 mongos 라는 프로세스들이 뜨고
뒷단에 실제 데이타를 저장하는 mongod라는 프로세스들이 뜨는데, 여기서 재미있는 것은 데이타 Replication을 하는데, 각 Shard당 3개의 인스턴스를 제공하도록 구성을 권장한다. Swift등에서 흔히 이야기 하는 3 Copy다. 데이타 안정성등을 위하는 건데. (딱 봐도, 하드웨어 비용이 장난 아니겠다.)

더불어서 MogoDB는 Cassandra나 HBase에 비해서 나은 성능을 갖는데 앞에서 설명한 바와 같이 Memory를 이용한 Indexing등으로, 반대로 이야기 하면 Memory가 충분히 있어야 한다는 이야기고, 비싸다는 이야기다.

큐브리드 블로그에 보면 재미있는 내용이 있는데 http://blog.cubrid.org/dev-platform/nosql-benchmarking/

Cassandra and HBase is for processing full-scale large amounts of data, while MongoDB can be used quickly, schema-free when using a certain amount of data.

MongoDB adopts a documented-oriented format, so it is more similar to RDBMS than a key-value or column oriented format.

MongoDB operates on a memory base and places high performance above data scalability. If reading and writing is conducted within the usable memory, then high-performance is possible. However, performance is not guaranteed if operations exceed the given memory. Therefore, MongoDB should be used as a medium or small-sized storage system.

한마디로, 성능은 좋지만 빅데이타는 Cassandra나 HBase를 쓰고 중소형에만 MongoDB를 쓰라는 것이다.
RDBMS에 유사하고 강력한 Feature, 사용의 편리성의 입장에서 MongoDB가 국내외에서 많은 사용층을 가지고 있는 것이 대강 이해는 된다. 한편으로는 MongoDB의 한계를 벗어날만한 데이타를 아직까지 사용해본 적이 없다는 반증도 될것이다. 10~20억 데이타는 내가 아는한에서는 RDBMS에서도 크게 문제가 없다. 문제는 10~20억을 넘는 100억, 1000억개의 데이타 핸들링에도 MongoDB가 버텨 줄것이냐인데.. 데이타 한건당 대략 10K만 잡아도 용량이 1Peta 이다. 3TB 노드를 300개 정도 연결해야 한다는 것인데... MongoDB에서 보통 1000개의 Instance를 이야기를 하니 이론상으로는 가능할것 같기는 한데
첫번째는 어렵지 않을까? 하는 생각이고, (그만한 레퍼런스가 있냐?) 두번째는 만약에 된다고 하더라도 돈이 엄청 들어갈것 같은 느낌이다. Swift도 MogileFS도 저가라고는 말하지만 소프트웨어가 저가인거지 3Copy로 하드웨어 구성을 벤더 제품으로 하면 마찬가지라는... (Commodity 하드웨어라면 몰라도..)
  이래 저래 자료를 찾아볼 필요가 있다.



출처 - http://bcho.tistory.com/601






MongoDB 탐구

이 데이터베이스 관리 시스템이 매우 인기 있는 이유를 확인한다.

Joe Lennon, 모바일관련 개발자, Core International

요약:  이 기사에서는 프로덕션 환경에서 데이터베이스를 확장할 수 있는 기능을 제공하는, C++로 작성된 오픈 소스 문서 지향 데이터베이스 관리 시스템인 MongoDB에 관해 배웁니다. 기존의 관계형 데이터 베이스 시스템(RDBMS)과 비교하여 문서 지향 데이터베이스가 갖고 있는 이점을 확인합니다. MongoDB를 설치하고 데이터베이스 콜렉션과 문서 작성을 시작합니다. RDBMS 데이터베이스 관리자와 개발자에게 익숙한 방식으로 키/값 저장소에 효율성을 제공하는 MongoDB의 동적 쿼리 기능을 시험합니다.

기사 게재일:  2011 년 9 월 20 일 


MongoDB란?

최근에는 기존의 관계형 모델과는 다른 데이터베이스 관리 시스템에 대한 관심이 증가하고 있다. 이 중심에는 NoSQL이라는 개념이 있는데, 이는 데이터베이스 상호 작용에 SQL을 사용하지 않는 데이터베이스 소프트웨어를 총괄하는 용어이다. 주목할 만한 NoSQL 프로젝트 중 하나는 JSON 형태의 문서 콜렉션으로 데이터를 저장하는 오프 소스 문서 지향 데이터베이스인 MongoDB이다. MongoDB가 다른 NoSQL 데이터베이스와 다른 점은 쿼리가 매우 쉽게 변환되기 때문에 관계형 데이터베이스를 MongoDB로 쉽게 변환할 수 있는 강력한 문서 지향 쿼리 언어에 있다.

MongoDB는 C++로 작성되어 있다. MongoDB는 JSON의 2진 버전인 BSON을 사용하여, 키/값 쌍으로 데이터를 유지하는 JSON 형태의 문서에 데이터를 저장한다. MongoDB가 다른 문서 데이터베이스와 구별되는 한 가지 기능은 SQL문을 MongoDB 쿼리 함수 호출로 매우 간단하게 변환하는 기능이다. 이 기능을 이용하면 조직에서 현재 사용 중인 관계형 데이터베이스를 쉽게 마이그레이션할 수 있다. 또한, 주요 운영 체제와 프로그래밍 언어에서 사용 가능한 2진 파일과 드라이버를 사용하면 매우 간단하게 설치하여 사용할 수 있다.

MongoDB는 GNU AGPL(Affero General Public License) 버전 3.0에 따라 라이센스가 부여된 데이터베이스를 사용하는 오픈 소스 프로젝트이다. 이 라이센스는 카피레프트 제한이 소프트웨어를 사용하는 데는 적용되지 않고 배포에만 적용되는 허점을 보완한 GNU GPL의 수정 버전이다. 물론, 일반적으로 클라이언트 디바이스에 설치되지 않고 클라우드에 저장되는 소프트웨어는 이점이 중요하다. 사실상 소프트웨어가 배포되지 않기 때문에 일반 GPL을 사용하는 경우에는 라이센스 조항을 회피할 수 있다는 사실을 인식할 수 있다.

AGPL은 데이터베이스 애플리케이션 자체에만 적용되며 MongoDB의 다른 요소에는 적용되지 않는다. 개발자들이 다양한 프로그래밍 언어로 MongoDB에 연결하는 데 필요한 공식 드라이버는 Apache License Version 2.0에 따라 배포된다. MongoDB 문서는 CCL(Creative Commons license)에 따라 사용 가능하다.

문서 지향 데이터베이스

문서 지향 데이터베이스는 기존의 관계형 데이터베이스와는 매우 다르다. 문서 지향 데이터베이스는 테이블과 같은 경직된 구조에 데이터를 저장하지 않고 느슨하게 정의된 문서에 데이터를 저장한다. 관계형 데이터베이스 시스템(RDBMS) 테이블에서는 열을 새로 추가하려면 테이블 자체의 정의를 변경해야 한다. 따라서 비록 널 값을 갖게 될지라도 열이 기존의 모든 레코드에 추가된다. 이는 RDBMS의 엄격한 스키마 기반 설계로 인한 것이다. 그러나 문서를 사용하는 경우에는 기타 모든 문서를 변경하지 않고도 개별 문서에 속성을 새로 추가할 수 있다. 이는 문서 지향 데이터베이스가 일반적으로 스키마를 사용하지 않도록 설계되기 때문이다.

또 다른 기본적인 차이점은 문서 지향 데이터베이스는 문서 간의 엄격한 관계를 제공하지 않는다는 점이다. 이러한 점은 문서 지향 데이터베이스가 스키마 없는 설계를 유지하는 데 도움이 된다. 이점은 관계에 의존하여 데이터 스토리지를 표준화하는 관계형 데이터베이스와는 매우 다른 점이다. 문서 데이터베이스에서는 "관련" 데이터를 별도의 스토리지 영역에 저장하는 대신에 문서 자체에 삽입한다. 각 참조는 추가 쿼리를 필요로 하기 때문에 이렇게 하는 것이 관련 데이터가 저장된 또 다른 문서에 참조를 저장하는 것보다 더 빠르다.

이러한 기능은 데이터가 상위 문서 안에서 독립적으로 존재하는 것이 적합한 많은 애플리케이션에서 매우 잘 동작한다. 이에 해당하는 예(MongoDB 문서에도 있음)로는 블로그 포스트와 주석이 있다. 주석은 단일 포스트에만 적용되므로 주석을 블로그 포스트와 분리해서 생각하는 것은 타당하지 않다. MongoDB에서는 블로그 포스트 문서에 해당 포스트의 주석을 저장하는 comments 속성이 있다. 관계형 데이터베이스에서는 ID가 기본 키인 주석 테이블과 포스트 테이블 그리고 주석이 속하는 포스트를 정의하는 중간 맵핑 테이블 post_comments가 존재하게 된다. 이로 인해 매우 간단해야 할 것들이 불필요하게 매우 복잡해진다.

그러나 관련 데이터를 별도로 저장해야 하는 경우에는 MongoDB에서 별도의 콜렉션을 사용하여 쉽게 이러한 작업을 수행할 수 있다. 또 다른 좋은 예는 MongoDB 문서에 고객 주문 정보를 저장하는 것이다. 일반적으로 고객 주문 정보는 고객 정보, 주문 자체, 주문 품목 및 제품 정보로 구성된다. MongoDB를 사용하면 고객, 제품 및 주문 정보를 개별 콜렉션에 저장하게 되지만, 품목 데이터는 관련된 주문 문서 안에 삽입된다. 그러면, 관계형 데이터베이스에서 사용한 것과 같은 외부 키 형태의 ID를 사용하여 제품 고객 콜렉션을 참조한다. 이러한 하이브리드 방식은 단순하기 때문에 MongoDB는 SQL로 작업하는 데 익숙한 개발자들에게 좋은 선택이 된다. 그렇긴 하지만, 다른 콜렉션에서 데이터를 참조하는 대신에 문서 내부에 데이터를 삽입하면 성능을 대폭 개선할 수 있으므로 각각의 개별 유스 케이스를 대상으로 취해야 하는 접근 방식을 신중하게 결정해야 한다.

기능 개요

MongoDB는 단지 기본적인 키/값 저장소가 아니다. MongoDB의 다른 기능 중 일부를 간략하게 살펴보도록 하자.

  • 공식 2진 파일은 Windows®, Mac OS X, Linux® 및 Solaris에서 사용 가능하며 소스 배포판을 이용하여 직접 빌드할 수도 있다.
  • 공식 드라이버는 C, C#, C++, Haskell, Java™, JavaScript, Perl, PHP, Python, Ruby 및 Scala에서 사용 가능하며, 다른 언어에서는 광범위한 커뮤니티 지원 드라이버를 사용할 수 있다.
  • 모든 문서 속성에서 기준을 사용하여 데이터를 찾을 수 있게 하는 임시(Ad-hoc) Javascript 쿼리. 이러한 쿼리는 SQL 쿼리의 기능을 반영한 것으로 SQL 개발자는 이 쿼리를 이용하여 MongoDB 쿼리를 매우 간단하게 작성할 수 있다.
  • 쿼리에서 정규 표현식 지원
  • MongoDB의 쿼리 결과는 limit(), skip(), sort(), count(), distinct()  group()을 포함하여 필터링과 수집 및 정렬에 필요한 다양한 함수를 제공하는 커서에 저장된다.
  • 고급 수집용 map/reduce 구현
  • GridFS를 사용하는 대용량 파일 스토리지
  • RDBMS 형태의 속성 인덱싱 지원, 여기에서는 선택된 문서 속성에서 직접 인덱스를 작성할 수 있다.
  • 힌트, 설명 계획 및 프로파일링을 사용하는 쿼리 최적화 기능
  • MySQL과 비슷한 마스터/슬레이브 복제
  • 표준화된 데이터를 필요로 하는 참조 쿼리를 허용하는 콜렉션 기반 오브젝트 스토리지
  • 자동 샤딩(Auto-sharding)을 이용한 수평적 확장
  • 경쟁이 없는 고성능의 동시성을 구현하는 데 필요한 제자리 쓰기(In-place update) 기능
  • 설치하지 않고도 MongoDB를 사용해 볼 수 있는 온라인 쉘
  • 발행되었거나 현재 작성 중인 여러 권의 책과 상세한 문서

MongoDB 설치

다행히도 MongoDB는 다양한 플랫폼에서 매우 간단하게 설치할 수 있다. 2진 배포판은 Windows, Mac OS X, Linux 및 Solaris에서 사용 가능하며 다른 시스템에서는 다양한 패키지 관리자가 쉬운 설치 및 설정 옵션을 제공한다. 자신이 있으면 직접 소스 코드를 컴파일해도 된다. 이 섹션에서는 Windows와 Mac OS X에서 MongoDB를 설치하고 프로세스를 Windows에서 서비스로 설정하거나 OS X에서 디먼으로 설정하는 방법을 배운다.

Windows에서 설치

Windows에서 MongoDB를 설치하는 과정은 매우 간단하다. 선호하는 웹 브라우저로 http://www.mongodb.org/downloads를 탐색하여 안정된 최신 프로덕션 릴리스(Windows용)를 다운로드한다. 64비트 버전을 권장하지만 이 버전은 Windows 운영 체제 64비트 버전을 사용 중인 경우에만 사용할 수 있다. 사용 중인 운영 체제의 버전이 불확실한 경우에는 32비트 버전을 사용한다.

zip 파일을 C:\drive에 추출하면 이름이 mongodb-win32-i386-1.6.4인 폴더가 새로 생긴다. 작업을 편하게 하려면 이 폴더의 이름을 mongo로 바꾼다. 다음에는 데이터 디렉토리를 작성해야 한다. Windows 탐색기에서 C:\drive의 루트로 이동하여 data라는 폴더를 새로 작성한다. 이 폴더 안에 db라는 폴더를 새로 작성한다.

그러면 MongoDB 서버를 시작할 수 있다. Windows 탐색기를 사용하여 C:\mongo\bin을 탐색하고 mongod.exe를 두 번 클릭한다. 열린 명령 프롬프트 창을 닫으면 MongoDB 서버가 중지된다. 따라서, MongoDB 서버를 Windows 제어인 서비스로 설정하는 것이 더 편리하다. 이제 이 작업을 수행하도록 하자.

Start>Run>을 선택하고 cmd를 입력한 후, OK를 클릭하여 명령행 프롬프트 창을 열고 목록 1에 있는 명령을 실행한다.


목록 1. MongoDB 서버를 서비스로 설정 
> cd \mongo\bin
> mongod --install --logpath c:\mongo\logs --logappend 
--bind_ip 127.0.0.1 --directoryperdb

목록 2에 있는 결과물이 표시된다.


목록 2. 성공적으로 작성된 서비스
all output going to c:\mongo\logs
Creating service MongoDB.
Service creation successful.
Service can be started from the command line via 'net start "MongoDB"'.

MongoDB를 서비스로 설치했으므로 다음 명령을 사용하여 MongoDB를 시작할 수 있다. > net start "MongoDB".

목록 3에 있는 결과물이 표시된다.


목록 3. 성공적으로 시작된 MongoDB
The Mongo DB service is starting.
The Mongo DB service was started successfully.

이제 MongoDB 쉘 클라이언트를 실행할 수 있다. 명령 프롬프트 창이 열리면 위치가 c:\mongo\bin 폴더인지 확인한 다음, >mongo 명령을 입력한다.

또는 Windows 탐색기에서 C:\mongo\bin으로 이동하여 mongo.exe를 두 번 클릭한다. 어떤 방법으로 쉘을 시작하든지 목록 4에 있는 것과 같은 프롬프트가 표시된다.


목록 4. 쉘 시작
MongoDB shell version: 1.8.1
connecting to: test
>

Mac OS X 시스템에서 MongoDB를 설정하는 경우가 아니면 이 섹션의 다음 부분을 건너뛰어 "시작하기"로 이동할 수 있다. 여기서는 쉘 클라이언트를 사용하여 MongoDB 서버와 상호 작용하는 방법을 배운다.

Mac OS X에서 설치

Mac OS X 64비트 버전을 사용 중이라고 가정하여 다음 단계에서는 MongoDB 64비트 OS X 2진 파일을 다운로드하여 추출한 후, 구성하여 시작하는 방법을 자세히 다룬다. 또한, MongoDB를 디먼으로 실행하는 방법을 살펴본다.

먼저, 터미널을 실행한다(Applications>Utilities>Terminal). 터미널 창에서 목록 5에 있는 명령을 실행한다.


목록 5. Mac OS X에서 MongoDB 설정
$ cd ~
$ curl http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-1.6.4.tgz > mongo.tgz
$ tar xzf mongo.tgz
$ mv mongodb-osx-x86_64-1.8.1/ mongo
$ mkdir -p /data/db

이제 MongoDB가 설정되었으므로 사용할 차례이다. 진도를 나가기 전에 해당 경로에 MongoDB를 추가하는 것이 좋다. $ nano ~/.bash_profile 명령을 실행한다.

이 파일이 아직 존재하지 않을 수도 있다. 어떤 경우이든 다음 행(export PATH={$PATH}:~/mongo/bin)을 추가한다.

ctrl + O을 눌러서 파일을 저장한 후, 프롬프트에서 Enter를 누른다. 그런 다음, ctrl + X를 눌러서 nano를 종료한다. 이제, $ source ~/.bash_profile 명령을 사용하여 bash 프로파일을 다시 로드한다.

그러면 MongoDB를 시작할 준비가 된다. MongoDB를 시작하려면 $ mongod 명령을 실행한다.

이렇게 하면 MongoDB 데이터베이스 서버가 포그라운드 프로세스로 시작된다. MongoDB를 백그라운드에서 디먼 프로세스로 시작하고 싶은 경우에는 그 대신 $ sudo mongod --fork --logpath /var/log/mongodb.log --logappend 명령을 실행한다.

비밀번호를 입력하라는 메시지가 표시되면 이 프롬프트에서 Mac OS X 관리자 비밀번호를 입력한다.

MongoDB를 시작하는 방법에 관계없이 서버가 실행된다. MongoDB를 포그라운드에서 시작한 경우, 클라이언트를 시작하려면 별도의 Terminal 탭이나 창이 필요하다. 클라이언트를 시작하려면 $ mongo 명령을 사용한다.

목록 6에 있는 것과 같은 프롬프트가 표시된다.


목록 6. 클라이언트 시작
MongoDB shell version: 1.8.1
connecting to: test
> 

다음 섹션에서는 MongoDB 쉘을 사용하여 데이터베이스, 콜렉션 및 문서 등을 작성하는 방법을 배운다.

MongoDB 시작하기

MongoDB 배포판에 포함되어 있는 것은 데이터베이스를 완전히 제어할 수 있는 쉘 애플리케이션이다. 이 쉘을 사용하는 경우에는 서버측 Javascript 함수를 사용하여 데이터베이스, 콜렉션, 문서 및 인덱스를 작성하고 관리할 수 있다. 이 쉘을 사용하면 MongoDB를 신속하고 쉽게 실행할 수 있다. 이 섹션에서는 쉘을 시작하는 방법을 배우고 예제를 통해 기본적인 데이터 저장 및 검색을 수행할 수 있는 몇 가지 기본적인 명령을 살펴본다.

MongoDB 쉘

MongoDB 쉘 애플리케이션은 bin 폴더에 MongoDB 배포판과 함께 포함되어 있다. Windows에서는 이 쉘이 애플리케이션(mongo.exe)으로 존재한다. Windows 탐색기에서 이 프로그램을 두 번 클릭하면 쉘이 시작된다. 위에 있는 지시사항을 따라 MongoDB 디렉토리를 해당 경로에 추가했다고 가정하면 UNIX® 기반 운영 체제(Mac OS X 포함)에서는 터미널 창에서 mongo 명령을 실행하여 MongoDB 쉘을 시작할 수 있다.

먼저 쉘을 실행하면 목록 7에 있는 메시지가 표시된다.


목록 7. 쉘을 실행 한 후 표시되는 메시지
MongoDB shell version: 1.8.1
connecting to: test
> 

이제 로컬 MongoDB 서버(특히 "test" 데이터베이스)에 연결된다. 다음 섹션에서는 데이터베이스, 문서 및 콜렉션을 작성하는 방법을 배운다. 어떤 단계에서든 도움이 필요하면 Mongo 쉘 프롬프트에서 간단히 "help" 명령을 실행한다. 그림 1에는 help 명령을 실행했을 때 표시되는 일반적인 결과물이 표시되어 있다.


그림 1. Mongo 쉘에서 help 명령을 실행했을 때의 결과물
Mongo 쉘에서 help 명령을 실행했을 때의 결과물 

MongoDB 함수의 소스 코드를 알고 싶으면 쉘에서 해당 함수의 이름을 입력하기만 하면 해당하는 Javascript 소스가 표시된다. 예를 들면,connect를 입력하고 리턴 키를 누르면 MongoDB 데이터베이스에 연결하는 데 사용된 소스 코드가 표시된다.

데이터베이스 콜렉션 및 문서 작성

기본적으로 Mongo 쉘은 "test" 데이터베이스에 연결된다. 다른 데이터베이스로 전환하려면 "use dbname" 명령을 사용한다. 데이터베이스가 존재하지 않는 경우에는 데이터를 데이터베이스에 추가하는 즉시 MongoDB에서 데이터베이스가 작성된다. >use mymongo 명령을 사용하여 "mymongo" 데이터베이스로 전환한다.

쉘에서 switched to db mymongo 메시지가 리턴된다.

이 시점에서는 데이터베이스에 데이터가 없으므로 사실상 아직은 데이터베이스가 존재하지 않는다. MongoDB에서는 데이터가 콜렉션에 저장되므로 필요한 경우에는 문서를 분리할 수 있다. 문서를 작성하여 다음과 같이 새 콜렉션("colors")에 저장해 본다. > db.colors.save({name:"red",value:"FF0000"});.

다음과 같이 데이터베이스를 쿼리하여 문서가 저장되었는지 확인한다. > db.colors.find();.

다음과 같은 응답이 표시된다(_id 속성은 고유한 식별자로 결과마다 다를 수 있음). { "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "red", "value" : "FF0000" }.

MongoDB에서는 문서가 BSON(2진 JSON)으로 저장된다. Mongo 쉘을 사용하는 경우에는 JSON 형태의 구문을 사용하여 데이터를 삽입할 수 있으며 여기에서는 각 문서가 키/값 쌍으로 구성된 하나의 오브젝트이다. 이 예제에서는 값이 각각 red FF0000(표준 빨간색의 16진 표현)인 name  value 속성이 있는 문서를 작성했다.

알고 있을지 모르지만, colors 콜렉션을 사전 정의할 필요는 없었으며 이러한 작업은 save 함수를 사용하여 항목을 삽입할 때 자동으로 수행된다.

이 예제에서는 매우 간단한 문서를 작성했다. 그러나 사용된 JSON 형태의 구문은 더 복잡한 문서를 작성하는 데 사용될 수 있다. 구매 주문이나 송장을 표현하는 다음 JSON 문서를 생각해 보자(목록 8 참조).


목록 8. 간단한 문서 작성
{
    order_id: 109384,
    order_date: new Date("12/04/2010"),
    customer: {
        name: "Joe Bloggs",
        company: "XYZ Inc.",
        phone: "(555) 123-4567"
    },
    payment: {
        type: "Cash",
        amount: 4075.99,
        paid_in_full: true
    },
    items: [
        {
            sku: "ABC1200",
            description: "A sample product",
            quantity: 1,
            price_per_unit: 75.99,
        }, {
            sku: "XYZ3400",
            description: "An expensive product",
            quantity: 2,
            price_per_unit: 2000
        }
    ],
    cashier_id: 340582242
}

아는 바와 같이 이러한 문서에는 문자열, 정수, 부동수, 날짜, 오브젝트, 배열 등과 같은 다양한 데이터 유형을 저장할 수 있다. 목록 8에서는 주문 품목을 주문 문서에 직접 삽입하며, 이렇게 하면 나중에 문서를 쿼리할 때 이 정보를 더 빠르게 검색할 수 있다.

MongoDB 쉘은 Javascript를 사용하므로 데이터베이스와 상호 작용할 때 일반 Javascript 구문을 작성할 수 있다. 목록 9에서는 문자의 문자열 표현과 문자와 연관된 ASCII 코드가 각각 포함된 문자 문서 콜렉션을 작성한다.


목록 9. 문자 문서 콜렉션 작성
> var chars = "abcdefghijklmnopqrstuvwxyz"
> for(var i =0; i<chars.length; i++) {    
... var char = chars.substr(i, 1);          
... var doc = {char:char, code: char.charCodeAt(0)};
... db.alphabet.save(doc);
... }

이 루프에서는 각 알파벳 소문자에 해당하는 문서가 26개 작성되며 각 문서에는 문자 자체와 문자의 ASCII 코드가 포함되어 있다. 다음 섹션에서는 다양한 방식으로 이 데이터를 검색하는 방법을 살펴본다.

데이터 검색하기

마지막 섹션에서는 MongoDB 데이터베이스에 데이터를 삽입하는 방법을 배울 뿐만 아니라 가장 기본적인 데이터 검색 함수인 find를 사용하는 방법을 배운다. 먼저, 이전 섹션의 마지막 부분에서 작성한 알파벳 콜렉션을 대상으로 다음과 같이 find 명령을 사용하자.db.alphabet.find();.

이렇게 하면 목록 10과 같은 응답이 생성된다.


목록 10. 생성된 응답
> db.alphabet.find()
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec90"), "char" : "e", "code" : 101 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f", "code" : 102 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g", "code" : 103 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h", "code" : 104 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i", "code" : 105 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec95"), "char" : "j", "code" : 106 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec96"), "char" : "k", "code" : 107 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec97"), "char" : "l", "code" : 108 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec98"), "char" : "m", "code" : 109 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec99"), "char" : "n", "code" : 110 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9a"), "char" : "o", "code" : 111 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9b"), "char" : "p", "code" : 112 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9c"), "char" : "q", "code" : 113 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9d"), "char" : "r", "code" : 114 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9e"), "char" : "s", "code" : 115 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9f"), "char" : "t", "code" : 116 }
has more
> 

기본적으로 find() 함수는 콜렉션에 있는 모든 문서를 검색하지만, 처음 20개의 문서만 표시한다. it 명령을 입력하면 나머지 문서 6개가 검색된다(목록 11 참조).


목록 11. 나머지 문서 6개 검색
> it
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca0"), "char" : "u", "code" : 117 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca1"), "char" : "v", "code" : 118 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca2"), "char" : "w", "code" : 119 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca3"), "char" : "x", "code" : 120 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca4"), "char" : "y", "code" : 121 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca5"), "char" : "z", "code" : 122 }
> 

사실상 find() 함수는 쿼리 결과 세트에 커서를 리턴하며, 이 경우에는 모든 문서를 검색한다. 이것을 변수에 지정하지 않거나 더 이상의 함수가 수행되지 않으면 기본적으로 샘플 결과 세트가 화면에 표시된다. >db.alphabet.find().forEach(printjson); 명령을 사용하여 모든 결과 세트를 표시할 수도 있다.

이렇게 하면 서브세트가 표시되는 대신 모든 레코드가 결과 세트로 표시된다. 다음 섹션에서는 커서와 쿼리를 사용하여 데이터를 필터링하는 방법을 자세히 본다.

데이터 쿼리

MongoDB의 가장 큰 강점 중 하나는 비록 테이블 대신 BSON 문서를 필터링하고 리턴하기는 해도 기존의 관계형 데이터베이스와 거의 같은 방식으로 작동하는 임시 쿼리를 강력하게 지원한다는 점이다. 이러한 방식이 SQL 개발자들이 이해하는 데 어려울 수도 있는 다른 문서 저장소와 MongoDB의 차이점이다. MongoDB를 사용하면 비교적 복잡한 SQL 쿼리를 Javascript 함수 호출로 쉽게 변환할 수 있다. 이번 섹션에서는 MongoDB에서 데이터를 쿼리할 때 사용되는 다양한 함수와 DB2, MySQL 또는 Oracle의 like에서와 같이 인덱스를 설정하여 쿼리를 최적화하는 방법을 배운다.

기본 쿼리

이전 섹션에서는 find 함수를 사용하여 모든 문서를 검색하는 방법을 배웠다. find 함수는 리턴된 결과를 필터링할 수 있는 일련의 인수를 받는다. 예를 들면, >db.alphabet.find({char: "o"}); 명령을 사용하여, 앞서 작성한 알파벳 콜렉션에서 "char" 속성값이 "q"인 모든 레코드를 찾을 수 있다.

이 명령은 { "_id" : ObjectId("4cfa4adf528bad4e29beec9a"), "char" : "o", "code" : 111 } 응답을 리턴한다.

코드가 100 이하인 모든 문자를 리턴하려면 다음 명령을 사용한다. >db.alphabet.find({code:{$lte:100}});.

예상하는 바와 같이 이 명령은 목록 12와 같은 결과를 리턴한다.


목록 12. 결과
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 }

MongoDB는 다음과 같은 다양한 조건부 연산자를 지원한다.

  • $lt(미만)
  • $lte(이하)
  • $gt(초과)
  • $gte(이상)
  • $all(배열에 있는 모든 값과 일치)
  • $exists(필드의 존재 여부 확인)
  • $mod(모듈)
  • $ne(같지 않음)
  • $in(배열에 있는 하나 이상의 값과 일치)
  • $nin(배열에 있는 0 값과 일치)
  • $or(쿼리 중 하나와 일치)
  • $nor(쿼리 중 어느 것과도 일치하지 않음)
  • $size(정의된 요소 수가 있는 배열과 일치)
  • $type(지정된 BSON 데이터 유형의 값과 일치)
  • $not(같지 않음)

이러한 모든 연산자를 자세히 확인하려면 MongoDB 문서를 참조한다(링크는 참고자료 참조).

find 함수의 두 번째 인수를 사용하여 쿼리에서 리턴되는 필드를 제한할 수 있다. 예를 들면, 다음 쿼리는 코드 값이 102 ~ 105 범위 안에 있는 모든 문서의 char 속성만을 리턴한다. > db.alphabet.find({code:{$in:[102,103,104,105]}}, {char: 1});.

이 쿼리의 결과는 목록 13과 같다.


목록 13. 결과
{ "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f" }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g" }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h" }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i" }

다음 섹션에서는 인덱스를 작성하여 쿼리 속도를 높이는 방법을 배운다.

인덱싱

MongoDB 인덱스는 관계형 데이터베이스 인덱스와 매우 비슷하다. 모든 속성에 인덱스를 삽입할 수 있다. 이외에도 인덱스화된 필드는 모든 데이터 유형(오브젝트 또는 배열 포함)이 될 수 있다. RDBMS 인덱스와 마찬가지로 다중 속성과 고유 인덱스를 사용하여 복합 인덱스를 작성할 수 있으며 이렇게 하면 값이 중복되지 않도록 할 수 있다.

기본 인덱스를 작성하려면 ensureIndex 함수를 사용한다. 이제 알파벳 콜렉션의 code char 속성을 대상으로 인덱스를 작성하자(목록 14참조).


목록 14. 인덱스 작성
> db.alphabet.ensureIndex({code: 1});
> db.alphabet.ensureIndex({char: 1});

dropIndex와 dropIndexes 함수를 사용하여 인덱스를 삭제할 수 있다. 자세한 내용은 MongoDB 문서를 참조한다.

정렬

결과 세트를 정렬하려면 해당 커서에 sort 함수를 적용한다. 알파벳 콜렉션은 이미 code와 char 속성으로 오름차순으로 정렬되어 있으므로 서브세트를 다시 code 속성으로 오름차순으로 정렬하자. > db.alphabet.find({code: {$gte: 118}}).sort({code: 0});.

이 쿼리는 목록 15와 같은 결과를 리턴한다.


목록 15. 결과
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca5"), "char" : "z", "code" : 122 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca4"), "char" : "y", "code" : 121 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca3"), "char" : "x", "code" : 120 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca2"), "char" : "w", "code" : 119 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca1"), "char" : "v", "code" : 118 }

이전 명령에서 sort 함수에 {code: 1} 인수를 제공하면 결과가 오름차순으로 정렬된다. 쿼리의 성능을 강화하려면 사용할 데이터를 정렬할 모든 속성에 인덱스를 추가해야 한다.

SKIP과 LIMIT를 사용하여 결과를 페이지로 나누기

데이터 결과 세트를 처리할 때는 아마도 결과를 페이지로 나누어서 웹 페이지에 표시하기 위해 한 번에 하나의 서브세트만 검색하고자 할 경우도 있다. MySQL에서는 LIMIT 키워드를 사용하여 이러한 작업을 수행한다. MongoDB에서는 skip과 limit 함수를 사용하여 이 기능을 쉽게 복제할 수 있다. 알파벳 콜렉션에서 처음 5개 문서를 리턴하려면 다음 조작을 수행한다. > db.alphabet.find().limit(5);.

이 조작은 목록 16과 같은 결과를 리턴한다.


목록 16. 결과
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec90"), "char" : "e", "code" : 101 }

다음 페이지를 얻으려면 다음 명령을 사용한다. > db.alphabet.find().skip(5).limit(5);.

목록 17에서 알 수 있는 바와 같이 이 명령은 다음 5개 레코드를 페치한다.


목록 17. 다음 5개 레코드 페치
{ "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f", "code" : 102 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g", "code" : 103 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h", "code" : 104 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i", "code" : 105 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec95"), "char" : "j", "code" : 106 }

group 함수와 수집

MongoDB의 쿼리 엔진을 이용하면 해당 데이터에 수집 및 그룹 함수를 매우 간단하게 적용할 수 있다. 이러한 기능은 다른 데이터베이스의 해당 SQL 기능과 비슷하다. 이론의 여지가 있지만, 가장 널리 사용되는 함수는 count() 함수이다. > db.alphabet.find().count();.

이 명령은 26을 리턴한다. 필터링된 쿼리를 다음과 같이 쉽게 계수할 수 있다. > db.alphabet.find({code: {$gte: 105}}).count();.

위에 있는 명령문은 18을 리턴한다.

또 다른 유용한 수집 함수는 distinct이다. 이 함수는 고유한 속성값 세트를 리턴하기 위해 사용된다. 알파벳 콜렉션은 모든 데이터가 고유하기 때문에 예제로서 적합하지 않다. 그러므로 이 기사의 앞 부분에서 작성한 colors 콜렉션에 레코드 두 개를 추가한다(목록 18 참조).


목록 18. color 콜렉션에 레코드 추가
> db.colors.save({name:"white",value:"FFFFFF"});
> db.colors.save({name:"red",value:"FF0000"});  
> db.colors.find();

colors 콜렉션을 삭제하지 않았다고 가정하면 목록 19와 같은 응답이 표시된다.


목록 19. 응답
{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "red", "value" : "FF0000" }
{ "_id" : ObjectId("4cfa5830528bad4e29beeca8"), "name" : "white", "value" : "FFFFFF" }
{ "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" }

아는 바와 같이 이 콜렉션에는 분명히 빨간색 문서가 두 개 있다. 이제, distinct 함수를 사용하여 이 콜렉션에서 고유한 name 속성값을 가져온다. > db.colors.distinct("name");.

이 명령은 [ "red", "white" ]를 리턴한다.

다른 쿼리 함수를 수행하므로 커서나 결과 세트에 대해서는 distinct 함수를 수행하지 않고 콜렉션을 대상으로 직접 distinct 함수를 수행한다. 또한, 이 함수가 문서 세트를 리턴하지 않고 값으로 구성된 배열을 리턴한다는 점을 알게 된다.

MongoDB는 SQL의 GROUP BY 표현식으로 하는 것과 같은 조치를 수행하는 데 필요한 group 함수를 제공한다. group 함수는 복잡하므로 여기에서는 간단한 예제만 살펴보도록 한다. 예를 들면, 이름 값으로 그룹화된 문서의 수를 계수한다고 가정한다. SQL에서는 이 표현식을 다음과 같이 정의할 수 있다. SELECT name, COUNT(*) FROM colors GROUP BY name;.

MongoDB에서 이 쿼리를 수행하려면 목록 20에 있는 명령을 사용해야 한다.


목록 20. group 함수 사용
> db.colors.group(
... {key: {name: true},
... cond: {},
... initial: {count: 0},                                  
... reduce: function(doc, out) { out.count++; }
... });

이 코드는 목록 21과 같은 결과를 생성한다.


목록 21. 결과
[
    {
        "name" : "red",
        "count" : 2
    },
    {
        "name" : "white",
        "count" : 1
    }
]

고급 수집 기능을 수행해야 하거나 대용량 데이터 세트를 사용해야 하는 경우, MongoDB에는 이러한 기능을 수행할 수 있는 map/reduce 구현이 포함되어 있다. 위에서 언급한 group 함수는 공유된 MongoDB 설정에서는 작동하지 않으므로 샤딩을 사용할 경우에는 group 함수 대신map/reduce를 사용해야 한다.

기존 데이터 업데이트

MongoDB 쉘에서는 문서를 업데이트하기가 매우 쉽다. 앞서 작성한 colors 콜렉션에는 red에 해당하는 레코드가 두 개 있었다. 이 레코드 중 하나를 취하여 값 속성이 000000(검정색의 16진 값)인 black으로 변경한다고 가정한다. 먼저, findOne 함수를 사용하여 값이 red인 단일 항목을 검색하고 필요에 따라 그 특성을 변경하고 해당 문서를 다시 데이터베이스에 저장할 수 있다.

이름이 red인 단일 문서를 가져와서 다음과 같이 blackDoc 변수에 저장한다. > var blackDoc = db.colors.findOne({name: "red"});.

다음에는 점 표기법을 사용하여 문서의 특성을 변경한다(목록 22 참조).


목록 22. 문서의 특성 변경

> blackDoc.name = "black";
> blackDoc.value = "000000";

문서를 저장하기 전에 다음과 같이 문서가 올바른지 확인한다. (문서에는 _id 속성이 있어야 한다. 그렇지 않으면 문서가 red 레코드를 덮어서 저장되지 않고 새 레코드로 삽입된다.) > printjson(blackDoc);

목록 23과 같은 결과가 리턴되면 준비가 된 것이다.


목록 23. 결과
{
    "_id" : ObjectId("4cfa43ff528bad4e29beec57"),
    "name" : "black",
    "value" : "000000"
}

마지막으로 save 함수를 사용하여 문서를 다시 데이터베이스의 colors 콜렉션에 저장한다. > db.colors.save(blackDoc);.

이제 find 함수를 사용하여 콜렉션이 올바른지 확인할 수 있다. > db.colors.find();.

그러면 목록 24와 같은 결과가 리턴된다. 레코드가 4개이면 잘못된 것이다.


목록 24. 결과
{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "black", "value" : "000000" }
{ "_id" : ObjectId("4cfa5830528bad4e29beeca8"), "name" : "white", "value" : "FFFFFF" }
{ "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" }

Mongo 쉘 외부에서는 애플리케이션에서 update 함수를 사용하여 기존 데이터를 변경한다. update 함수에 대한 자세한 정보는 MongoDB 문서를 참조한다.

데이터 삭제

MongoDB에서 데이터를 삭제하려면 remove 함수를 사용한다. 이는 MongoDB 쉘 프로그램에도 적용되며, 일부 드라이버가 delete 함수를 구현할 수도 있고 그렇지 않을 수도 있다. 필요한 경우에는 특정 구현에 대한 문서를 확인한다.

remove 함수는 find 함수와 비슷하게 작동한다. colors 콜렉션에서 이름이 white인 문서와 일치하는 문서를 제거하려면 다음 명령을 사용한다. > db.colors.remove({name:"white"});.

그런 다음, 다음과 같이 이 문서가 제거되었는지 확인한다. > db.colors.find();.

모든 것이 제대로 되면 문서 두 개만 표시된다(목록 25 참조).


목록 25. 데이터 삭제
{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "black", "value" : "000000" }
{ "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" }

콜렉션에서 모든 문서를 제거하려면 다음과 같이 명령에서 필터를 생략한다. > db.colors.remove();.

이제는 다음과 같이 find 함수를 사용하려고 해도 응답이 표시되지 않으며 이는 결과 세트가 없다는 것을 의미한다. > db.colors.find();.

변수에 문서를 저장한 경우에는 이 문서를 remove 함수에 전달하여 문서를 삭제할 수 있지만, 이렇게 하는 것은 효과적인 방법이 아니다. 그 대신 이 문서의 _id 속성을 찾아서 remove 함수에 전달하는 것이 더 나은 방법이다.

콜렉션을 삭제하려면 다음 명령을 사용한다. > db.colors.drop();.

이 명령은 true를 리턴한다.

이제 show collections 명령을 사용하여 실제로 콜렉션이 삭제되었는지 확인한다. 그러면 목록 26과 같은 결과가 표시된다.


목록 26. show collections 명령 사용
alphabet
system.indexes

마지막으로 전체 데이터베이스를 제거할 경우에는 다음 명령을 수행한다. > db.dropDatabase();.

이 명령은 현재 선택된 데이터베이스를 삭제한다. 다음과 같은 결과가 표시된다. { "dropped" : "mymongo", "ok" : 1 }.

show dbs 명령을 사용하여 사용 가능한 데이터베이스 목록을 확인한다. mymongo는 이 목록에 표시되지 않는다.

도구와 기타 기능

MongoDB에는 데이터베이스를 관리하는 데 필요한 일련의 유용한 유틸리티가 포함되어 있다. 또한, MongoDB에는 보고나 백업을 위해 데이터를 가져오거나 내보낼 수 있는 다양한 수단이 있다. 이번 섹션에서는 파일을 JSON 형식으로 가져오거나 내보내는 방법과 복구를 하는 데 더욱 효과적인 핫 백업 파일을 작성하는 방법을 알아본다. 또한, map/reduce 함수를 복잡한 데이터 수집에 필요한 Mongo의 일반 쿼리 함수의 대체 수단으로 사용하는 방법을 배운다.

데이터 가져오기 및 내보내기

MongoDB의 bin 디렉토리에는 다양한 형식으로 데이터를 가져오고 내보낼 수 있는 일련의 유틸리티가 있다. mongoimport 유틸리티를 이용하면 각 행에 JSON, CSV 또는 TSV 형식의 문서가 포함되어 있는 파일을 제공하고 이러한 각 문서를 MongoDB 데이터베이스에 삽입할 수 있다. MongoDB에서는 BSON 형식을 사용하므로 JSON 문서를 가져올 경우, 일반 JSON으로는 사용 불가능한, BSON의 추가 데이터 형식을 이용하려면 수정자 정보를 일부 제공해야 한다.

mongoexport 유틸리티를 이용하면 JSON이나 CSV 형식으로 표현된, MongoDB 데이터베이스의 모든 문서가 있는 파일 결과물을 생성할 수 있다. 이 유틸리티는 애플리케이션에서 JSON이나 CSV 데이터를 입력으로 받아서 보고서를 생성하는 데 유용하다. CSV 파일을 생성하려면 결과 파일에 표시되는 순서에 해당 필드를 제공해야 한다.

데이터베이스 백업 및 복원

mongoimport 및 mongoexport 유틸리티는 MongoDB에서 데이터를 가져와서 다른 애플리케이션에서 사용하거나 JSON 또는 CSV 데이터를 사용 가능하게 할 수 있는 다른 애플리케이션에서 데이터를 가져오는 데 유용하다. 그러나 이러한 유틸리티는 MongoDB 데이터베이스를 주기적으로 백업하거나 복원하는 데는 사용되지 않는다. MongoDB에서는 JSON이나 CSV 대신 BSON을 사용하기 때문에 이러한 형식으로 데이터를 가져올 경우에는 데이터 유형을 유지하기가 어렵다.

적당한 백업 및 복원 기능을 제공하기 위해 MongoDB는 두 가지 유틸리티(mongodump 및 mongorestore)를 제공한다. mongodump는 데이터베이스의 2진 백업 파일을 생성하며 mongorestore는 이 파일을 읽어서 이 파일을 사용하는 데이터베이스를 복원하고 필요에 따라 자동으로 인덱스를 작성한다(백업 디렉토리에서 system.indexes.bson 파일을 제거하지 않는 한).

관리 유틸리티

또한, MongoDB는 웹 기반 진단 인터페이스를 제공하며, MongoDB가 기본값으로 구성된 경우에는 이 인터페이스를http://localhost:28017/ URL에서 이용할 수 있다. 이 화면은 그림 2에 있는 스크린샷과 같다.


그림 2. MongoDB의 진단 인터페이스
MongoDB의 진단 인터페이스 

기타 관리 정보를 얻으려면 MongoDB 쉘에서 다음 명령을 실행한다.

  • db.serverStatus();
  • db.stats();

MongoDB 서버가 파손되는 경우에는 데이터베이스를 복구하여 손상이 없는지 확인하고 데이터 압축을 일부 수행한다. OS 명령행에서 mongod --repair를 실행하거나 MongoDB 쉘에서 db.repairDatabase(); 명령을 사용하여 복구를 실행할 수 있다. 후자는 데이터베이스 레벨에 따라 실행되므로 해당 서버에서 각 데이터베이스를 대상으로 이 명령을 실행해야 한다.

또한, 유효성 검증 함수를 사용하여 콜렉션 데이터의 유효성을 검증할 수 있다. contacts라는 콜렉션이 있는 경우에는db.contacts.validate(); 명령을 사용하여 콜렉션의 유효성을 검증할 수 있다.

이외에도 MongoDB에는 DBA에게 도움이 되는 기능이 많이 있다. 이외에도 다양한 써드파티 관리 도구와 인터페이스를 사용할 수 있다. 자세한 정보는 MongoDB 문서를 참조한다.

map/reduce

뷰 엔진은 기본적으로 map/reduce 함수를 사용하여 데이터를 필터링하고 수집하므로 이전에 CouchDB 데이터베이스를 사용한 적이 있으면map/reduce 함수에 익숙할 것이다. 그러나 MongoDB에서는 이렇게 하지 않으며 간단한 쿼리와 필터링 및 수집 기능은 map/reduce 함수에 의존하지 않는다. 그러나 MongoDB는 대용량 데이터 세트를 수집하는 데 사용할 수 있는 map/reduce 구현을 제공한다.

map/reduce는 그 자체로도 하나의 기사가 될 수 있다. 그러므로 MongoDB의 map/reduce 구현에 대한 자세한 정보는 MongoDB 문서를 참조한다(링크는 참고자료 참조).

MongoDB 확장

키/값 저장소와 문서 지향 데이터베이스가 최근에 널리 사용되는 기본적인 이유는 확장성이 우수하고 메모리를 적게 사용한다는 데 있다. 이러한 점을 활용하기 위해 MongoDB는 이번 섹션에서 배우게 될 샤딩과 복제 개념에 의존한다. 이외에도 GridFS를 사용하여 대용량 파일을 MongoDB에 저장하는 방법을 배운다. 마지막에는 쿼리를 프로파일링하여 데이터베이스의 성능을 최적화하는 방법을 배운다.

샤딩

데이터베이스 인프라의 핵심 부분은 확장성에 있다. MongoDB 구현은 자동 샤딩 메커니즘을 사용하여 수평으로 확장되며, 이 메커니즘을 이용하면 자동 로드 밸런싱, 단일 장애 지점 불허 및 자동 장애 복구 기능과 더불어 MongoDB 구성을 수천 개의 노드로 확장할 수 있다. MongoDB 클러스터에 시스템을 새로 추가하는 것도 매우 간단하다.

MongoDB의 자동 샤딩 기능의 장점은 애플리케이션 코드를 거의 변경하지 않고도 단일 서버에서 샤딩된 클러스터로 이동하기가 매우 간단하다. 자동 샤딩이 작동하는 과정과 자동 샤딩을 구현하는 방법과 관련된 자세한 문서는 MongoDB 문서를 참조한다.

복제

MongoDB는 장애 복구와 중복을 구현하기 위해 MySQL과 마찬가지로 마스터-슬레이브 구성의 복제 기능을 제공하며, 이 기능은 노드 간의 일관성을 높은 수준으로 보장한다. 또는 MongoDB에서는 복제 세트를 사용하여 언제든지 노드를 기본 노드로 정의할 수 있으며 장애가 발생했을 때는 또 다른 노드를 기본 노드로 대체할 수 있다.

복제를 기본으로 하여 확장을 하는 CouchDB와 달리, MongoDB에서는 슬레이브 노드를 중복 복제본으로 사용하여 고가용성을 보장하기 위해 주로 복제를 사용한다.

MongoDB 복제에 대한 자세한 정보는 MongoDB 문서를 참조한다(링크는 참고자료 참조).

GridFS를 사용하는 대용량 파일 스토리지

MongoDB 데이터베이스는 BSON 문서로 데이터를 저장한다. 그러나 BSON 문서의 최대 크기는 4MB이기 때문에 BSON 문서로 대용량 파일이나 오브젝트를 저장하는 것은 적합하지 않다. MongoDB에서는 GridFS 스펙을 사용하여 파일을 작은 청크로 나누고 다수의 문서에 분배하여 대용량 파일을 저장한다.

표준 MongoDB 배포판에는 GridFS 파일을 로컬 파일 시스템에 추가하거나 로컬 파일 시스템에서 GridFS 파일을 검색하는 데 필요한 명령행 유틸리티가 들어 있다. 이외에도 모든 공식 MongoDB API 드라이버에는 GridFS에 대한 지원이 포함되어 있다. 자세한 내용은 MongoDB 문서를 참조한다(참고자료 참조).

결론

이 기사에서는 MongoDB 데이터베이스 관리 시스템을 배웠으며 MongoDB가 DBMS 시장의 인기 있는 NoSQL 섹션에서 가장 빠르게 성장하는 옵션 중 하나인 이유를 알아 보았다. 또한, 기존의 RDBMS에 비해 문서 지향 데이터베이스를 선택하는 이유와 MongoDB에서 제공하는 여러 가지 우수한 기능을 배웠다. 더불어 MongoDB를 설치하는 방법과 MongoDB를 사용하여 데이터를 저장하고 검색하는 방법을 배웠을 뿐만 아니라 MongoDB에서 제공하는 다양한 도구와 확장성 옵션을 알아 보았다.


참고자료

교육

  • 공식 MongoDB 사이트를 방문하자. 

  • Wikipedia의 MongoDB 목록을 읽어보자. 

  • 공식 MongoDB 문서에 액세스할 수 있다. 

  • MongoDB map/reduce 함수를 자세히 배우자. 

  • MongoDB Cookbook에는 MongoDB를 사용하는 일반적인 방법이 자세히 설명되어 있다. 

  • Twitter의 MongoDB 페이지를 팔로우하자. 

  • developerWorks에 있는 "An introduction to MongoDB" 데모를 보자. 

  • developerWorks의 지식 경로를 통해 NoSQL을 사용하는 방법과 대용량 데이터를 분석하는 방법을 배우자. 

  • 한 회사에서 MySQL을 MongoDB로 전환한 방법을 확인하려면 Notes from a production MongoDB deployment를 읽어 본다. 

  • Collective Idea가 어떻게 전환했는지 배우려면 Reflections on MongoDB을 읽어보자. 

  • Wordnik이 어떻게 전환했는지 배우려면 12 Months with MongoDB 블로그를 읽어보자. 

  • Eltot Horowitz(MongoDB를 후원하는 회사인 10gen의 CTO)의 MongoDB 관련 팟캐스트를 들어보자. 

  • 10gen에서는 확장 가능한 고성능 문서 지향 오픈 소스 데이터베이스인 MongoDB를 개발하고 지원한다. 

  • Java development 2.0: MongoDB: A NoSQL datastore with (all the right) RDBMS moves(Andrew Glover, developerWorks, 2010년 9월): MongoDB의 사용자 정의 API, 대화식 쉘, RDBMS 스타일 동적 쿼리 및 빠르고 쉬운 MapReduce 계산에 관해 자세히 배우자. 

  • Exploring CouchDB(Joe Lennon, developerWorks, 2009년 3월): Apache의 오픈 소스 CouchDB는 스키마 없는 문서 지향 데이터베이스 모델로 부르는 것으로 데이터를 저장하는 새로운 방법을 제공한다. CouchDB는 관계형 모델의 고도로 구조화된 데이터 스토리지 대신, 반구조화된 문서로부터 구조화된 수집 및 보고 결과를 생성하는 데 필요한 Javascript 기반 뷰 모델을 사용하여 반구조화된 형식으로 데이터를 저장한다. 

  • 관심 이벤트: IBM 오픈 소스 개발자에게 유익한 컨퍼런스, 기술 박람회, 웹 캐스트 및 기타 행사를 확인하고 참여하자. 

  • developerWorks 오픈 소스 영역: 오픈 소스 기술을 사용하여 개발하고 이러한 기술을 IBM 제품과 함께 사용하는 데 도움이 되는 광범위한 사용법 정보, 도구 및 프로젝트 업데이트를 찾아보자. 

제품 및 기술

  • MongoDB를 다운로드하자. 

  • IBM 시험판 소프트웨어: 다운로드하거나 DVD로 이용할 수 있는 IBM 시험판 소프트웨어를 사용하여 차기 오픈 소스 개발 프로젝트를 강화하자. 

토론

  • developerWorks 커뮤니티: 개발자가 운영하고 있는 블로그, 포럼, 그룹 및 위키를 살펴보면서 다른 developerWorks 사용자와 의견을 나눌 수 있다. developerWorks 커뮤니티에서 Real world open source 그룹을 빌드하는 데 도움을 주자. 

필자소개

Joe Lennon

Joe Lennon은 소프트웨어 개발자로 24살이며 아일랜드 코크에 살고 있다. Joe Lennon은 Beginning CouchDB의 저자이며, 이 책은 Apress에서 출간될 예정이다. 그는 여러 개의 기술 관련 기사와 튜토리얼을 IBM developerWorks에 기고했다. 한가로운 때에는 축구를 하거나 가젯을 조작하며 Xbox 360 게이머 점수를 높이기 위해 노력한다. 그의 웹 사이트 주소는www.joelennon.ie이다.


출처 - http://www.ibm.com/developerworks/kr/library/os-mongodb4/index.html



'DB > MongoDB' 카테고리의 다른 글

mongodb - mongod.conf(web interface enable)  (0) 2013.05.19
mongo - 보안 및 계정 관리  (0) 2013.04.30
mongodb - Hadoop과 연동한 구축사례  (0) 2013.04.29
mongodb - 고려 사항  (0) 2013.04.29
mongodb wiki intro  (0) 2013.01.07
Posted by linuxism
,