MongoDB



[MongoDB] 강좌 6편 Index 설정

[MongoDB] 강좌 6편 Index 설정

MongoDB
블로그 바로가기! 이번 강좌는 MongoDB의 Index에 관한 내용입니다. Index란? Index는 MongoDB에서 데이터 쿼리를 더욱 효율적으로...
Read More
[MongoDB] 강좌 5편 Document 수정 – update() 메소드

[MongoDB] 강좌 5편 Document 수정 – update() 메소드

MongoDB
블로그 바로가기! 이번 강좌에서는 document를 수정하는 update() 메소드에 대하여 알아보도록 하겠습니다. 정의 MongoDB에서는 update() 메소드를...
Read More
[MongoDB] 강좌 4편 find() 메소드 활용 – sort(), limit(), skip()

[MongoDB] 강좌 4편 find() 메소드 활용 – sort(), limit(), skip()

MongoDB
블로그바로가기! 이번 강좌에선 find() 메소드를 더욱 더 활용하기 위해 필요한 sort(), limit(), skip() 메소드에 대해...
Read More
[MongoDB] 강좌 3편 Document Query(조회) – find() 메소드

[MongoDB] 강좌 3편 Document Query(조회) – find() 메소드

MongoDB
블로그 바로가기! 이번 강좌에선 Document를 조회하는 메소드인 find() 메소드를 자세히 알아보도록 하겠습니다. Document 조회: db.COLLECTION_NAME.find(query,...
Read More
[MongoDB] 2편: Database/Collection/Document 생성·제거

[MongoDB] 2편: Database/Collection/Document 생성·제거

MongoDB
블로그 바로가기! 이번 강좌에서는 Database, Collection, Document 를 생성하는 명령어와 제거하는 명령어를 배워보도록 하겠습니다. 이...
Read More
[MongoDB] 1편: 소개, 설치 및 데이터 모델링

[MongoDB] 1편: 소개, 설치 및 데이터 모델링

MongoDB
메인 블로그 바로가기! 1편: 소개, 설치 및 데이터 모델링 블로그 바로가기 소개 MongoDB는 C++로 작성된...
Read More
[MongoDB] 강좌 6편 Index 설정
MongoDB

[MongoDB] 강좌 6편 Index 설정

블로그 바로가기!

이번 강좌는 MongoDB의 Index에 관한 내용입니다.

Index란?
Index는 MongoDB에서 데이터 쿼리를 더욱 효율적으로 할 수 있게 해줍니다. 인덱스가 없이는, MongoDB는 collection scan – 컬렉션의 데이터를 하나하나 조회 – 방식으로 스캔을 하게 됩니다. 만약 document의 갯수가 매우 많다면, 많은 만큼 속도가 느려지겠죠? 이 부분을 향상시키기 위하여 인덱스를 사용하면 더 적은 횟수의 조회로 원하는 데이터를 찾을 수 있습니다.

Document의 필드(들) 에 index 를 걸면, 데이터의 설정한 키 값을 가지고 document들을 가르키는 포인터값으로 이뤄진 B-Tree를 만듭니다. 여기서 B-Tree는 Balanced Binary search Tree 인데요, B-Tree 에서 Binary Search를 통하여 쿼리 속도를 매우 빠르게 향상 시킬 수 있습니다. Balanced Binary Tree / Binary Search 키워드에 대해선 자료구조를 공부하신 분들이라면 익숙하겠지만 그렇지 않은 분들을 위해 한번 간단하게 원리를 설명해보겠습니다.

만약에 숫자가 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 가 있을 때 이 중에서 14를 찾는다고 한다면, Index가 없을때는 1부터 14까지 쭉 조회를 하여 14를 찾아냅니다.

하지만 Index가 있을땐 다음과 같은 B-Tree를 만듭니다. ( B-Tree가 만들어지는 과정은 생략하겠습니다. )

Untitled-7

이 트리를 간단하게 설명해드리자면, 특정 값보다 작은 값은 왼쪽에, 큰 값은 오른쪽에 위치하는 규칙을 가지고 있는데요.

이 트리를 사용하여 14를 찾을땐 8 → 12 → 14 이렇게 3번의 조회만에 14를 찾을 수 있게됩니다.

그리고, 순회 알고리즘을 사용하여 가장 낮은값부터 가장 큰 값 까지 매우 효율적으로 정렬도 할 수 있습니다.bintree-traverse

자, 이제 원리를 이해하였다면 MongoDB에서 인덱스를 사용하는 방법을 배워보겠습니다.

Index의 종류
기본 인덱스 _id
모든 MongoDB의 컬렉션은 기본적으로 _id 필드에 인덱스가 존재합니다. 만약에 컬렉션을 만들 때 _id 필드를 따로 지정하지 않으면 mongod드라이버가 자동으로 _id 필드 값을 ObjectId로 설정해줍니다.

_id 인덱스는 unique(유일)하고 이는 MongoDB 클라이언트가 같은 _id 를 가진 문서를 중복적으로 추가하는 것을 방지합니다.

Single(단일) 필드 인덱스
MongoDB 드라이버가 지정하는 _id 인덱스 외에도, 사용자가 지정 할 수 있는 단일 필드 인덱스가 있습니다.

다음 이미지 처럼 score 값으로 정렬 할 수 있지요.

Diagram of an index on the “score“ field (ascending).
Compound (복합) 필드 인덱스
두개 이상의 필드를 사용하는 인덱스를 복합 인덱스라고 부릅니다. 다음 이미지와 같이 첫번째 필드 (userid)는 오름차순으로, 두번째 필드 (score)는 내림차순으로 정렬 해야 하는 상황이 있을때 사용합니다.

Diagram of a compound index on the “userid“ field (ascending) and the “score“ field (descending). The index sorts first by the “userid“ field and then by the “score“ field.
Multikey 인덱스
필드 타입이 배열인 필드에 인덱스를 적용 할 때는 Multikey 인덱스가 사용됩니다. 이 인덱스를 통하여 배열에 특정 값이 포함되어 있는 document를 효율적으로 스캔 할 수 있습니다.Diagram of a multikey index on the “addr.zip“ field. The “addr“ field contains an array of address documents. The address documents contain the “zip“ field.

Geospatial(공간적) Index
지도의 좌표와 같은 데이터를 효율적으로 쿼리하기 위해서 (예: 특정 좌표 반경 x 에 해당되는 데이터를 찾을 때) 사용되는 인덱스입니다. 자세한 사항은 매뉴얼을 참고해주세요.

Text 인덱스
텍스트 관련 데이터를 효율적으로 쿼리하기 위한 인덱스입니다. 자세한 사항은 매뉴얼 Text Indexes 을 참고하세요.

해쉬 (hashed) 인덱스
이 인덱스를 사용하면 B Tree가아닌 Hash 자료구조를 사용합니다. Hash는 검색 효율이 B Tree보다 좋지만, 정렬을 하지 않습니다.

인덱스 생성
인덱스를 생성 할 땐, 다음과 같은 createIndex() 메소드를 사용합니다. 파라미터는 인덱스를 적용할 필드를 전달합니다. 값을 1로하면 오름차순으로, -1로 하면 내림차순으로 정렬합니다.

db.COLLECTION.createIndex( { KEY: 1 } )
다양한 예제를 통하여 인덱스 생성을 배워보도록 하겠습니다.

예제1 단일 필드 인덱스 생성

db.report.createIndex( { score: 1 } )
score 필드에 인덱스를 걸어줍니다.

이 인덱스는 다음과 같은 쿼리를 할 때 효율적으로 실행하게 해줍니다.

db.report.find( { score: 57 } )
db.report.find( { score: { $gt: 60 } } )
예제2 복합 필드 인덱스 생성

db.report.createIndex( { age: 1, score: -1} )
이렇게 여러 필드를 넣어 인덱스를 생성하면 age를 오름차순으로 정렬한 상태에서 score 는 내림차순으로 정렬합니다.

인덱스 속성
인덱스에 속성을 추가 할 땐 createIndex() 메소드의 두번째 인자에 속성값을 document 타입으로 전달해주면 됩니다.

db.COLLECTION.createIndex( { KEY: 1 }, { PROPERTY: true } )
인덱스에 적용 할 수 있는 4가지 속성이 있는데요, 한번 이에 대해 알아보고, 예제를 통해 사용법을 배워보도록 하겠습니다.

Unique (유일함) 속성
_id 필드처럼 컬렉션에 단 한개의 값만 존재 할 수 있는 속성입니다.

예제3 email 인덱스에 unique 속성 적용

db.userinfo.createIndex( { email: 1 }, { unique: true } )
unique 속성은 다음처럼 복합 인덱스에도 적용 할 수 있습니다.

예제4 firstName 과 lastName 복합인덱스에 unique 속성 적용

db.userinfo.createIndex( { firstName: 1, lastName: 1 }, { unique: true } )
Partial (부분적) 속성
partial 속성은 document의 조건을 정하여 일부 document에만 인덱스를 적용 할 때 사용됩니다.

partial 속성을 사용하면, 필요한 부분에만 인덱싱을 사용하여 저장공간도 아끼고 속도를 더 높일수 있습니다.

예제5 visitors 값이 1000 보다 높은 document에만 name 필드에 인덱스 적용

db.store.createIndex(
{ name: 1 },
{ partialFilterExpression: { visitors: { $gt: 1000 } } }
)
예제6 TLL 속성
이 인덱스 속성은 Date 타입, 혹은 Date 배열 타입의 필드에 적용 할 수 있는 속성입니다. 이 속성을 사용하여 document를 expire(만료) 시킬 수 있습니다. 즉, 추가하고 특정 시간이 지나면, document 를 컬렉션에서 제거합니다.

예제: notifiedDate 가 현재 시각과 1시간 이상 차이나면 제거

db.notifications.createIndex( { “notifiedDate”: 1 }, { expireAfterSeconds: 3600 } )

document가 만료되어 제거 될 때, 시간이 아주 정확하지는 않습니다. 만료되는 document를 제거하는 thread는 매 60초마다 실행됩니다. 이점 유의해주세요.

인덱스 조회
생성된 인덱스를 조회 할 땐 getIndexes() 메소드를 사용합니다.

db.COLLECTION.getIndexes()

인덱스 제거
인덱스를 제거 할 땐 dropIndex() 메소드를 사용합니다.

db.COLLECTION.dropIndex( { KEY: 1 } )

( _id 인덱스를 제외한 ) 모든 인덱스를 제거 할 땐 dropIndexes() 메소드를 사용합니다.

마무리하며..
강좌 6편을 끝으로 MongoDB 기초 연재 강좌를 마치겠습니다. 다음 강좌부터는 팁 위주로 올리도록 하겠습니다. 감사합니다.

[MongoDB] 강좌 5편 Document 수정 – update() 메소드
MongoDB

[MongoDB] 강좌 5편 Document 수정 – update() 메소드

블로그 바로가기!

이번 강좌에서는 document를 수정하는 update() 메소드에 대하여 알아보도록 하겠습니다.

정의
MongoDB에서는 update() 메소드를 통하여 데이터를 수정 할 수 있습니다. 이 메소드의 구조는 다음과 같습니다:

db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
Collection 안의 document(들)을 수정합니다. 이 메소드를 통하여 특정 field 를 수정 할 수도 있고 이미 존재하는 document를 대체(replace) 할 수도 있습니다.

update() 메소드의 기본 옵션으로는 단 하나의 document를 수정합니다.

Parameter Type 설명
*query document 업데이트 할 document의 criteria 를 정합니다. find() 메소드 에서 사용하는 query 와 같습니다.
*update document document에 적용할 변동사항입니다.
upsert boolean Optional. (기본값: false) 이 값이 true 로 설정되면 query한 document가 없을 경우, 새로운 document를 추가합니다.
multi boolean Optional. (기본값: false) 이 값이 true 로 설정되면, 여러개의 document 를 수정합니다.
writeConcern document Optional. wtimeout 등 document 업데이트 할 때 필요한 설정값입니다. 기본 writeConcern을 사용하려면 이 파라미터를 생략하세요. 자세한 내용은 매뉴얼을 참조해주세요.

샘플 데이터 추가
update 메소드를 연습해보기 위해 샘플 데이터를 추가하세요.

db people insert( [
{ name: “Abet”, age: 19 },
{ name: “Betty”, age: 20 },
{ name: “Charlie”, age: 23, skills: [ “mongodb”, “nodejs”] },
{ name: “David”, age: 23, score: 20 }
])
이제 예제를 통하여 update() 메소드 사용법을 배워보도록 하겠습니다.

예제1. 특정 field 업데이트 하기

// Abet document 의 age를 20으로 변경한다
> db.people.update( { name: “Abet” }, { $set: { age: 20 } } )
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })
특정 field의 값을 수정할 땐 $set 연산자를 사용합니다. 이 연산자를 사용해서 똑같은 방법을 새로운 field를 추가 할 수도 있습니다.

