IT Log

MongoDB 본문

기타

MongoDB

newly0513 2019. 5. 7. 09:51
728x90
반응형

MongoDB란?

  • 필요한 쿼리 및 인덱싱을 통해 확장성과 유연성을 갖춘 문서 데이터베이스
  • 데이터를 JSON 형식의 문서로 저장
  • 응용 프로그램 코드의 객체에 매핑되므로 데이터를 쉽게 사용

 

 

Architecture

  • 문서데이터 모델
  • 분산시스템 설계
  • 어디서나 자유롭게 운영

문서데이터 모델

  • 자연스럽고 직관적인 방식으로 데이터 작업
  • 적응 및 신속한 변경
  • 다양한 데이터 및 쿼리 지원
  • 빠른작업

분산시스템 설계

  • 정교한 복제 및 자체 복구
  • Sharding을 통해 수평으로 확장
  • 동일한 클러스터에서 운영 및 분석 작업을 실행
  • 특정 장치 및 관리, 서비스 클래스 및 대기 시간이 적은 액세스에 대한 특정 지역에 데이터 배치

어디서나 자유롭게 운영

  • 모든곳에서 동일하게 실행되는 DB
  • 잠금이 없는 다중 클라우드의 이점 활용

 

Scale

  • Cluster Scale
  • Performance Scale
  • Data Scale

Cluster Scale

  • 100개 이상의 노드 (종종 여러 데이터 센터)에 데이터베이스 배포

Performance Scale

  • SLA를 유지하면서 초당 100,000 개 이상의 데이터베이스 읽기 및 쓰기 지속

Data Scale

  • 10억개 이상의 문서를 데이터베이스에 저장
서비스 수준 협약서
(Service Level Agreement)는 서비스를 제공함에 있어서 공급자와 사용자간에 서비스에 대하여 측정지표와 목표 등에 대한 협약서이다.

 

논리적 저장구조 비교

RDBMS MongoDB
Database Database
Table Collection
Tuple/Row Document
Column Key/Field
Table Join Embedded Documents
Primary Key Primary Key(_id)

 

Data Type

Type Number Alias
Double 1 double
String 2 string
Object 3 object
Array 4 array
Binary data 5 binData
Undefined 6 undefined
ObjectId 7 objectId
Boolean 8 bool
Date 9 date
Null 10 null
Regular Expression 11 regex
DBpointer 12 dbPointer
JavaScript 13 javascript
Symbol 14 symbol
JavaScript (with scope) 15 javascriptWithScope
32-bit integer 16 int
Timestamp 17 timestamp
64-bit integer 18 long
Decimal128 19 decimal
Min key -1 minKey
Max key 127 maxKey

 

Document Structure

  • 데이터 레코드를 BSON 문서로 저장
  • 필드와 값의 쌍으로 구성 ( field : value )
  • 필드이름은 null문자를 사용할 수 없다
  • 다양한 Type의 값을 포함할 수 있다
BSON이란 Binary json의 약자로 JSON과 유사한 2진 표현

 

_id key

  • 12바이트의 hexadecimal값
  • 각 document의 유일함을 제공
  • 4바이트는 현재 timestamp
  • 3바이트는 machine id
  • 2바이트는 mongodb 서버의 프로세스 id
  • 3바이트는 순차번호

 

Data Modeling

  • 사용자 요구에 따라 스키마 작성
  • 읽을 때 조인하는게 아니고 데이터를 작성할 때 join
  •  

모델링 6가지 원칙

  1. 피할 수 없는 이유가 없다면 문서에 포함
  2. 객체에 직접 접근할 필요가 있다면 문서에 포함하지 말 것
  3. 배열이 지나치게 커져서는 안됨
  4. 어플리케이션 레벨 join을 두려워 하지 말 것
  5. 비정규화는 읽기/쓰기 비율을 고려할 것
  6. 각각의 어플리케이션 데이터 접근 패턴에 따라서 데이터를 모델링 수행

 

