본문 바로가기
  • 행복하게 오래오래 개발자로 살아가기
Old/NODE.JS

MongoDB

by yundev 2013. 10. 23.
반응형

MongoDB

전통적인 RDBMS의 대안이다.

MongoDB에서 DataJSON과 같은 Dynamic Schema 형태의 Document(문자열로 구성된 단위) 구조로 저장이 되는데 MongosDB에서는 이를 BSON이라 함.

SQL문을 MongoDB쿼리 함수 호출로 매우 간단하게 변환하는 기능이 있어 기존 RDBMS를 쉽게 마이그레이션할 수 있다.

문서 지향(Document-Oriented) 저장소를 제공하는 NoSQL 데이터베이스 시스템.

기존의 데이터베이스들은 대부분 관계형 모델 기반을 두고 있으므로 대부분 SQL 질의문에 의해 데이터베이스를 수정, 갱신, 저장,검색하도록 구성되어 있다.

문서 지향 데이터 베이스. 객체 지향 프로그래밍과 잘 맞고, JSON을 사용할 때 아주 유용함.

(문서 기반의 데이터 구조란 데이터 설계를 종이문서 설계하듯이 설계 해야한다. 한 장의 document에 필요한 정보를 모두 담아야 한다. One query로 모두 해결이 되게끔 collection model설계를 해야한다.)

- Join이 중요하지 않기 때문에 빠른 임베디드 생성

- 관리의 편의성

- 스키마 없는 데이터베이스를 이용한 신속한 개발

no schema? schmaRDBMSrelation을 의미함. Foreign key 개념이 없다. Join query 사용하기 힘들다. humongus해지기 위해서 relation을 포기하고 performancescalability를 선택했다.

Collection(=table)에 저장할 documents(=row, record)의 구조에 대해 미리 정의할 필요가 없다. 동일한 collection에 다른 구조를 가진 document를 저장할 수 있다.

Documentkey/value 쌍의 데이터를 저장하며 key string이며, values data type의 어떤 것도 가능하다.

관계형 연산이 필요한 CRM, 데이터 마트 구축에는 RDBMS 사용.

Code table을 참조하는 방식으로 data modeling을 해서는 안된다.

스키마의 제약이 없기 때문에 개발 시 유연성을 제공함.

- 쉬운 수평 확장성

- auto-sharding

Mongodb의 핵심기능. 이론적으로는 가상의 큰 테이블을 만들고 데이터를 집어넣는 방식이 sharding. 아무렇게나 랜덤으로 disk에 집어 넣는 것. Disk error가 뜨면 그 부분의 데이터 유실이 발생함. 그래서 꼭 replica set을 구성해야 함. Shardingreplication1 set으로 구성해야 함.

단순 master/slave구조를 넘어 replica set을 통해 자동으로 장애를 감지하고 복구한다.

- Map Reduce

Auto-sharding, replica, map reduce는 하나의 set. 흩어진 데이터를 어떻게 모아서 읽거나 쓸 것 인가에 대해 핵심적인 부분. 쉽게 구성이 되고 쉽게 사용할 수 있음. 생각보다 detail하게 만질 수 없음.

**Replica-set

Master/slave 구조보다 좀 더 안정적인 방법으로 Master와 같은 역할을 하는 Primary서버에 장애가 감지되면 자동으로 새로운 primary 서버를 선정하고 동작하게 함으로써 일관성 및 가용성을 보장하는 방식이다.

**Sharding

range파티션 기법으로 shard key를 중심으로 데이터를 여러 shard서버에 분산하여 저장하는 방식이며 shard 서버들 간의 데이터 balancing도 모두 자동으로 이루어짐.

고가용성을 위해 replica-setsharding방식을 함께 사용할 수 있다.

불편한 점

-      config server 에 부하 집중

document에는 sharding 관련해서 file index config server 에 구성된다고 써있습니다.

config server에 병목이 발생되면, 대용량 분산 서버 구성도 말짱 헛일이 될 수 있습니다.

Auto-sharding을 구성하면서 반드시 config server 부하 테스트를 해보시길 바랍니다.

병목이 발생된다면, Hadoop 등으로 분산형 스토리지를 구축할 필요가 있을 것 같습니다.

 