예제2. document를 replace 하기

// Betty document를 새로운 document로 대체한다.
> db.people.update( { name: “Betty” }, { “name”: “Betty 2nd”, age: 1 })
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })
이렇게 새로운 document 로 replace 할 때, _id는 바뀌지 않습니다.

예제3. 특정 field를 제거하기

// David document의 score field를 제거한다
> db.people.update( { name: “David” }, { $unset: { score: 1 } } )
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })
여기서 score: 1 의 1 은 true 의 의미입니다.

예제4. criteria에 해당되는 document가 존재하지 않는다면 새로 추가하기

// upsert 옵션을 설정하여 Elly document가 존재하지 않으면 새로 추가
> db.people.update( { name: “Elly” }, { name: “Elly”, age: 17 }, { upsert: true } )
WriteResult({
“nMatched” : 0,
“nUpserted” : 1,
“nModified” : 0,
“_id” : ObjectId(“56c893ffc694e4e7c8594240”)
})
예제5. 여러 document의 특정 field를 수정하기

// age가 20 보다 낮거나 같은 document의 score를 10으로 설정
> db.people.update(
… { age: { $lte: 20 } },
… { $set: { score: 10 } },
… { multi: true }
… )
WriteResult({ “nMatched” : 3, “nUpserted” : 0, “nModified” : 0 })
예제6-1. 배열 에 값 추가하기