관계 작성방법

  • One to Few 하나당 적은 수
  • One to Many 하나 당 여럿
  • One to Squillions 하나 당 많은 수
  • 양방향 참조와 비정규화 활용

 

One to Few

  • 하나 당 적은 수의 관계가 필요한 경우
  • 쿼리 한 번에 모든 정보를 가져올 수 있다
  • 내포된 엔티티만 독자적으로 불러올 수 없다

 

One to Many

  • 부모가 되는 문서에 배열로 자식 문서의 ObjectID를 저장하는 방식으로 구현
  • DB레벨이 아닌 어플리케이션 레벨join으로 두 문서를 연결해 사용
  • 각각의 문서를 독자적으로 다룰 수 있어 쉽게 추가, 갱신 및 삭제가 가능한 장점이 있지만 여러번 호출해야 하는 단점
  • join이 어플리케이션 레벨에서 처리되기 때문에 N to N도 쉽게 구현가능

 

One to Squillion

  • 이벤트 로그와 같이 엄청나게 많은 데이터가 필요한 경우, 단일 문서의 크기는 16MB를 넘지 못하는 제한이 있어서 One to Many 같은 방식으로 접근할 수 없다
  • 부모 참조 방식을 활용해야 한다

 

양방향 참조(Two Way Referencing)

  • One to Many 관계에서 반대 문서를 찾을 수 있게 양쪽에 참조
  • 단일로 atomic한 업데이트를 할 수 없다

 

Many to One 관계 비정규화

  • Many to One에서 필수적으로 2번 이상 쿼리를 해야 하는 형태를 벗어나기 위해, 비정규화
  • 비정규화로 매번 데이터를 불러오는 비용을 줄이는 장점, 그러나 part의 name을 갱신할 때는 모든 product의 문서에 포함된 이름도 변경해야 하는 단점
  • 비정규화는 업데이트가 적고, 읽는 비율이 높을때 유리
  • 업데이트가 잦은 데이터에는 부적합

 

One to Many 관계 비정규화

  • 이름 변경시 Many to One에 비해 수정해야 하는 범위가 더 넓은 단점

 

One to Squillion 관계 비정규화

 

 


실습

DB생성 : use DATABASE_NAME

선택된 DB확인 : db

DB 목록조회 : show dbs

Database 제거 : db.dropDatabase()

use test
db
show dbs
db.dropDatabase()

//db.dropDatabase()로 DB 삭제 시, use DATABASE_NAME으로 접속 후 실행

Collection 생성 : db.createCollection(name, [options])

Options 설명
capped
  • true로 설정하면 capped collection을 활성화
  • capped collection이란, 고정된 크기를 가진 collection으로, size가 초과되면 가장 오래된 데이터를 덮어씀
  • true로 설정하면 size값을 반드시 설정
autoIndexId
  • true로 설정하면 _id필드에 index를 자동으로 생성
  • default값은 false
size
  • capped collection을 위해 해당 collection의 최대 사이즈를 ~바이트로 지정
max
  • 해당 collection에 추가 할 수 있는 최대 document 개수를 설정

Collection 조회 : show collections

Collection 제거 : db.COLLECTION_NAME.drop()

db.createCollection("mycol",{capped:true,autoIndexId:true,size:6142800,max:10000})

db.people.insert({"name":"korea"})
// document를 추가하면 자동으로 collection이 생성

show collection
// people이 생긴것을 확인할 수 있다.

Document 추가 : db.COLLECTION_NAME.insert(document)

Document 조회 : db.COLLECTION_NAME.find(query, projection)

파라미터 설명
query
  • 조회할 때 기준을 정함
  • 기준이 없이 collection에 있는 모든 document를 조회할 때 이 매개변수를 비우거나 비어있는 document {}를 전달
projection
  • 조회할 때 보여질 field를 선언

 

query연산자

