IT Log
MongoDB 본문
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가지 원칙
- 피할 수 없는 이유가 없다면 문서에 포함
- 객체에 직접 접근할 필요가 있다면 문서에 포함하지 말 것
- 배열이 지나치게 커져서는 안됨
- 어플리케이션 레벨 join을 두려워 하지 말 것
- 비정규화는 읽기/쓰기 비율을 고려할 것
- 각각의 어플리케이션 데이터 접근 패턴에 따라서 데이터를 모델링 수행
관계 작성방법
- 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 |
|
autoIndexId |
|
size |
|
max |
|
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 |
|
projection |
|
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 생성
- 이클립스 create a project
- Maven > Maven project 선택 > Next..
- Group Id 적는 창이 나오면 Group ID에 nosql 입력
- 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 작성
- 좌측에 mongo 폴더 클릭
- src/main/java 클릭 > nosql.mongo.lab 우클릭
- New > Class 클릭 > Name에 Main 입력 후 Finish
- 아래 코드를 작성하고 왼쪽위에 Run main(초록색 재생아이콘) 클릭
- 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