// Charlie document의 skills 배열에 “angularjs” 추가
> db.people.update(
… { name: “Charlie” },
… { $push: { skills: “angularjs” } }
… )
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })
예제6-2. 배열에 값 여러개 추가하기 + 오름차순으로 정렬하기

// Charlie document의 skills에 “c++” 와 “java” 를 추가하고 알파벳순으로 정렬
> db.people.update(
… { name: “Charlie” },
… { $push: {
… skills: {
… $each: [ “c++”, “java” ],
… $sort: 1
… }
… }
… }
… )
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })
$sort 값을 내림차순으로 정렬하려면 -1 로 하면 됩니다.

배열이 document의 배열이고 그 embedded document의 특정 field에 따라서 정렬을 할 때는 다음과 같이 설정하면 됩니다.

$sort: { KEY: 1 }
예제7-1. 배열에 값 제거하기

// Charlie document에서 skills 값의 mongodb 제거
> db.people.update(
… { name: “Charlie” },
… { $pull: { skills: “mongodb” } }
… )
예제7-2. 배열에서 값 여러개 제거하기

// Charlie document에서 skills 배열 중 “angularjs” 와 “java” 제거
> db.people.update(
… { name: “Charlie” },
… { $pull: { skills: { $in: [“angularjs”, “java” ] } } }
… )
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })

마무리하면서…
데이터를 수정하는 웬만한 케이스를 모두 다뤄보았습니다. 그러나 물론, 이 글에서 설명되지 않은 케이스들도 어느정도 있답니다. 위에 해당하지 않는 케이스가 있을 경우엔 매뉴얼을 참조해주세요.

다음 강좌에선 데이터 쿼리의 성능을 효율적으로 높여주는 Index 에 대하여 알아보도록 하겠습니다.

[MongoDB] 강좌 4편 find() 메소드 활용 – sort(), limit(), skip()
MongoDB

[MongoDB] 강좌 4편 find() 메소드 활용 – sort(), limit(), skip()

블로그바로가기!

이번 강좌에선 find() 메소드를 더욱 더 활용하기 위해 필요한 sort(), limit(), skip() 메소드에 대해 배워보겠습니다. 그냥 find() 메소드를 사용하면 criteria 에 일치하는 모든 document 들을 출력해주기 때문에, 예를들어 페이지 같은 기능을 사용한다면 불적합하겠죠. 그렇다고 find() 메소드 자체에 어디부터 어디까지 불러오겠다 라고 설정하는 매개변수는 따로 없습니다.

find() 메소드를 사용했을 시 cursor 형태의 결과값을 반환하는데요, 이 객체가 가지고 있는 limit() 메소드와 skip() 메소드를 통하여 보이는 출력물의 갯수를 제한 할 수 있고, sort() 메소드를 사용하여 데이터를 순서대로 나열 할 수 있습니다.

샘플 데이터
쿼리 연습을 해보기 위해 샘플데이터를 추가하세요.

[
{ “_id”: 1, “item”: { “category”: “cake”, “type”: “chiffon” }, “amount”: 10 },
{ “_id”: 2, “item”: { “category”: “cookies”, “type”: “chocolate chip” }, “amount”: 50 },
{ “_id”: 3, “item”: { “category”: “cookies”, “type”: “chocolate chip” }, “amount”: 15 },
{ “_id”: 4, “item”: { “category”: “cake”, “type”: “lemon” }, “amount”: 30 },
{ “_id”: 5, “item”: { “category”: “cake”, “type”: “carrot” }, “amount”: 20 },
{ “_id”: 6, “item”: { “category”: “brownies”, “type”: “blondie” }, “amount”: 10 }
]
> use mongodb_tutorial
switched to db mongodb_tutorial
> db.orders.insert(
…. SAMPLE DATA
)
BulkWriteResult({
“writeErrors” : [ ],
“writeConcernErrors” : [ ],
“nInserted” : 6,
“nUpserted” : 0,
“nMatched” : 0,
“nModified” : 0,
“nRemoved” : 0,
“upserted” : [ ]
})
cursor.sort( DOCUMENT )
이 메소드는 데이터를 정렬할 때 사용됩니다. 매개변수로는 어떤 KEY 를 사용하여 정렬 할 지 알려주는 document 를 전달합니다.

이 document 의 구조는 다음과 같습니다.

{ KEY: value }
KEY 는 데이터의 field 이름이고, value 의 값은 1 혹은 -1 입니다. 이 값을 1로 설정하면 오름차순으로, -1로 하면 내림차순으로 정렬합니다.

또한 여러 KEY를 입력 할 수 있고 먼저 입력한 KEY가 우선권을 갖습니다.

예제1: _id 의 값을 사용하여 오름차순으로 정렬하기

> db.orders.find().sort( { “_id”: 1 } )
{ “_id” : 1, “item” : { “category” : “cake”, “type” : “chiffon” }, “amount” : 10 }
{ “_id” : 2, “item” : { “category” : “cookies”, “type” : “chocolate chip” }, “amount” : 50 }
{ “_id” : 3, “item” : { “category” : “cookies”, “type” : “chocolate chip” }, “amount” : 15 }
{ “_id” : 4, “item” : { “category” : “cake”, “type” : “lemon” }, “amount” : 30 }
{ “_id” : 5, “item” : { “category” : “cake”, “type” : “carrot” }, “amount” : 20 }
{ “_id” : 6, “item” : { “category” : “brownies”, “type” : “blondie” }, “amount” : 10 }
예제2: amount 값을 사용하여 오름차순으로 정렬하고, 정렬한 값에서 id 값은 내림차순으로 정렬하기

> db.orders.find().sort( { “amount”: 1, “_id”: -1 } )
{ “_id” : 6, “item” : { “category” : “brownies”, “type” : “blondie” }, “amount” : 10 }
{ “_id” : 1, “item” : { “category” : “cake”, “type” : “chiffon” }, “amount” : 10 }
{ “_id” : 3, “item” : { “category” : “cookies”, “type” : “chocolate chip” }, “amount” : 15 }
{ “_id” : 5, “item” : { “category” : “cake”, “type” : “carrot” }, “amount” : 20 }
{ “_id” : 4, “item” : { “category” : “cake”, “type” : “lemon” }, “amount” : 30 }
{ “_id” : 2, “item” : { “category” : “cookies”, “type” : “chocolate chip” }, “amount” : 50 }

cursor.limit( value )
이 메소드는 출력할 데이터 갯수를 제한할 때 사용됩니다. value 파라미터는 출력 할 갯수 값 입니다.

예제3: 출력 할 갯수를 3개로 제한하기

> db.orders.find().limit(3)
{ “_id” : 1, “item” : { “category” : “cake”, “type” : “chiffon” }, “amount” : 10 }
{ “_id” : 2, “item” : { “category” : “cookies”, “type” : “chocolate chip” }, “amount” : 50 }
{ “_id” : 3, “item” : { “category” : “cookies”, “type” : “chocolate chip” }, “amount” : 15 }

cursor.skip( value )
이 메소드는 출력 할 데이터의 시작부분을 설정할 때 사용됩니다. value 값 갯수의 데이터를 생략하고 그 다음부터 출력합니다.

예제4: 2개의 데이터를 생략하고 그 다음부터 출력