-      현실적인 Spatial query “Near”, “Box”, “Center” 연산만 지원합니다.

Near 연산은 기준점에서 가장 가까운 것부터 출력해줍니다.

Box 연산은 사각형 내의 poi 를 출력해줍니다.

Center 연산은 원형의 반경내 poi 를 출력해줍니다.

polygon 내의 poi 검색은 현재 개발자 버전만 지원한다고 하지만, Indexing 생성이 제대로 되지 않는 등의 문제가 있었습니다.

 

-      저장블럭이 2G 단위로 커집니다.

아직까지 조정이 불가능합니다. 큰 불편은 아니지만, 알아두어야 할 것 같습니다.

64M, 128M, 512M,1G,2G,2G,2G…. 이렇게 블럭이 늘어납니다.

 

-      단편화된 저장공간을 모으는 것이 offline mode 에서만 가능합니다.

따라서, 한 개씩 disk offline 으로 떨구어 가면서 repair를 해야 합니다.

불편할 것 같네요. PC환경에서 테스트 시에는 1GB 20분 정도 걸렸다고 합니다.

저장블럭은 2G씩 늘어나는데, 삭제가 많은 환경이면 Disk 낭비가 심할 것 같은데요.

빈번한 delete, insert 가 반복되는 환경에는 권하고 싶지 않습니다.

프로그래밍 할 때도 delete, insert 형식으로 데이터를 update하지 마세요.

 

-      관리툴이 미흡해서 운영이 불편할 것 같네요.

많은 disk repair하다 보면, 많이 헷갈릴 듯.

손토매틱(반대말 오토매틱)으로 하던지, 별도 개발을 해야 할 것 같습니다.

써야하는 곳

-      기본적으로 하나의 table(collection)이 무한정 커지는 경우

collection 설계하고, shard 에 태우면 됩니다. 쉽죠? 오라클은 partitioning table, archive backup, hot backup/recovery 이런거에 신경써야 하는 반면, mongo db disk 하나를 더 끼우고 configuration에 더해주면 끝입니다.

어떤 경우가 하나의 table 이 무한정 커지는 경우일까요?

“로그 데이터에 적용하면 좋겠네요.

파일로그를 분석 하려면 어차피 DB에 넣어야 하는데, 기가급이 넘어가도 Handling 이 쉽지 않죠.

“회원정보 테이블에 좋겠네요.

물론 회원수가 일정하면 상관없겠지만, Foursquare Facebook 같은 글로벌 서비스의 경우는 회원수 관리하기가 만만치 않을 듯.

“메시징 데이터 테이블도 좋겠네요.

하루에도 수억 건씩 쌓이니까요.

-쌓아놓기만 하고, 삭제가 적은 경우

delete가 많은 거대 데이터라면 주기적으로 repair 를 해야 하는데, 서버 환경이나 운영에 드는 손 씀씀이로 볼 때, 현실적으로 가능할까 싶습니다.

쌓아놓기만 하고, 삭제가 적은 경우가 어떤 경우일까요?

“오래된 음원 DB”를 만들 때는 좋겠군요.

값싼 Disk 에 오랫동안 많이 넣어두면 보관하기 좋고, read/write 성능도 떨어지지 않을 듯.

CDDB bugs 같은 곳은 좋을 듯.

poi” “check-in” 데이터를 넣어두기 좋겠네요.

많은 상점들이 사라졌다 생겼다 하겠지만, foursquare 와 같은 user check-in 데이터들은 거의 삭제할 이유가 없으니(데이터가 재산인 사업환경), 정말 딱 적합하다는 생각이 듭니다.

*NoSQL : 관계형 데이터 모델을 사용하지 않고 SQL을 사용하지 않는 그 이외의 모든 데이터 베이스 시스템 또는 데이터 스토어를 일컬음이넴모리기반의 분산 캐싱 서버에서부터 칼럼 데이터를 지원하는 데이터베이스. 확장성 가용성 높은 성능 다양한 데이터 형태를 수용할 수 있다. 무한에 가까운 확장성을 제공함. 키와 값의 쌍으로 이루어져 있다. 인덱스와 데이터는 분리되어 별도로 운영되며 고정된 스키마도 없음.

