데이터형
몽고DB는 도큐먼트의 값으로 다양한 데이터형을 지원한다.
기본 데이터형
몽고DB에서 도큐먼트는 자바스크립트 객체와 개념적으로 닮았다는 점에서 JSON과 닮았다라고 생각할 수 있다.
JSON은 데이터의 간단한 표현이다. 명세는 한 단락 정도로 설명되며 여섯 가지 데이터형만을 열거한다.
따라서 이해하고, 구문을 분석하고, 기억하기가 쉬워 여러 방면에서 유용하다. 한편으로는 데이터형이 null, 불리언, 숫자, 문자열, 배열, 객체만 지원하기 때문에 JSON의 표현력은 제한적이다.
하지만 JSON은 데이터베이스와 연동할 때는 날짜형이 따로 없어 다루기가 성가시고, 숫자형이 있기는 하지만 한 가지 뿐이다.
부동소수점형(float)과 정수형을 표현하는 방법은 없으며 32비트와 64비트도 구별되지 않는다.
함수나 정규 표현식과 같은 흔히 쓰는 데이터형을 표현하는 방법도 없다.
몽고DB는 JSON의 키/값 쌍 성질을 유지하면서 추가적인 데이터형을 지원한다.
각 데이터형 값을 표시하는 방식은 언어에 따라 다르지만, 다음 목록은 지원되는 데이터형이 셸에서 어떻게 도큐먼트의 일부로 표현되는지 나타낸다.
- null : null 값과 존재하지 않는 필드를 표현
ex) {"x": null} - boolean : 참과 거짓을 값에 사용
ex) {"x": true} - 숫자 : 셸은 64비트 부동소수점 수를 기본으로 사용
ex) {"x": 3.14, "y": 6} - 4바이트 혹은 8바이트 부호 정수 : NumberInt(4byte) 혹은 NumberLong(8byte) 클래스 사용
ex) {"x": NumberInt("3"), "y": NumberLong("6")} - 문자열 : 어떤 UTF-8 문자열이든 문자열형으로 표현
ex) {"x": "string"} - 날짜 : 1970년 1월 1일부터의 시간을 1/1000초 단위로 나타내는 64비트 정수로 날짜 저장(표준 시간대는 저장하지 않는다.)
ex) {"x": new Date()} - 정규 표현식 : 쿼리는 자바스크립트의 정규 표현식 문법을 사용
ex) {"x": /foobar/i} - 배열 : 값의 Set이나 List를 배열로 표현
ex) {"x": ["a", "b", "c"]} - 내장 도큐먼트 : 도큐먼트는 부모 도큐먼트의 값으로 내장된 도큐먼트 전체를 포함
ex) {"x": {"foo": "bar"}} - 객체 ID : 객체 ID는 도큐먼트용 12바이트 ID
ex) {"x": ObjectId()} - 이진 데이터 : 셸에서는 조작 불가능
- 코드 : 쿼리와 도큐먼트는 임의의 자바스크립트 코드를 포함할 수 있다.
ex) {"x": function() { /* ... */ }}
날짜
자바스크립트에서 Date 클래스는 몽고DB의 날짜를 표현하는데 사용한다.
새로운 객체를 생성할 때는 new Date()를 호출해야 한다. 그냥 Date()를 호출하게 되면 실제 Date가 아닌 날짜의 문자열 표현을 반환한다.
> new Date()
ISODate("2022-05-25T08:18:47.332Z")
> Date()
Wed May 25 2022 08:18:59 GMT+0000 (UTC)
항상 Date 생성자를 사용하도록 주의하지 않으면 문자열과 날짜가 뒤범벅되므로, CRUD 쿼리 등 거의 모든 작업에서 문제를 일으킬 수 있다.
셸에서는 날짜가 현지 시간대 설정을 이용해 표시된다. 하지만 데이터베이스 날짜는 1970년 1월 1일부터의 시간을 1/1000초 단위로 저장하며 표준 시간대 정보는 없다.
배열
배열은 정렬 연산(List, Stack, Queue)과 비정렬 연산(Set)에 호환성 있게 사용 가능한 값이다.
> things={"things": ["a", "b", 1, 2, 3.4]}
{ "things" : [ "a", "b", 1, 2, 3.4 ] }
배열은 서로 다른 데이터형을 값으로 포함할 수 있다.
사실 배열값은 일반적인 키/값 쌍을 지원하는 어떤 데이터형 값이든 될 수 있으며, 중첩 배열도 가능하다.
도큐먼트 내 배열의 장점으로 몽고DB가 배열의 구조를 이해한다는 점과, 배열의 내용에 작업을 수행하기 위해 내부에 도달하는 방법을 안다는 점이 있다. 따라서 배열에 쿼리하거나 배열의 내용을 이용해 인덱스를 만들 수 있다.
내장 도큐먼트
도큐먼트는 키에 대한 값이 될 수 있는데 이를 내장 도큐먼트라고 한다. 즉, 객체안에 객체가 있는 셈이다.
내장 도큐먼트를 사용해 데이터를 키/값 쌍의 평면적인 구조보다는 좀 더 자연스러운 방법으로 구성할 수 있다.
> userInfo={name: "hong gil dong", address: {zipcode: "1234", address: "서울시 강남구 역삼동", detailAddress: "103호"}}
{
"name" : "hong gil dong",
"address" : {
"zipcode" : "1234",
"address" : "서울시 강남구 역삼동",
"detailAddress" : "103호"
}
}
배열과 마찬가지로 몽고DB는 내장 도큐먼트의 구조를 이해하고, 인덱스를 구성하고, 쿼리하며, 갱신하기 위해 내장 도큐먼트 내부에 접근한다.
하지만 몽고DB에서는 더 많은 데이터 반복이 생길 수 있다는 단점이 있다.
관계형 데이터베이스에서 address가 분리된 테이블이 있고 주소의 오타를 고쳐야 한다고 가정하자.
userInfo와 address를 조인하면 같은 주소를 갖는 모든 사람의 주소를 수정할 수 있다.
하지만 몽고DB에서는 각 userInfo의 도큐먼트에서 오타를 수정해야 한다.
_id와 ObjectId
몽고DB에 저장된 모든 도큐먼트는 "_id" 키를 가진다.
"_id" 키 값은 어떤 데이터형이어도 상관없지만 "ObjectId"가 기본이다.
하나의 컬렉션에서 모든 도큐먼트는 고유한 "_id" 값을 가지며, 이 값은 컬렉션 내 모든 도큐먼트가 고유하게 식별되게 한다.
간단히 말해서 컬렉션에는 같은 "_id"를 가진 도큐먼트는 존재할 수 없다.
ObjectIds
ObjectId는 "_id"의 기본 데이터형이다.
ObjectId 클래스는 가벼우면서도, 여러 장비에 걸쳐 전역적으로 고유하게 생성하기 쉽게 설계됐다.
자동 증가하는 기본 키처럼 전통적인 것이 아닌 ObjectId를 사용하는 주요 이유는 몽고DB의 분산 특성 때문이다.
여러 서버에 걸쳐 자동으로 증가하는 기본 키를 동기화하는 작업은 어렵고 시간이 걸린다.
ObjectId는 12바이트 스토리지를 사용하며 24자리 16진수 문자열 표현이 가능하다.(바이트당 2자리를 사용한다.)
ObjectId가 흔히 거대한 16진수 문자열로 표현되긴 하지만 실제로 문자열은 저장된 데이터의 두 배만큼 길다는 점을 알아둬야 한다.
여러 개의 새로운 ObjectId를 연속으로 생성하면 매번 마지막 숫자 몇 개만 바뀐다.
몇 초 간격을 두고 생성하면 ObjectId의 중간 숫자 몇 개가 바뀐다.
이는 ObjectId가 생성되는 방식 때문이다.
첫 4바이트는 1970년 1월 1일부터의 시간을 1/1000초 단위로 저장하는 타임스탬프다.
다음 5바이트는 랜던 값이다.
최종 3바이트는 서로 다른 시스템에서 충돌하는 ObjectId들을 생성하지 않도록 랜덤 값으로 시작하는 카운터다.
고유한 ObjectId는 프로세스당 1초에 1677만 7216개까지 생성된다.
_id 자동 생성
도큐먼트를 입력할 때 "_id" 키를 명시하지 않으면 입력된 도큐먼트에 키가 자동으로 추가된다.
이는 몽고DB 서버에서 관리할 수 있지만 일반적으로는 클라이언트 쪽 드라이버에서 관리한다.
'MongoDB' 카테고리의 다른 글
몽고DB 도큐먼트 삽입, 삭제하기 (0) | 2022.05.26 |
---|---|
몽고DB 셸 사용해보기 (0) | 2022.05.26 |
몽고DB 셸 소개 (0) | 2022.05.25 |
Docker로 몽고DB 시작하기 (0) | 2022.05.25 |
몽고DB란 무엇인가? 몽고DB의 기초 (0) | 2022.05.24 |