> db.orders.find().skip(2)
{ “_id” : 3, “item” : { “category” : “cookies”, “type” : “chocolate chip” }, “amount” : 15 }
{ “_id” : 4, “item” : { “category” : “cake”, “type” : “lemon” }, “amount” : 30 }
{ “_id” : 5, “item” : { “category” : “cake”, “type” : “carrot” }, “amount” : 20 }
{ “_id” : 6, “item” : { “category” : “brownies”, “type” : “blondie” }, “amount” : 10 }

응용
이 강좌에서 배운 메소드들의 반환값 역시 cursor 객체이기 때문에 위 메소드들을 중첩해서 사용 할 수 있습니다.

예제를 통하여 한번 응용 방법을 배워보겠습니다.

예제5: order 를 최신순으로 한 페이지당 2개씩 나타냅니다.

> var showPage = function(page){
… return db.orders.find().sort( { “_id”: -1 } ).skip((page-1)*2).limit(2);
… }
> showPage(1)
{ “_id” : 6, “item” : { “category” : “brownies”, “type” : “blondie” }, “amount” : 10 }
{ “_id” : 5, “item” : { “category” : “cake”, “type” : “carrot” }, “amount” : 20 }
> showPage(2)
{ “_id” : 4, “item” : { “category” : “cake”, “type” : “lemon” }, “amount” : 30 }
{ “_id” : 3, “item” : { “category” : “cookies”, “type” : “chocolate chip” }, “amount” : 15 }
> showPage(3)
{ “_id” : 2, “item” : { “category” : “cookies”, “type” : “chocolate chip” }, “amount” : 50 }
{ “_id” : 1, “item” : { “category” : “cake”, “type” : “chiffon” }, “amount” : 10 }

마무리하며…
이제 find() 메소드를 충분히! 활용 할 수 있게되었습니다.

다음 강좌에선 document를 수정하는 update() 메소드에 대하여 알아보겠습니다.

[MongoDB] 강좌 3편 Document Query(조회) – find() 메소드
MongoDB

[MongoDB] 강좌 3편 Document Query(조회) – find() 메소드

블로그 바로가기!

이번 강좌에선 Document를 조회하는 메소드인 find() 메소드를 자세히 알아보도록 하겠습니다.

Document 조회: db.COLLECTION_NAME.find(query, projection)
이 메소드에서 사용되는 매개변수에 대하여 알아봅시다

parameter Type 설명
query document Optional(선택적). 다큐먼트를 조회할 때 기준을 정합니다. 기준이 없이 컬렉션에 있는 모든 다큐먼트를 조회 할때는 이 매개변수를 비우거나 비어있는 다큐먼트 { } 를 전달하세요.
projection document Optional. 다큐먼트를 조회할 때 보여질 field를 정합니다.

반환(return) 값: cursor

criteria에 해당하는 Document들을 선택하여 cursor를 반환합니다. cursor 는 query 요청의 결과값을 가르키는 pointer 입니다. cursor 객체를 통하여 보이는 데이터의 수를 제한 할 수 있고, 데이터를 sort 할 수 도 있습니다. 이는 10분동안 사용되지 않으면 만료됩니다.

먼저 find() 메소드를 테스트해보기 위에 mock-up data를 만들어보도록 하겠습니다.

[
{
“title”: “article01”,
“content”: “content01”,
“writer”: “Velopert”,
“likes”: 0,
“comments”: []
},
{
“title”: “article02”,
“content”: “content02”,
“writer”: “Alpha”,
“likes”: 23,
“comments”: [
{
“name”: “Bravo”,
“message”: “Hey Man!”
}
]
},
{
“title”: “article03”,
“content”: “content03”,
“writer”: “Bravo”,
“likes”: 40,
“comments”: [
{
“name”: “Charlie”,
“message”: “Hey Man!”
},
{
“name”: “Delta”,
“message”: “Hey Man!”
}
]
}
]
추가하기:

db.articles.insert([
{
“title” : “article01”,
“content” : “content01”,
“writer” : “Velopert”,
“likes” : 0,
“comments” : [ ]
},
{
“title” : “article02”,
“content” : “content02”,
“writer” : “Alpha”,
“likes” : 23,
“comments” : [
{
“name” : “Bravo”,
“message” : “Hey Man!”
}
]
},
{
“title” : “article03”,
“content” : “content03”,
“writer” : “Bravo”,
“likes” : 40,
“comments” : [
{
“name” : “Charlie”,
“message” : “Hey Man!”
},
{
“name” : “Delta”,
“message” : “Hey Man!”
}
]
}
])
BulkWriteResult({
“writeErrors” : [ ],
“writeConcernErrors” : [ ],
“nInserted” : 3,
“nUpserted” : 0,
“nMatched” : 0,
“nModified” : 0,
“nRemoved” : 0,
“upserted” : [ ]
})
예제1: 모든 다큐먼트 조회

> db.articles.find()

> db.articles.find()
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c4”), “title” : “article01”, “content” : “content01”, “writer” : “Velopert”, “li
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c5”), “title” : “article02”, “content” : “content02”, “writer” : “Alpha”, “likes
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c6”), “title” : “article03”, “content” : “content03”, “writer” : “Bravo”, “likes ] }
다큐먼트들이 한줄로 나와서 보기 힘들죠,,
다큐먼트들을 깔끔하게 보고싶다면? find() 메소드 뒤에 .pretty() 를 붙여주면됩니다.

예제2: 다큐먼트를 예쁘게 깔끔하게 조회

> db.articles.find().pretty()

> db.articles.find().pretty()
{
“_id” : ObjectId(“56c0ab6c639be5292edab0c4”),
“title” : “article01”,
“content” : “content01”,
“writer” : “Velopert”,
“likes” : 0,
“comments” : [ ]
}
{
“_id” : ObjectId(“56c0ab6c639be5292edab0c5”),
“title” : “article02”,
“content” : “content02”,
“writer” : “Alpha”,
“likes” : 23,
“comments” : [
{
“name” : “Bravo”,
“message” : “Hey Man!”
}
]
}
{
“_id” : ObjectId(“56c0ab6c639be5292edab0c6”),
“title” : “article03”,
“content” : “content03”,
“writer” : “Bravo”,
“likes” : 40,
“comments” : [
{
“name” : “Charlie”,
“message” : “Hey Man!”
},
{
“name” : “Delta”,
“message” : “Hey Man!”
}
]
}
예제3: writer 값이 “Velopert” 인 Document 조회

> db.articles.find( { “writer”: “Velopert” } ).pretty()

> db.articles.find({“writer”: “Velopert”}).pretty()
{
“_id” : ObjectId(“56c0ab6c639be5292edab0c4”),
“title” : “article01”,
“content” : “content01”,
“writer” : “Velopert”,
“likes” : 0,
“comments” : [ ]
}
예제4: likes 값이 30 이하인 Document 조회

> db.articles.find( { “likes”: { $lte: 30 } } ).pretty()