주목을 받게 된 이유 : 모바일 환경의 확대, SNS의 활성화

모바일 환경의 확대

1.     최근 모바일 어플리케이션은 Hybrid 형태를 띄며 Data를 기본적으로 Server Side에 저장하기 때문에 지속적으로 Server Side로부터 Data을 받아오는 게 사용자 사용성에 중요한 척도가 되었다.

2.     모바일 어플리케이션 개발 기술 중 Server/Client 통신 기술은 Open API형태로 Web Service를 사용하며 그 중 Restful 방식으로 전문형태는 JSON을 사용하는 것이 거의 표준으로 잡혀 있음.

3.     MongoDB와 같은 Document기반 DB JSON형태로 저장되기 때문에 Data와 어플리케이션간 통합에 최적의 구조를 가진다.

SNS의 활성화

1.     모바일 환경에서 SNS가 활성화 되고 나서 엄청난 규모의 Data가 발생한다.

2.     전통적인 RDBMS로는 현재 규모의 Big Data을 저장하고 관리하기 어렵다.

3.     새로운 형태의 NoSQL 기술이 필요하게 되었고 가장 적합한 형태가 MongoDB이다.

My SQL, MongoDB 비교

MySQL

MongoDB

database

database

table

Collection

index

Index

row

JSON document

column

JSON field

join

Embedding and linking

Primary key

_id field

Group by

aggregation

SQL 구문 비교

SQL 문장

Mongo 쿼리 문장 

CREATE TALE USERS (a int, b int)

db.createCollection("mycoll") 

 INSERT INTO USERS VALUES (3,5)

db.users.insert({a:3, b:5}) 

 SELECT a, b FROM USERS

db.users.find({}, {a:1, b:1}) 

 SELECT * FROM users

 db.users.find()

 SELECT * FROM users WHERE age=33

 db.users.find({age:33})

 SELECT a,b FROM users WHERE age=33

 db.users.find({age:33}, {a:1,b:1})

 SELECT * FROM users WHERE age=33 ORDER BY name

 db.users.find({age:33}).sort({name:1})

 SELECT * FROM users WHERE age>33

 db.users.find({'age':{$gt:33}})

 SELECT * FROM users WHERE age<33

 db.users.find({'age':{$lt:33}})

 SELECT * FROM users WHERE name LIKE"%Joe%"

 db.users.find({name:/Joe/})

 SELECT * FROM users WHERE name LIKE "Joe%"

 db.users.find({name:/^Joe/})

 SELECT * FROM users WHERE age>33 AND age<=40

 db.users.find({'age':{$gt:33,$lte:40}})

 SELECT * FROM users ORDER BY name DESC

 db.users.find().sort({name:-1})

 SELECT * FROM users WHERE a=1 and b='q'

 db.users.find({a:1,b:'q'})

 SELECT * FROM users LIMIT 10 SKIP 20

 SELECT * FROM users LIMIT 10 SKIP 20

 SELECT * FROM users WHERE a=1 or b=2

 db.users.find( { $or : [ { a : 1 } , { b : 2 } ] } )

 SELECT * FROM users LIMIT 1

 db.users.findOne()

 SELECT DISTINCT last_name FROM users

 db.users.distinct('last_name')

 SELECT COUNT(*y) FROM users

 db.users.count()

 

 SELECT COUNT(*y) FROM users where AGE > 30

 db.users.find({age: {'$gt': 30}}).count()

 SELECT COUNT(AGE) from users

 db.users.find({age: {'$exists': true}}).count()

 

 CREATE INDEX myindexname ON users(name)

 db.users.ensureIndex({name:1})

 CREATE INDEX myindexname ON users(name,ts DESC)

 db.users.ensureIndex({name:1,ts:-1})

 EXPLAIN SELECT * FROM users WHERE z=3

 db.users.find({z:3}).explain()

 UPDATE users SET a=1 WHERE b='q'

 db.users.update({b:'q'}, {$set:{a:1}}, falsetrue)

 UPDATE users SET a=a+2 WHERE b='q'

 db.users.update({b:'q'}, {$inc:{a:2}}, falsetrue)

 DELETE FROM users WHERE z="abc"

 db.users.remove({z:'abc'});

