성장, 그리고 노력

부족하더라도 어제보다 더 잘해지자. 노력은 절대 배신하지 않는다.

데이터베이스/MongoDB

MongoDB 기초

제이콥(JACOB) 2020. 5. 24. 15:13

 현 회사에서 GraphQL + mongoDB를 사용하다 보니, (물론 관계형 데이터 베이스도 사용하지만) 몽고 디비의 관한 내용을 얼추 알지만, 조금 더 정리하고 싶어서 시작한 포스팅. 얼른 뽀개자.


MongoDB란?

MongoDB는 도큐먼트 지향적인 데이터베이스다.

NoSQL (비관계형 데이터베이스)로 JSON Type의 데이터 저장 구조를 가지며, Memory Mapping 기술을 기반으로 Big Data 처리에 탁월한 성능을 제공하고 있다. 또한 시스템 장애가 발생하더라도 안전하게 데이터를 보관하고 운영할 수 있도록 샤딩(분산, Sharding)과 레플리카(복제, Replica)를 제공하고 있다. 좀 더 자세한 내용은 이후에 설명하도록 하겠다.

 

내부적으로 MongoDB는 Binary JSON 혹은 BSON의 형태로 도큐먼트를 저장한다.

다시 말해, MongoDB는 데이터를 컬렉션(Collection)에 도큐먼트(Document)로 저장하는 반면, MySQL 같은 관계형 데이터베이스에서는 데이터를 테이블의 행(Row)로 저장한다. 

관계형 데이터베이스 논리적 구조 vs 몽고 디비 용어 비교

관계형 데이터베이스 몽고디비
Table Collection
Row Document
Column Field
Primay key Object_Id Field
Relationship Embedded & Link
> use COMMERCE
> db.createCollection('order', {capped: true}, size: 200000})
{"ok" : 1}

> show collections
orders

> db.orders.renameCollection('checkout')
{"ok" : 1}
> db.checkout.drop()
true

save, insert, update문의 차이

MongoDB에서는 하나의 Document를 저장할 때 save, insert, update 메소드를 실행할 수 있다. 유사해 보이지만, 내부적으로 데이터를 처리하는 방법은 다르다. 

 

insert

Collection에 하나의 Document를 최초 저장할 때 사용되는 메서드

 

update

하나의 Document에서 특정 필드만을 수정하는 경우 사용되는 메서드. 이 때 하나의 Document가 여러 개의 필드로 구성되어 있더라도 해당 필드만 수정하기 때문에 빠른 시간 내에 효율적으로 데이터를 변경할 수 있다. 

> db.commerce.update({username: 'jacob'}, {$set: {address: 'Seoul ...'}})
WriteResult({"nMatched": 1, "nUpserted": 0, "nModified": 1})

 

단일 필드를 명시된 값으로 설정하는 $set 연사자를 사용하여 업데이트 문을 작성했다. 이 업데이트 쿼리는 username이 jacob인 도큐먼트를 찾아서 address 속성의 값을 Seoul ...로 수정하라고 지시하는 것이다. (연산자 업데이트)

save

하나의 Document에서 특정 필드만 변경하더라도 Document 단위로 데이터를 변경하는 방법. Document 단위로 데이터를 변경하는 경우 효율적이지만, 필드 단위로 변경하는 경우에는 update문이 더 효율적. 

> item = { label: "iphone" }

> db.order.save(option)
WriteResult({ "nInserted" : 1 })

> db.order.find()
{"_id": ObjectId("4c5d60c123eabefdafc1234b"), "label" : "iphone"}

> db.order.insert({label : "iphone 13", price: 999})
WriteResult({ "nInserted" : 1 })

> db.order.find()
{"_id": ObjectId("4c5d60c123eabefdafc1234b"), "label" : "iphone"}
{"_id": ObjectId("4c5d60c123eabefdafc5678b"), "label" : "iphone 13", "price": 999}

 

MongoDB는 스키마가 없다(schema-less)

데이터 베이스가 아닌 애플리케이션이 데이터 구조를 정한다.

 이것의 장점은 첫번째는 데이터베이스가 아닌 애플리케이션이 데이터 구조를 정한다는 것이다. 데이터의 구조가 빈번히 변경되는 개발 초기 단계에서 개발 속도를 단축시켜 줄 수 있다.

 또한 스키마가 없는 데이터 모델을 통해 가변적인 속성을 갖는 데이터를 표현할 수 있다. 즉 MongoDB는 애플리케이션 개발을 할 때 추후에 필요할 데이터 필드가 무엇인지에 대해서는 걱정할 필요가 없다. 

 

인덱스(Index)