> db.articles.find({“likes”: {$lte: 30}}).pretty()
{
“_id” : ObjectId(“56c0ab6c639be5292edab0c4”),
“title” : “article01”,
“content” : “content01”,
“writer” : “Velopert”,
“likes” : 0,
“comments” : [ ]
}
{
“_id” : ObjectId(“56c0ab6c639be5292edab0c5”),
“title” : “article02”,
“content” : “content02”,
“writer” : “Alpha”,
“likes” : 23,
“comments” : [
{
“name” : “Bravo”,
“message” : “Hey Man!”
}
]
}
여기서 $lte 가 사용됐죠? 이건 less than 을 의미하고, mongodb 의 query 비교 연산자 중 하나랍니다.

여기서 잠깐! Query 연산자에 대해 알아봅시다.
프로그래밍 언어에서 >, <, <=, ==, != 등 연산자가 있는것처럼, mongoDB 에서도 원하는 데이터를 찾기 위해 연산자를 사용합니다. 연산자의 종류는 비교(Comparison), 논리(Logical), 요소(Element), 배열(Array) 등 여러종류가 있는데요, 이는 mongoDB 매뉴얼 에서 확인 가능합니다.

이 강좌에선 자주 사용되는 연산자에 대해서만 설명하도록 하겠습니다. (맘 같아선 다 설명하고싶지만 시간이 남아나질 않네요)

비교(Comparison) 연산자
operator 설명
$eq (equals) 주어진 값과 일치하는 값
$gt (greater than) 주어진 값보다 큰 값
$gte (greather than or equals) 주어진 값보다 크거나 같은 값
$lt (less than) 주어진 값보다 작은 값
$lte (less than or equals) 주어진 값보다 작거나 같은 값
$ne (not equal) 주어진 값과 일치하지 않는 값
$in 주어진 배열 안에 속하는 값
$nin 주어빈 배열 안에 속하지 않는 값
예제5: likes 값이 10보다 크고 30보다 작은 Document 조회

> db.articles.find( { “likes”: { $gt: 10, $lt: 30 } } ).pretty()

> db.articles.find( { “likes”: { $gt: 10, $lt: 30 } } ).pretty()
{
“_id” : ObjectId(“56c0ab6c639be5292edab0c5”),
“title” : “article02”,
“content” : “content02”,
“writer” : “Alpha”,
“likes” : 23,
“comments” : [
{
“name” : “Bravo”,
“message” : “Hey Man!”
}
]
}
예제6: writer 값이 배열 [“Alpha”, “Bravo”] 안에 속하는 값인 Document 조회

> db.articles.find( { “writer”: { $in: [ “Alpha”, “Bravo” ] } } ).pretty()

논리 연산자
이 부분은 프로그래머라면 따로 설명이 필요 없을 듯 합니다.

operator 설명
$or 주어진 조건중 하나라도 true 일 때 true
$and 주어진 모든 조건이 true 일 때 true
$not 주어진 조건이 false 일 때 true
$nor 주어진 모든 조건이 false 일때 true

예제7: title 값이 “article01” 이거나, writer 값이 “Alpha” 인 Document 조회

> db.articles.find({ $or: [ { “title”: “article01” }, { “writer”: “Alpha” } ] })

> db.articles.find({ $or: [ { “title”: “article01” }, { “writer”: “Alpha” } ] })
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c4”), “title” : “article01”, “content” : “content01”, “writer” : “Velopert”, “likes” : 0, “comments” : [ ] }
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c5”), “title” : “article02”, “content” : “content02”, “writer” : “Alpha”, “likes” : 23, “comments” : [ { “name” : “Bravo”, “message” : “Hey Man!” } ] }
예제8: writer 값이 “Velopert” 이고 likes 값이 10 미만인 Document 조회

> db.articles.find( { $and: [ { “writer”: “Velopert” }, { “likes”: { $lt: 10 } } ] } )

이렇게도 가능합니다: > db.articles.find( { “writer”: “Velopert”, “likes”: { $lt: 10 } } )

> db.articles.find( { $and: [ { “writer”: “Velopert” }, { “likes”: { $lt: 10 } } ] } )
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c4”), “title” : “article01”, “content” : “content01”, “writer” : “Velopert”, “likes” : 0, “comments” : [ ] }

> db.articles.find( { “writer”: “Velopert”, “likes”: { $lt: 10 } } )
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c4”), “title” : “article01”, “content” : “content01”, “writer” : “Velopert”, “likes” : 0, “comments” : [ ] }

$regex 연산자
$regex 연산자를 통하여 Document를 정규식을 통해 찾을 수 있습니다. 이 연산자는 다음과 같이 사용합니다.

{ <field>: { $regex: /pattern/, $options: ‘<options>’ } }
{ <field>: { $regex: ‘pattern’, $options: ‘<options>’ } }
{ <field>: { $regex: /pattern/<options> } }
{ <field>: /pattern/<options> }
4번쨰 라인 처럼 $regex 를 작성하지 않고 바로 정규식을 쓸 수도 있습니다. 여기서 $options는 다음과 같습니다.

option 설명
i 대소문자 무시
m 정규식에서 anchor(^) 를 사용 할 때 값에 \n 이 있다면 무력화
x 정규식 안에있는 whitespace를 모두 무시
s dot (.) 사용 할 떄 \n 을 포함해서 매치
예제09: 정규식 article0[1-2] 에 일치하는 값이 title 에 있는 Document 조회

> db.articles.find( { “title” : /article0[1-2]/ } )

> db.articles.find( { “title” : /article0[1-2]/ } )
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c4”), “title” : “article01”, “content” : “content01”, “writer” : “Velopert”, “likes” : 0, “comments” : [ ] }
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c5”), “title” : “article02”, “content” : “content02”, “writer” : “Alpha”, “likes” : 23, “comments” : [ { “name” : “Bravo”, “message” : “Hey Man!” } ] }
$where 연산자
$where 연산자를 통하여 javascript expression 을 사용 할 수 있습니다.

예제10: comments field 가 비어있는 Document 조회

> db.articles.find( { $where: “this.comments.length == 0” } )

> db.articles.find( { $where: “this.comments.length == 0” } )
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c4”), “title” : “article01”, “content” : “content01”, “writer” : “Velopert”, “likes” : 0, “comments” : [ ]
$elemMatch 연산자
$elemMatch 연산자는 Embedded Documents 배열을 쿼리할때 사용됩니다. 저희 mock-up data 에서는 comments 가 Embedded Document에 속합니다.

예제11: comments 중 “Charlie” 가 작성한 덧글이 있는 Document 조회

db.articles.find( { “comments”: { $elemMatch: { “name”: “Charlie” } } } )

> db.articles.find( { “comments”: { $elemMatch: { “name”: “Charlie” } } } )
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c6”), “title” : “article03”, “content” : “content03”, “writer” : “Bravo”, “likes” : 40, “comments” : [ { “name” : “Charlie”, “message” : “Hey Man!” }, { “name” : “Delta”, “message” : “Hey Man!” } ] }
Embedded Document 배열이 아니라 아래 Document의 “name” 처럼 한개의 Embedded Document 일 시에는,

{
“username”: “velopert”,
“name”: { “first”: “M.J.”, “last”: “K.”},
“language”: [“korean”, “english”, “chinese”]
}
다음과 같이 쿼리합니다.

> db.users.find({ “name.first”: “M.J.”})
그리고 Document의 배열이아니라 그냥 배열일 시에는 다음과 같이 Query 합니다.