db.dropDatabase() 사용중인 [DB_NAME]drop(삭제) 시킨다

사용법

db 현재 접속한 DB 확인

show dbs모든 DB 확인

use mydb사용할 DB 지정, 없는 경우 자동 생성 된다.

help도움말보기

help.help() DB 매소드 도움말 보기

j={name:”mong”} 데이터를 넣어보기 위해 JSON형태의 DATA 생성

k={x:3} 처음과 다른 형태의 JSON형태 생성, MongoDBJSON형태가 다르더라도 같은 collection에 넣을 수 있다.

db.mydb.insert(j) 생성한 ‘j’’ collection ‘mydb’에 넣는다.

db.mydb.insert(k) 생성한 ‘k’ collection ‘mydb’에 넣는다.

Show collections 어떤 collection들이 있는지 확인해본다.

db.mydb.find mydb에 포함된 Document을 조회한다. “_id” MongoDBcollection에 입력되는 순간 자동으로 부여하며, mongoDB내에서 유니크 하다.

For(var i=0;i<=20;i++)db.mydb.insert(x:4,j:i) ->for문을 이용해서 다중 문서를 넣어본다.

db.mydb.find()

it 더 있는 경우

 

쿼리 연산자

1.    < “$lt” / <= “$lte” / >“$gt” / >=“$gte”

2.    AND 연산

SELECT * FROM users WHERE age BETWEEN 20 AND 25;

==> db.users.find({ age : { "$gte" : 20 , "$lte" : 25} });

age:{"gte":20}, age:{"$lte":25} 로 질의하면 같은 도큐먼트 내의 같은 수준에서는 반복으로 질의 할 수 없습니다. 따라서 틀렸습니다.

3.    $in, $nin, $all 연산자

SELECT * FROM users WHERE age IN(3,5,7,9);