구분 연산자 설명
비교 $eq 주어진 값과 일치하는 값
$gt 주어진 값보다 큰 값
$gte 주어진 값보다 크거나 같은 값
$lt 주어진 값보다 작은 값
$lte 주어진 값보다 작거나 같은 값
$ne 주어진 값과 일치하지 않는 값
$in 주어진 배열 안에 속하는 값
$nin 주어진 배열 안에 속하지 않는 값
논리 $or  주어진 조건중 하나라도 true일 때
$and 주어진 모든 조건이 true일 때
$not 주어진 조건이 false일 때
$nor 주어진 모든 조건이 false일 때
db.COLLECTION_NAME.find()
// 모든 document 조회

db.COLLECTION_NAME.find().pretty()
// 모든 document 보기 좋게 조회

db.COLLECTION_NAME.find({"writer":"Velopert"}).pretty()
// write값이 Velopert인 document 조회

db.COLLECTION_NAME.find({"like":{lte:30}}).pretty()
// like값이 30이하인 document 조회

db.COLLECTION_NAME.find({"like":{$ge:10,$lt:30}}).pretty()
// like값이 10보다 크고 30보다 작은 document 조회

db.COLLECTION_NAME.find({"writer":{$in:["Alpha","Bravo"]}}).pretty()
// writer값이 배열 ["Alpha","Bravo"]안에 속하는 값인 document 조회