> db.users.find({ “language”: “korean”})

projection?
find() 메소드의 두번째 parameter 인 projection에 대하여 알아보도록 하겠습니다.
쿼리의 결과값에서 보여질 field를 정하는건데요, 꽤나 간단합니다. 예제를 통해 배워볼까요?

예제12: article의 title과 content 만 조회

> db.articles.find( { } , { “_id”: false, “title”: true, “content”: true } )

> db.articles.find( { } , { “_id”: false, “title”: true, “content”: true } )
{ “title” : “article01”, “content” : “content01” }
{ “title” : “article02”, “content” : “content02” }
{ “title” : “article03”, “content” : “content03” }
$slice 연산자
projector 연산자 중 $slice 연산자는 Embedded Document 배열을 읽을때 limit 설정을 합니다.

예제13: title 값이 article03 인 Document 에서 덧글은 하나만 보이게 출력

> db.articles.find( { “title”: “article03” }, { comments: { $slice: 1 } } )

> db.articles.find({“title”: “article03”}, {comments: {$slice: 1}}).pretty()
{
“_id” : ObjectId(“56c0ab6c639be5292edab0c6”),
“title” : “article03”,
“content” : “content03”,
“writer” : “Bravo”,
“likes” : 40,
“comments” : [
{
“name” : “Charlie”,
“message” : “Hey Man!”
}
]
}
$slice 가 없었더라면, 2개를 읽어와야하지만 1개로 제한을 두었기에 한개만 출력하게됩니다.

$elemMatch 연산자
query 연산자 중 $elemMatch와 사용법은 같습니다. 단 역할이 다르지요.
다음과 같은 상황에서 사용합니다.

예제11번에서 “ comments 중 “Charlie” 가 작성한 덧글이 있는 Document 조회 ” 를 했을때, 게시물 제목과 Charlie의 덧글부분만 읽고싶을땐 어떻게할까요?

db.articles.find(
{
“comments”: {
$elemMatch: { “name”: “Charlie” }
}
},
{
“title”: true,
“comments.name”: true,
“comments.message”: true
}
)
이렇게 해보면 의도와는 다르게 Delta 의 덧글도 출력합니다.

{
“_id” : ObjectId(“56c0ab6c639be5292edab0c6”),
“title” : “article03”,
“comments” : [
{
“name” : “Charlie”,
“message” : “Hey Man!”
},
{
“name” : “Delta”,
“message” : “Hey Man!”
}
]
}
$elemMatch 연산자를 projection 연산자로 사용하면 이를 구현 할 수 있습니다.

예제14: comments 중 “Charlie” 가 작성한 덧글이 있는 Document 중 제목, 그리고 Charlie의 덧글만 조회

db.articles.find(
… {
… “comments”: {
… $elemMatch: { “name”: “Charlie” }
… }
… },
… {
… “title”: true,
… “comments”: {
… $elemMatch: { “name”: “Charlie” }
… },
… “comments.name”: true,
… “comments.message”: true
… }
… )
{ “_id” : ObjectId(“56c0ab6c639be5292edab0c6”), “title” : “article03”, “comments” : [ { “name” : “Charlie”, “message” : “Hey Man!” } ] }

마무리하며..
이번 강좌에서는 find() 메소드에 대하여 자세하게 알아보았습니다. 그.런.데. 이게 끝이 아니라는 사실!
find() 메소드를 더욱더 활용하기 위해 필요한 sort(), limit(), skip() 메소드 등이 남아있습니다.
이는 다음 강좌로 미루도록 하겠습니다…

[MongoDB] 2편: Database/Collection/Document 생성·제거
MongoDB

[MongoDB] 2편: Database/Collection/Document 생성·제거

블로그 바로가기!

이번 강좌에서는 Database, Collection, Document 를 생성하는 명령어와 제거하는 명령어를 배워보도록 하겠습니다. 이 세가지 키워드의 관계는 아래 이미지와 같습니다. 이 단어들이 생소하신분은 전 강좌를 읽어주세요.

ffff

Database 생성: use
use DATABASE_NAME 명령어를 통하여 Database를 생성 할 수 있습니다.
생성 후, 생성된 데이터베이스를사용하게 되구요, 데이터베이스가 이미 존재하는 경우엔 현존하는 데이터베이스를 사용합니다.

예제: mongodb_tutorial 이라는 데이터베이스를 생성합니다.

> use mongodb_tutorial
switched to db mongodb_tutorial
현재 사용중인 데이터베이스를 확인하려면 db 명령어를 입력하세요.

> db
mongodb_tutorial
내가 만든 데이터베이스 리스트들을 확인하려면 show dbs 명령어를 입력하세요.

> show dbs
local 0.000GB
엥?! 방금 만든 mongodb_tutorial 이 없죠?
리스트에서 방금 만든 데이터베이스를 보려면 최소 한개의 Document를 추가해야합니다.

> db.book.insert({“name”: “MongoDB Tutorial”, “author”: “velopert”});

WriteResult({ “nInserted” : 1 })
> show dbs
local 0.000GB
mongodb_tutorial 0.000GB
* 여기서 book 은 Collection 입니다. 따로 Collection 을 미리 생성하지 않아도
위처럼 명령어를 작성하는데 차질이 없습니다.

Database 제거: db.dropDatabase()
Database를 제거할땐 db.dropDatabase() 명령어를 사용합니다.

이 명령어를 사용하기 전, use DATABASE_NAME 으로 삭제하고자 하는 데이터베이스를 선택해줘야합니다.

예제: mongodb_tutorial 데이터베이스를 제거합니다.

> use mongodb_tutorial
switched to db mongodb_tutorial
> db.dropDatabase();
{ “dropped” : “mongodb_tutorial”, “ok” : 1 }

Collection 생성: db.createCollection()
Collection을 생성할때는 db.createCollection(name, [options]) 명령어를 사용합니다.

name 은 생성하려는 컬렉션의 이름이며 option 은 document 타입으로 구성된 해당 컬렉션의 설정값입니다.
options 매개변수는 선택적인(Optional) 매개변수로서 생략하셔도 되고, 필요에따라 사용하면 됩니다.

Option:
Field Type 설명
capped Boolean 이 값을 true 로 설정하면 capped collection 을 활성화 시킵니다. Capped collection 이란, 고정된 크기(fixed size) 를 가진 컬렉션으로서, size 가 초과되면 가장 오래된 데이터를 덮어씁니다. 이 값을 true로 설정하면 size 값을 꼭 설정해야합니다.
autoIndex Boolean 이 값을 true로 설정하면, _id 필드에 index를 자동으로 생성합니다. 기본값은 false 입니다.
size number Capped collection 을 위해 해당 컬렉션의 최대 사이즈(maximum size)를 ~ bytes로 지정합니다.
max number 해당 컬렉션에 추가 할 수 있는 최대 갯수를 설정합니다.

예제1 : test 데이터베이스에 books 컬렉션을 옵션없이 생성합니다.

> use test
switched to db test
> db.createCollection(“books”)
{ “ok” : 1 }
예제2: test 데이터베이스에 articles 컬렉션을 옵션과 함께 생성합니다.