==> db.users.find({ age : { $in : [3, 5, 7, 9] });

SELECT * FROM users WHERE age NOT IN(3,5,7,9);

==> db.users.find({ age : { $nin : [3, 5, 7, 9] }); // 문자열["ab", "안녕", "margo"]

모든 조건이 검색키와 일치되는 도큐먼트 찾기

도큐먼트 

{ name: "Bird Feeder",

   tags: [ "gift", "birds", "garden" ]

}

==> db.products.find({ tags : { $all : ["gift", "garden"] }  });

4. $ne, $not, $or, $and, $exists 연산자

$ne - 같지않음(not equal to)  ** 단일한 값이거나, 배열인 경우 모두 수행된다

name "ace" 인 도큐먼트 중 tags "test" 가 아닌 모든 도큐먼트

==> db.products.find({ 'name':'ace', tags: {$ne : "test"} })

$not - 다른 연산자나 정규 표현식으로 부터 얻은 결과의 여집합을 리턴

성이 B로 시작하지 않는 모든 유저의 도큐먼트

==> db.users.find({ last_name: { $not: /^B/ } })

$or - 서로 다른 키에 대한 검색을 할 때 사용한다. 만약 같은 키에 대해 찾는다면  $in을 써야한다.

color blue 이거나, name ace인 도큐먼트를 검색할 때

==> db.products.find({ $or : [

{ 'details.color': 'blue'}

, { 'details.name': 'ace'}

})

$and 

- {age:3, name:'margo'}  age :3 AND name:'margo' 로 해석된다.

  이런 방법으로 AND 를 표현할 수 없을때 $and를 사용한다.

예제 도큐먼트

{ tags: ['gift', 'holiday', 'gardening', 'landscaping'] }

gift holiday중 하나가 포함되고, gardening landscaping 중 하나가 포함된 도큐먼트를

찾고싶을때, 이 쿼리를 표현하는 유일한 방법은 2개의 $in 쿼리를 $and 로 연결하는 것이다.

db.products.find({ $and : [

{tags : { $in : ['gift', 'holiday']}}

, {tags : { $in : ['gardening', 'landscaping']}}

]

}) 

$exists - 특정 키, 즉 도큐먼트가 해당 속성을 가지고 있는지 질의하는 쿼리다.

도큐먼트 내에 특성 속성이 존재할 수도 있고, 존재하지 않을 수도 있다.

상품에 대한 컬렉션의 경우, 어떤 상품만의 특별한 키를 가질 수 있을텐데

그때 해당도큐먼트가 그 키를 가지고 있는지 확인하고싶을 때 사용한다.

속성을 가지고 있지 않은 도큐먼트를 찾을 때 - false

==> db.products.find({ 'datails.color' : { $exists : false}})

속성을 가진 도큐먼트 - true

==> db.products.find({ 'datails.color' : { $exists : true}})

$exists : false 는 아래와 같이 표현가능하다.

==> db.products.find({ 'details.color' : null })

$exists : true 는 아래와 같이 표현가능하다.

==> db.products.find({ 'details.color' : {$ne: null }  })

CRUD(Create Read Update Delete)

Insert() : 새로운 도큐먼트를 삽입.

=>db.users.insert({username:”미니”})

Save : 새로운 도큐먼트를 삽입

=>db.users.save({username:”종민”})

Insertsave의 차이

-      Insert는 무조건 값을 추가하지만 save()는 중복 id값이 없는 경우에 추가하고 있다면 수정하는 명령어. 명확하게 추가를 하고자 할 경우에는 insert()를 사용하는 것이 보다 나을 것이다.

l  mongoDB의 도큐먼트는 모두 _id라는 필드가 반드시 필요하다.

이 값이 없으면 MongoDB에서 _id값을 자동으로 생성해서 추가하게 된다.

Count()명령어를 사용해서 컬렉션에 포함된 도큐먼트의 수를 알 수 있다.

find() : 데이터 가져오기

db.users.find()

필드 값을 이용하여 데이터 검색

->db.users.find({x:4}).forEach(printjson);

특정 필드 값만 출력하기

->db.users.find({x:4},{j:true}).forEach(printjson);

출력하고자 하는 필드의 값을 true/falseboolean값으로 입력.

update(): 데이터 수정

명령어 $set을 조합해서 사용함.

>db.users.update({username:”미니”},{$set:{country:”한국”}})

>db.users.find()

$set연산자는 해당하는 배열 전체에 대해 다시 쓰기를 한다.

여기에서는 배열이 아니라 한국이라는 하나의 값이라 차이가 없지만

만약 country가 배열로 되어 있다면 새로운 항목을 추가할 때 $addToSet이나 $push를 사용하는 것이 효율적이다.

새롭게 추가한 항목을 제거하기 위해서는 $unset연산자를 사용하면 된다.

>db.users.find()

>db.users.update({username:”미니”},{$unset:{1}})

>db.users.find()

Delete , remove() : 값 삭제

>db.users.remove({username:”미니”})

drop():컬렉션 삭제

db.users.drop()

dropDatabase() : db 삭제

*show collections했을 때 system.indexes는 도큐먼트에 대한 인덱스를 나타내는 컬렉션이다.

 

*Ad-hoc Query

-시스템이 받아들일 수 있는 Query를 미리 정의할 필요가 없다. 기존 RDBSQL처럼 필요할 때, Query를 생성해서 결과를 받을 수 있다. MongoDB에서는 Query를 작성할 때 정규화된 모델이 아니므로 각 검색 항목들이 Document에 포함되어 있다고 가정하고 진행함.

SELECT * FROM POSTS 
INNER JOIN posts_tags ON posts.id = posts_tags.post_id 
INNER JOIN tags ON posts_tags.tag_id = tags.id 
WHERE tags.text = 'politics' AND posts.vote_count > 10;

> db.posts.find({'tags': 'politics', 'vote_count': {'$gt': 10}});

 

직관적이다!!


참고 사이트

http://daddycat.blogspot.kr/2013/02/mongodb-1.html

http://dev.kthcorp.com/2011/09/15/how-to-use-mongo-db/

http://winmargo.tistory.com/182

반응형

'Old > NODE.JS' 카테고리의 다른 글

heroku에서 log 보기  (0) 2013.10.25
Jade 모듈  (0) 2013.10.23
EJS 모듈  (0) 2013.10.23
Mongo DB 설치  (0) 2013.10.23
github + heroku Node.js 환경 셋팅  (0) 2013.10.23