MongoDB는 여러 개의 Secondary Index를 허용함으로써, 사용자가 넓은 범위의 쿼리를 최적화하도록 허용한다.

 MongoDB에서 index는 B-TREE로 구현되어 있다. 관계형 데이터베이스에서 기본적으로 제공되는 기능과 같이 index는 범위를 스캔하거나 정렬을 하는 것과 같이 다양한 쿼리에 최적화 되어있다. 

 MongoDB에서는 한 컬렉션에 64개까지 세컨더리 인덱스를 만들 수 있다. 오름차순, 내림차순, unique, compound-key, hash, text와 같이 관계형 데이터베이스 시스템에서 볼 수 있는 모든 인덱스가 가능하다. 데이터베이스를 효율적으로 운영하기 위해서는 인덱스를 잘 이해하는 것이 중요하다.

 

Indexes — MongoDB Manual

MongoDB provides a number of different index types to support specific types of data and queries. Text Indexes MongoDB provides a text index type that supports searching for string content in a collection. These text indexes do not store language-specific

docs.mongodb.com

 

그래서 MongoDB를 사용하는 이유가 뭔데?

아래 내용은 MongoDB의 설계자들의 말이므로... 나의 생각과는 상관없다...

 

MongoDB는 관계형 데이터베이스와 key-value 저장 시스템의 장점만 모아서 설계되었다.

 특히 key-value 저장 시스템은 시스템의 단순성으로 인해 속도가 매우 빠르고 확장도 상대적으로 용이하다. 물론 관계형 데이터베이스는 수평적인 확장은 어려운 반명에 다양한 데이터 모델과 강력한 쿼리 언어를 가지고 있다. MongoDB는 이 둘 사이의 장점을 취하는 타협점으로 의도었다.

 MongoDB는 웹 애플리케이션, 분석과 로깅 애플리케이션, 중간 정도의 캐시(cache)를 필요로 하는 애플리케이션에서 일차 데이터 저장 시스템으로 적합하다. 또한 스키마가 존재하지 않는 데이터를 저장하기가 용이하므로 미리 구조가 알려지지 않은 데이터를 저장하는데 유용하다.

관계형 데이터베이스보다 훨씬 더 신속하게 애플리케이션을 개발할 수 있다.

MongoDB에서는 고정된 스키마가 없기 때문에 애자일식 개발에 적합하며, 스키마를 적용시키고, 의논하고, 수정된 스키마를 반영하는데 들어가는 시간이 절약된다. 

 이외에도 빠른 원자적 업데이트와 복짭한 집계, 자동 장애조치와 복제, 수평적 확장을 위한 샤딩 등이 있다. 

 


도큐먼트 업데이트

모든 업데이트 쿼리는 최소 두 개의 매개변수가 필요하다. 첫 번째 매개변수는 업데이트할 도큐먼트에 대한 것이고, 두 번째 매개변수를 수정할 내용에 대한 것이다. 여러 관련 메서드가 있지만, update()단일 도큐먼트를 업데이트할 때 사용한다는 것을 먼저 알아두자. 

 

연산자 업데이트

> db.commerce.update({username: 'jacob'}, {$set: {address: 'Seoul ...'}})
WriteResult({"nMatched": 1, "nUpserted": 0, "nModified": 1})

> db.commerce.find()
{"_id": ObjectId("..."), "username":"jacob", "address": "Seoul ..."}

앞써 봤었던 이 구문이 연산자 업데이트이다. $set 연산자를 통해 업데이트를 했다.

 

대체 업데이트

이 방식은 도큐먼트의 필드 값을 설정하는 것이 아니라 아예 도큐먼트를 다른 것으로 대체하는 방식이다. $set을 의도했으나, 아래와 같이 작성해서 실수하는 경우가 많으니 꼭 봐두자.

> db.commerce.update({username: 'jacob'}, {address: 'Seoul ...'})
WriteResult({"nMatched": 1, "nUpserted": 0, "nModified": 1})

> db.commerce.find()
{"_id": ObjectId("..."), "address": "Seoul ..."}

_id는 같지만, 데이터는 대체되어버린다. 만약 address를 저장하는 것을 더 이상 원하지 않을 경우에는 $unset 연산자를 써서 그 값을 지울 수 있다. 

> db.commerce.update({username: 'jacob'}, {$unset: {address: 1}})
WriteResult({"nMatched": 1, "nUpserted": 0, "nModified": 1})

> db.commerce.find({username: 'jacob'})
{"_id": ObjectId("..."), "username":"jacob"}
반응형

'데이터베이스 > MongoDB' 카테고리의 다른 글

[MongoDB] Update ... 대치? 연산자? 뭐가 더 좋을까  (0) 2020.06.27
MongoDB TTL 컬렉션  (0) 2020.06.06