> db.createCollection(“articles”, {
… capped: true,
… autoIndex: true,
… size: 6142800,
… max: 10000
… })
{ “ok” : 1 }
예제3: 따로 createCollection() 메소드를 사용하지 않아도 document를 추가하면 자동으로 컬렉션이 생성됩니다.

> db.people.insert({“name”: “velopert”})
WriteResult({ “nInserted” : 1 })
내가 만든 collection 리스트를 확인하려면 show collections 명령어를 입력하세요.

> show collections
articles
books
people

Collection 제거: db.COLLECTION_NAME.drop()
Collection을 제거 할 땐 drop() 메소드를 사용합니다.

당연히, 이 명령어를 제거하기 전, 사용 할 데이터베이스를 우선 설정해야겠죠?

예제: test 데이터베이스의 people 컬렉션을 제거합니다.

> use test
switched to db test
> show collections
articles
books
people
> db.people.drop()
true
> show collections
articles
books

Document 추가: db.COLLECTION_NAME.insert(document)
insert() 메소드를 사용하여 Document를 추가 할 수 있습니다.

이 명령어를 사용하기 전 데이터를 추가 할 데이터베이스를 선택해주어야합니다.

배열형식의 인자를 전달해주면 여러 다큐먼트를 동시에 추가 할 수 있습니다.

예제1: 한개의 다큐먼트를 books 컬렉션에 추가합니다.

> db.books.insert({“name”: “NodeJS Guide”, “author”: “Velopert”})
WriteResult({ “nInserted” : 1 })
예제2: 두개의 다큐먼트를 books 컬렉션에 추가합니다. (가독성을 위해 여러줄로 작성되었습니다.)

> db.books.insert([
… {“name”: “Book1”, “author”: “Velopert”},
… {“name”: “Book2”, “author”: “Velopert”}
… ]);
BulkWriteResult({
“writeErrors” : [ ],
“writeConcernErrors” : [ ],
“nInserted” : 2,
“nUpserted” : 0,
“nMatched” : 0,
“nModified” : 0,
“nRemoved” : 0,
“upserted” : [ ]
})
컬렉션의 다큐먼트 리스트를 확인할때는 db.COLLECTION_NAME.find() 명령어를 사용하세요.

> db.books.find()
{ “_id” : ObjectId(“56c08f3a4d6b67aafdeb88a3”), “name” : “MongoDB Guide”, “author” : “Velopert” }
{ “_id” : ObjectId(“56c08f474d6b67aafdeb88a4”), “name” : “NodeJS Guide”, “author” : “Velopert” }
{ “_id” : ObjectId(“56c0903d4d6b67aafdeb88a5”), “name” : “Book1”, “author” : “Velopert” }
{ “_id” : ObjectId(“56c0903d4d6b67aafdeb88a6”), “name” : “Book2”, “author” : “Velopert” }

Document 제거: db.COLLECTION_NAME.remove(criteria, justOne)
remove(criteria, justOne) 메소드를 사용하여 Document를 제거 할 수 있습니다.
이 메소드에는 두가지의 매개변수가 있는데요,

parameter type 설명
*criteria document 삭제 할 데이터의 기준 값 (criteria) 입니다. 이 값이 { } 이면 컬렉션의 모든 데이터를 제거합니다.
justOne boolean 선택적(Optional) 매개변수이며 이 값이 true 면 1개 의 다큐먼트만 제거합니다. 이 매개변수가 생략되면 기본값은 false 로 서, criteria에 해당되는 모든 다큐먼트를 제거합니다.
이 강좌에선 criteria 에 부분에선 특정 field 의 값이 매칭하는 경우만 배워보도록 하겠습니다. criteria 에 대한 자세한 내용은 다음 강좌에서 다뤄보겠습니다.

다큐먼트 추가 부분에서 find() 메소드를 잠깐 사용했었는데, 이 메소드 역시 criteria를 인수로 전달 할 수 있습니다. 다큐먼트를 제거하다가 실수를 하지 않도록 초보일땐, 제거전에는 find() 를 먼저 해서 확인하는걸 습관화하세요.

예제: books 컬렉션에서 “name”이 “Book1” 인 다큐먼트를 제거

> db.books.find({“name”: “Book1”})
{ “_id” : ObjectId(“56c097f94d6b67aafdeb88ac”), “name” : “Book1”, “author” : “Velopert” }
> db.books.remove({“name”: “Book1”})
WriteResult({ “nRemoved” : 1 })
> db.books.find()
{ “_id” : ObjectId(“56c08f3a4d6b67aafdeb88a3”), “name” : “MongoDB Guide”, “author” : “Velopert” }
{ “_id” : ObjectId(“56c08f474d6b67aafdeb88a4”), “name” : “NodeJS Guide”, “author” : “Velopert” }
{ “_id” : ObjectId(“56c097f94d6b67aafdeb88ad”), “name” : “Book2”, “author” : “Velopert” }

마무리하며..
이번 강좌에서는 MongoDB 커맨드라인 위에서 Database, Collection 그리고 Document 를 추가하고 제거하는것에 대하여 배웠습니다. 다음 강좌에서는 Document 를 Query(조회/검색) 하는 메소드인 find() 메소드에 대하여 자세히 알아보도록 하겠습니다.

 

[MongoDB] 1편: 소개, 설치 및 데이터 모델링
MongoDB

[MongoDB] 1편: 소개, 설치 및 데이터 모델링

메인 블로그 바로가기!

1편: 소개, 설치 및 데이터 모델링

블로그 바로가기

소개
MongoDB는 C++로 작성된 오픈소스 문서지향(Document-Oriented) 적 Cross-platform 데이터베이스이며, 뛰어난 확장성과 성능을 자랑합니다. 또한, 현존하는 NoSQL 데이터베이스 중 인지도 1위를 유지하고있습니다.

NoSQL?
흔히 NoSQL이라고 해서 아, SQL이 없는 데이터베이스구나! 라고 생각 할 수도 있겠지만, 진짜 의미는 Not Only SQL 입니다. 기존의 RDBMS의 한계를 극복하기 위해 만들어진 새로운 형태의 데이터저장소 입니다. 관계형 DB가 아니므로, RDMS처럼 고정된 스키마 및 JOIN 이 존재하지 않습니다.

Document?
Document Oriented 데이터베이스라는데.. 여기서 말하는 Document가 뭘까요? 문서? 이게 그냥 ‘문서’ 로 번역해버리면 조금은 애매합니다. 문서라고 하면 보통 워드/엑셀에 사용되는 그런 문서가 떠오르는데요, 그것과는 다릅니다. Document는 RDMS의 record 와 비슷한 개념인데요, 이의 데이터 구조는 한개이상의 key-value pair 으로 이뤄져있습니다. MongoDB 샘플 Document를 확인 해 볼까요?

{
“_id”: ObjectId(“5099803df3f4948bd2f98391”),
“username”: “velopert”,
“name”: { first: “M.J.”, last: “Kim” }
}
여기서 _id, username, name 은 key 이고 그 오른쪽에 있는 값들은 value 입니다.

_id 는 12bytes의 hexadecimal 값으로서, 각 document의 유일함(uniqueness)을 제공합니다.
이 값의 첫 4bytes 는현재 timestamp, 다음 3bytes는 machine id, 다음 2bytes는 MongoDB 서버의 프로세스id, 마지막 3bytes는 순차번호입니다 추가될때마다 값이 높아진다는거지요.