db.COLLECTION_NAME.find({$or:[{"title":"article01"},{"writer","Alpha"}])
// title값이 article01이거나 writer값이 Alpha인 document 조회

db.COLLECTION_NAME.find({$and:[{"writer":"Velopert"},{"likes":{$lt:10}}]})
db.COLLECTION_NAME.find({"writer":"Velopert","likes":{$lt:10}})
// writer값이 Velopert이고 likes값이 10미만인 document 조회(2가지 방법)

 

정규표현식 연산자

연산자 설명
i 대소문자 무시
m 정규식에서 anchor(^)를 사용할 때 값에 \n이 있다면 무력화
x 정규식 안에 있는 whitespace를 모두 무시
s dot(.) 사용할 때 \n을 포함해서 매치
$where javascript expression을 사용
$elemMatch Embedded Documents 배열을 쿼리할 때 사용
$slice 연산자는 Embedded Document 배열을 읽을때 limit 설정
db.COLLECTION_NAME.find({"title":/article0[1-2]/}
// 정규식 artice0[1-2]에 일치하는 값이 title에 있는 document 조회

db.COLLECTION_NAME.find({$where:"this.comments.length == 0"})
// comments 필드가 비어있는 document 조회

db.COLLECTION_NAME.find({"comments":{$elemMatch:{"name":"Charlie"}}})
// comments중 Charlie가 작성한 덧글이 있는 documnet 조회

db.COLLECTION_NAME.find({},{"_id":false,"tite":true,"content":true})
// article의 title과 content만 조회

db.COLLECTION_NAME.find({"title":"article03"},{comments:{$slice:1}})
// title값이 article03인 document에서 덧글은 하나만 보이게 출력

db.COLLECTION_NAME.find({"comments":{$elemMatch:{"name":"Charlie"}}},
                        {"title":true, "comments":{$elemMatch:{"name":"Charlie"}},
                        {"comments.name":true, "comments.message":true})
// comments중 Charlie가 작성한 덧글이 있는 document중 제목, 그리고 Charlie의 덧글만 조회

데이터 정렬 : cursor.sort(document) / cursor.sort( {KEY:value} )

출력갯수 제한 : cursor.limit( value )

출력 시작부분 설정 : cursor.skip( value )

db.COLLECTION_NAME.sort( {"_id":1} )
// _id의 값을 사용하여 오름차순으로 정렬

db.COLLECTION_NAME.sort({"amount":1,"_id":-1})
// amount값을 사용하여 오름차순으로 정렬하고, 정렬한 값에서 id값은 내림차순으로 정렬

db.COLLECTION_NAME.limit(3)
// 출력 개수를 3개로 제한

db.COLLECTION_NAME.skip(2)
// 2개의 데이터를 생략하고 3번째부터 출력
var showPage = function(page){return db.orders.find().sort({"_id":-1}).skip((page-1)*2).limit(2);
// order를 최신순으로 한 페이지당 2개씩 출력

Aggregation

연산자 예시
$sum db.COLLECTION_NAME.aggregate([{$group:{_id:"$by_user",num_tutorial:{$sum:"$likes"}}}])
$avg db.COLLECTION_NAME.aggregate([{$group:{_id:"$by_user",num_tutorial:{$avg:"$likes"}}}])
$min db.COLLECTION_NAME.aggregate([{$group:{_id:"$by_user",num_tutorial:{$min:"$likes"}}}])
$max db.COLLECTION_NAME.aggregate([{$group:{_id:"$by_user",num_tutorial:{$max:"$likes"}}}])
$push db.COLLECTION_NAME.aggregate([{$group:{_id:"$by_user",url:{$push:"$url"}}}])
$addToset db.COLLECTION_NAME.aggregate([{$group:{_id:"$by_user",url:{$addToset:"$url"}}}])
$first db.COLLECTION_NAME.aggregate([{$group:{_id:"$by_user",url:{$first:"$url"}}}])
$last db.COLLECTION_NAME.aggregate([{$group:{_id:"$by_user",url:{$last:"$url"}}}])

데이터 수정 : update()

파라미터 설명
*query 업데이트 할 document의 criteria를 정함, find() 메소드에서 사용하는 query와 같다
*update document에 적용할 변동사항
upsert default는 false로 true로 설정되면 query한 document가 없을 경우, 새로운 document를 추가
multi default는 false로 true로 설정되면 여러개의 document를 수정
writeConcern wtimeout 등 document 업데이트할 때 필요한 설정값
db.COLLECTION_NAME.update(
   <query>,
   <update>,
   {
    upsert:<boolean>,
    multi:<boolean>,
    writeConcern:<document>
   }
)

 

 

 


Java 연동하기

Project 생성

  1. 이클립스 create a project
  2. Maven > Maven project 선택 > Next..
  3. Group Id 적는 창이 나오면 Group ID에 nosql 입력
  4. Artifact Id에는 mongo 입력 > pakages에 nosql.mongo.lab 입력 > Finish

pom.xml 수정

아래 내용을 <dependencies>에 추가

<dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongo-java-driver</artifactId>
        <version>3.5.0</version>
</dependency>
<dependency>
		<groupId>org.mongodb</groupId>
		<artifactId>bson</artifactId>
		<version>3.2.2</version>
</dependency>

 

Class 작성

  1.  좌측에 mongo 폴더 클릭
  2.  src/main/java 클릭 > nosql.mongo.lab 우클릭
  3.  New > Class 클릭 > Name에 Main 입력 후 Finish
  4.  아래 코드를 작성하고 왼쪽위에 Run main(초록색 재생아이콘) 클릭
  5.  console 창에서 결과 확인
package nosql.mongo.lab;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
 
   
public class Main {
    public static void main(String args[]){
        String MongoDB_IP = "127.0.0.1";
        int MongoDB_PORT = 27017;
        String DB_NAME = "test";
 
        String client_url = "mongodb://" + MongoDB_IP + ":" + MongoDB_PORT + "/" + DB_NAME;
        MongoClientURI uri = new MongoClientURI(client_url);
 
        // Connecting to the mongodb server using the given client uri.
        MongoClient mongoClient = new MongoClient(uri);
     
        
        MongoDatabase db = mongoClient.getDatabase(DB_NAME);       
    
        
        MongoCollection<Document> col = db.getCollection("books");


        FindIterable<Document> fi = col.find();
        MongoCursor<Document> cursor = fi.iterator();
        try {
            while(cursor.hasNext()) {
               System.out.println((cursor.next().toJson()));
            }
        } finally {
            cursor.close();
        }
    }
} 
728x90
반응형

'기타' 카테고리의 다른 글

Tensorflow (2)  (0) 2019.05.08
TensorFlow  (0) 2019.05.07
Redis  (0) 2019.05.07
Cassandra  (0) 2019.05.07
NoSQL  (0) 2019.05.07
Comments