Document는 동적(dynamic)의 schema 를 갖고있습니다. 같은 Collection 안에 있는 Document 끼리 다른 schema 를 갖고 있을 수 있는데요, 쉽게 말하면 서로 다른 데이터 (즉 다른 key) 들을 가지고 있을 수 있습니다.

Collection?
Collection은 MongoDB Document의 그룹입니다. Document들이 Collection내부에 위치하고 있습니다. RDMS의 table과 비슷한 개념입니다만 RDMS와 달리 schema를 따로 가지고 있지않습니다. Document 부분설명에 나와있듯이 각 Document들이 동적인 schema를 가지고 있으니까요

Database?
Database는 Collection들의 물리적인 컨테이너입니다. 각 Database는 파일시스템에 여러파일들로 저장됩니다.

RDMS와의 비교
RDMS 라는 키워드가 생소하신분들을 위하여 먼저 이에 대한 간단한 설명을 드리겠습니다. Relational Database Management System (관계형 데이터베이스 관리 시스템) 은 행과 열로 된 2차원의 table로 데이터를 관리하는 데이터베이스 시스템입니다. Mysql, Oracle Database, DB2 등 시스템들이 RDMS에 속하죠.

RDBMS MongoDB
Database Database
Table Collection
Tuple / Row Document
Column Key / Field
Table Join Embedded Documents
Primary Key Primary Key (_id)
Database Server & Client
mysqld mongod
mysql mongo

장점
Schema-less (Schema가 없다. 같은 Collection 안에 있을지라도 다른 Schema를 가지고 있을 수 있다)
각 객체의 구조가 뚜렷하다
복잡한 JOIN 이 없다.
Deep Query ability (문서지향적 Query Language 를 사용하여 SQL 만큼 강력한 Query 성능을 제공한다.
어플리케이션에서 사용되는 객체를 데이터베이스에 추가 할 때 Conversion / Mapping이 불필요하다.
MongoDB 설치
윈도우
MongoDB 공식 홈페이지의 다운로드 페이지에서 MSI 파일로 설치하면
C:\Program Files\MongoDB\Server\3.2\bin\ 에 설치됩니다.

CMD 창을 열어서 디렉토리로 들어가 mongod 를 실행하면 서버가 실행됩니다.
기본 데이터베이스 디렉토리가 C:\data\db 이므로 실행 전에 폴더를 수동으로 만들어주셔야합니다.

Microsoft Windows [Version 10.0.10586]
(c) 2015 Microsoft Corporation. All rights reserved.

C:\Users\Velopert>cd C:\Program Files\MongoDB\Server\3.2\bin

C:\Program Files\MongoDB\Server\3.2\bin>mkdir C:\data\db

C:\Program Files\MongoDB\Server\3.2\bin>mongod
데이터베이스 디렉토리를 변경하고싶다면 다음과같이 실행하면 됩니다.

C:\Program Files\MongoDB\Server\3.2\bin> mongod –dbpath “c:\custom_folder”
매번 MongoDB 설치 경로로 이동하는게 귀찮다면, 해당 디렉토리를 환경변수의 PATH 에 추가하세요.
(윈도우 10 이하 버전에서는
기존 값 ; C:\Program Files\MongoDB\Server\3.2\bin 이런식으로 수정해야합니다.)

Untitled-3

리눅스
이 포스트에서는 Ubuntu 에서 MongoDB 설치하는 과정을 살펴보도록하겠습니다.
다른 리눅스 디스트로를 사용하시는분들은 https://docs.mongodb.org/manual/installation/ 을 참조해주세요.

주의: Cloud9 를 사용하신다면 1번과 2번은 생략하셔도 됩니다.

1. MongoDB Pulbic GPG Key 등록

$ sudo apt-key adv –keyserver hkp://keyserver.ubuntu.com:80 –recv EA312927
2. MongoDB 를 위한 list file 생성 (자신의 Ubuntu 버전에 맞게 입력하세요)

# Ubuntu 12.04
$ echo “deb http://repo.mongodb.org/apt/ubuntu precise/mongodb-org/3.2 multiverse” | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list

# Ubuntu 14.04
$ echo “deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.2 multiverse” | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list
3. apt-get 을 이용하여 설치

$ sudo apt-get update

# latest stable version 설치
$ sudo apt-get install -y mongodb-org
4. 서버 실행

$ sudo service mongod start
# 서버가 제대로 실행됐는지 확인
$ cat /var/log/mongodb/mongod.log
# [initandlisten] waiting for connections on port <port>
기본 포트는 27017 이며, 방화벽을 사용하시는분들은 해당 포트를 Open 해주세요.
포트는 /etc/mongod.conf 에서 변경 가능합니다.

OS X
brew update
brew install mongodb

mkdir -p /data/db
mongod
# dbpath 지정
mongod –path <path>
자세한 내용: https://docs.mongodb.org/manual/tutorial/install-mongodb-on-os-x/

MongoDB 서버 접속
터미널에서 mongo 를 입력하세요.
(윈도우에서는 환경변수를 설정하지 않았다면 설치 경로에 이동 후 입력하세요)

$ mongo
MongoDB shell version: 3.2.1
connecting to: test
>

Data Modelling
MongoDB에서의 명령어들을 배우기전에, MongoDB에서 데이터를 모델링의 기본을 배워보겠습니다.

schema 디자인 할 때 고려사항

사용자 요구 (User Requirement) 에 따라 schema를 디자인한다.
객체들을 함께사용하게 된다면 한 Document에 합쳐서 사용한다. (예: 게시물-덧글 과의 관계)
그렇지 않으면 따로 사용한다 (그리고 join 을 사용하지 않는걸 확실히 해둔다)
읽을때 join 하는게아니라 데이터를 작성 할 때 join 한다.
예제

간단한 블로그를 위한 데이터베이스를 디자인한다고 가정해봅시다. 요구사항을 나열해볼까요?

– 게시글에는 작성자 이름, 제목, 내용이 담겨져있다.
– 각 게시글은 0개 이상의 태그를 가지고 있을 수 있다.
– 게시글엔 덧글을 달 수 있다. 덧글은 작성자 이름, 내용, 작성시간을 담고있다.

만약에 RDMS에서 데이터베이스 schema를 디자인한다면 이것과 비슷하겠죠?

d

RDMS라면,이런식으로 테이블 3개를 만들어야 효율적이라고 부르지만,
NoSQL 에선 모든걸 하나의 Document 에 넣습니다. 한번 살펴볼까요?

{
_id: POST_ID,
title: POST_TITLE,
content: POST_CONTENT,
username: POST_WRITER,
tags: [ TAG1, TAG2, TAG3 ],
time: POST_TIME
comments: [
{
username: COMMENT_WRITER,
mesage: COMMENT_MESSAGE,
time: COMMENT_TIME
},
{
username: COMMENT_WRITER,
mesage: COMMENT_MESSAGE,
time: COMMENT_TIME
}
]
}
어때요, 어느정도 이해가 갔나요?

다음 강좌에선 데이터베이스를 서버에서 직접 다뤄보도록 하겠습니다.