MongoDB - 데이터 타입 - Data Type

Share

Last Updated on 2월 3, 2023 by Jade(정현호)

안녕하세요 
이번 포스팅에서는 MongoDB 의 데이터 타입(Data Type) 에 대해서 정리해보려고 합니다.        

지원 데이터 타입

BSON은 MongoDB에서 문서를 저장하고 원격 절차를 호출하는 데 사용 되는 이진 직렬화 형식입니다.
BSON 사양은 아래 링크에서 확인 하실 수 있습니다.


즉 BSON 에서 지원되는 데이터 타입을 MongoDB 에서 사용할 수 있음을 의미 합니다.

BSON 유형에는 다음 표에 나열된 정수 및 문자열 식별자를 사용할 수 있습니다.

TypeType IDAliasNotes
Double1"double"
String2"string"
Object3"object"
Array4"array"
Binary data5"binData"
Undefined6"undefined"Deprecated.
ObjectId7"objectId"
Boolean8"bool"
Date9"date"
Null10"null"
Regular Expression11"regex"
DBPointer12"dbPointer"Deprecated.
JavaScript13"javascript"
Symbol14"symbol"Deprecated.
JavaScript code with scope15"javascriptWithScope"Deprecated in MongoDB 4.4.
32-bit integer16"int"
Timestamp17"timestamp"
64-bit integer18"long"
Decimal12819"decimal"
Min key-1"minKey"
Max key127"maxKey"


위와 같은 데이터 타입을 지원하며 각 데이터 타입에 대해서는 아래 각 항목별로 내용을 살펴보도록 하겠습니다.
          

Binary Data

Binary Data(또는 binData) 값은 바이트 배열입니다. 즉, 이름이 의미하는 바와 같이 필드 값에 이진(Binary) 데이터를 저장합니다.

binData 값에는 이진 데이터를 해석하는 방법을 나타내는 Subtype(하위 유형)이 있습니다.

다음 표는 Subtype을 보여줍니다.

Number(Sub Type ID) Subtype
0 Generic binary subtype
1 Function data
2 Binary (old)
3 UUID (old)
4 UUID
5 MD5 - Hash Function
6 Encrypted BSON value
7 Compressed time series data
New in version 5.2.
128 Custom data

128 to 255 는 유저 정의(defined) 서브타입 입니다.

Binary Data 를 입력시에는 서브타입 ID 와 Encode 된 Base64 형태로 입력하며, 입력된 Base64는 내부적으로 32-bit 길이의 Binary로 저장 됩니다.


이 데이터 유형은 관계형 데이터베이스 관리 시스템에서 Blob 유형에 해당(또는 유사) 합니다.

다만 BSON 에서 단일 도큐먼트의 크기가 16MB로 제한되어 있기 때문에, 바이너리 데이터의 전체 크기와 다른 필드가 합쳐서 16MB 미만인 경우 Binary Data 유형을 활용할 수 있습니다.
              

ObjectId

ObjectId 는 작고 고유할 가능성이 높으며 빠르게 생성되고 순서가 지정됩니다. ObjectId 값은 길이가 12바이트이며 문자와 숫자로 구성된 값입니다.

ObjectId 는 주로 Primary Key 인 "_id" 필드의 값으로 용도로 사용 됩니다.

12byte의 hexadecimal(16진수) 로 표현 되며, ObjectId 의 구성은 시간이 지남에 따라 변경 되었습니다.


버전에 따라 일부 구성이 다르며, MongoDB 3.4버전 부터 다음과 같은 정보로 구성됩니다.

  • 4-byte : 유닉스 타임스탬프을 의미하며, 이 값은 Unix epoch(1970년 1월 1일 00:00:00) 시간부터 초 단위로 측정된 값을 의미합니다.
  • 5-byte : 임의 값(랜덤값)
  • 3-byte : 증분 카운터, 임의의 값으로 초기화됩니다.


MongoDB 3.2 버전까지는 다음과 같은 정보로 구성되었습니다.

  • 4-byte : 유닉스 타임스탬프을 의미하며, 이 값은 Unix epoch(1970년 1월 1일 00:00:00) 시간부터 초 단위로 측정된 값을 의미합니다.
  • 3-byte : machine ID
  • 2-byte : 프로세스 ID
  • 3-byte : 증분 카운터, 임의의 값으로 초기화됩니다.


ObjectId 는 프라이머리 키인 "_id" 에만 사용되는 것은 아니며, 사용자 필드에 랜덤한 값을 할당해야 하는 경우에도 사용할 수 있습니다.
ObjectId 는 타임스탬프 정보를 포함 하고 있기 때문에 도큐먼트의 생성 시간으로 정렬하는 용도로도 사용할 수 있습니다.
         

String

BSON 문자열은 UTF-8 을 사용 합니다.

일반적으로 각 프로그래밍 언어의 드라이버는 문자열을 MongoDB에 저장할 경우 UTF-8 로 변환해서 BSON 도큐먼트에 저장합니다.
이를 통해 대부분의 국제 문자를 BSON 문자열에 쉽게 저장할 수 있습니다.

또한 MongoDB $regex 쿼리는 정규화 문자열에서 UTF-8을 지원합니다.

MongoDB 3.4 버전 부터는 String 에 Collation 을 관리할 수 있는 기능이 추가 되었습니다.

대소문자 비교인 case insensitivity 나 국가별 언어 등의 기능을 사용할 수 있습니다.
사용법에 대한 자세한 사항은 아래 문서를 참조하시면 됩니다.

             

Timestamp

BSON에는 내부 MongoDB 사용을 위한 특별한 타임스탬프 유형이 있으며 일반 날짜 유형과 연결되어 있지 않습니다.
이 내부 타임스탬프 유형은 다음과 같은 64비트(8byte) 값입니다.

가장 중요한 첫번째 32비트(4byte)는 time_t값입니다.
Unix Epoch 값으로, 1970년 1월 1일 00:00:00 협정 세계시(UTC) 부터의 경과 시간을 초로 환산한 값을 의미 합니다.

최하위(두번째) 32비트(4byte)는 1초 단위로 증분 서수로 같은 Unixtime 안에서 증가 합니다.
2개의 값을 합쳐서 사용하여 Timestamp 는 서버내에서 유일성을 보장받도록 설계되어 있습니다.

아래와 같은 insertOne 메서드를 짧은시간안에 호출하면 1초내 입력 됨에 따라서 2번째 32비트(4byte) 는 숫자가 증가하게 됩니다.
> db.testts.insertOne( { ts: new Timestamp() } )

> db.testts.find()
{ "_id" : ObjectId("63c5db4d0ba8e3322fa5db25"), "ts" : Timestamp(1673911117, 1) }
{ "_id" : ObjectId("63c5db4d0ba8e3322fa5db26"), "ts" : Timestamp(1673911117, 2) }


1초를 넘어서 insertOne 메서드를 사용하여 입력하면 하위의 32비트는 1로 되는 것을 확인 할 수 있습니다.

> db.testts.find()
{ "_id" : ObjectId("63c5db4d0ba8e3322fa5db25"), "ts" : Timestamp(1673911117, 1) }
{ "_id" : ObjectId("63c5db4d0ba8e3322fa5db26"), "ts" : Timestamp(1673911117, 2) }
-> { "_id" : ObjectId("63c5db880ba8e3322fa5db27"), "ts" : Timestamp(1673911176, 1) }
-> { "_id" : ObjectId("63c5db8a0ba8e3322fa5db28"), "ts" : Timestamp(1673911178, 1) }


dateToString 메서드를 이용하면 Timestamp 값을 ISO 8601인 ISODate 유형으로 변환해서 볼 수 있습니다.

> db.testts.find({}, {ts:{$dateToString:{date:"$ts"}}})
{ "_id" : ObjectId("63c5db4d0ba8e3322fa5db25"), "ts" : "2023-01-16T23:18:37.000Z" }
{ "_id" : ObjectId("63c5db4d0ba8e3322fa5db26"), "ts" : "2023-01-16T23:18:37.000Z" }
{ "_id" : ObjectId("63c5db880ba8e3322fa5db27"), "ts" : "2023-01-16T23:19:36.000Z" }
{ "_id" : ObjectId("63c5db8a0ba8e3322fa5db28"), "ts" : "2023-01-16T23:19:38.000Z" }

* ISODate는 UTC 시간대에서 끝에 Z가 붙는 것이 특징입니다.

BSON의 타임스탬프 유형은 MongoDB의 내부적인 사용 용도 입니다. 이러한 Timestamp가 MongoDB 내부에서 사용되는 용도 oplog 에서 대표적으로 사용이 됩니다.

대부분의 경우 응용프로그램 개발에서 BSON의 date 유형을 사용 합니다.
               

Date

BSON의 Date는 Unix epoch (1970년 1월 1일) 이후의 밀리초 수를 나타내는 64비트 정수입니다.
표현할 수 있는 날짜의 범위는 2억 9천만년으로 추정 됩니다.

공식적인 BSON 규격의 date 유형은 UTC 타입의 날짜 시간으로 나타냅니다.
BSON의 date 유형은 signed 입니다. 즉 음수 값은 1970년 이전의 날짜를 나타냅니다.

  • signed 는 음수,양수 모두 사용
  • unsigned 는 양수만 사용


mongosh 에서는 ISODate() 와 new Date() 메서드를 이용해서 날짜 시간을 입력 할 수 있습니다.
date 타입에서는 ISO-8601 날짜 문자열 형식을 사용 합니다.


• ISO-8601 표시 예시)
2016-10-27T17:13:40+00:00 || 2016-10-27T17:13:40Z || 20161027T171340Z

중간의 T 문자는 시간 영역의 시작을 표시하는 문자 입니다.


MongDB의 date 타입에서는 다음 형식을 허용합니다.

  • new Date("<YYYY-mm-dd>") : 지정된 날짜의 ISODate를 반환합니다.
  • new Date("<YYYY-mm-ddTHH:MM:ss>") : 클라이언트의 현지 시간대에서 datetime을 지정하고 UTC에서 지정된 datetime으로 ISODate를 반환합니다.
  • new Date("<YYYY-mm-ddTHH:MM:ssZ>") : UTC로 datetime을 지정하고 UTC로 지정된 datetime으로 ISODate를 반환합니다.
  • new Date(<integer>) : 날짜 시간을 UNIX epoch(1970년 1월 1일) 이후의 밀리초로 지정하고 결과 ISODate 인스턴스를 반환합니다.


new Date()는 현재 날짜를 Date 개체로 반환하며, ISODate helper로 Date 개체를 감싸게 됩니다.
ISODate는 UTC 입니다.

입력은 아래와 같은 방식으로 할 수 있습니다.

## 날짜 시간 입력
> db.testdt.insertOne({_id : 1, name : 'a', dt : ISODate()})
> db.testdt.insertOne({_id : 2, name : 'b', dt : ISODate("2023-01-01")})
> db.testdt.insertOne({_id : 3, name : 'c', dt : ISODate("2022-07-25 15:10")})
> db.testdt.insertOne({_id : 4, name : 'd', dt : ISODate("2022-08-15 15:05")})
> db.testdt.insertOne({_id : 5, name : 'e', dt : ISODate("2022-11-07")})
> db.testdt.insertOne({_id : 6, name : 'f', dt : new Date()})
> db.testdt.insertOne({_id : 7, name : 'g', dt : ISODate("2022-10-15T00:00:00Z")})


## 입력한 내용 조회
> db.testdt.find()
{ "_id" : 1, "name" : "a", "dt" : ISODate("2023-01-17T06:01:54.176Z") }
{ "_id" : 2, "name" : "b", "dt" : ISODate("2023-01-01T00:00:00Z") }
{ "_id" : 3, "name" : "c", "dt" : ISODate("2022-07-25T15:10:00Z") }
{ "_id" : 4, "name" : "d", "dt" : ISODate("2022-08-15T15:05:00Z") }
{ "_id" : 5, "name" : "e", "dt" : ISODate("2022-11-07T00:00:00Z") }
{ "_id" : 6, "name" : "f", "dt" : ISODate("2023-01-17T06:02:25.570Z") }
{ "_id" : 7, "name" : "g", "dt" : ISODate("2022-10-15T00:00:00Z") }

                 

숫자 - Integer,Double,Long

MongoDB는 32비트 정수형, 64비트 정수형을 지원하고 기본값으로(별도로 타입을 지정하지 않았다면) 64비트 부동 소수점 double 로 처리 합니다.

double 형, int형 , long형으로 각각 입력해보도록 하겠습니다.

# double형
> db.testnumber.insertOne({ "_id" : 1, "num": 1} )
# 별도의 타입을 지정하지 않았기 때문에 double 형으로 저장


# int형
> db.testnumber.insertOne( { "_id" : 2,"num": NumberInt(1234567890)} )
# NumberInt 을 사용하여 명시적으로 32비트 정수로 저장


# long형
> db.testnumber.insertOne( {"_id" : 3,"num": NumberLong(1234567890)} )
# NumberLong 을 사용하여 명시적으로 64비트 정수로 저장


NumberLong() 생성자가 mongo 셸에서 정수 입력 값을 허용하지만(즉, 따옴표 없이) 이는 권장되지 않습니다.

JavaScript에서 정의한 Number.MAX_SAFE_INTEGER(숫자 2^53 - 1)보다 큰 정수 값을 지정하면 예기치 않은 동작이 발생할 수 있습니다.

즉, NumberLong() 나 NumberInt() 를 사용할 경우 큰 숫자의 경우 "(큰따옴표) 를 사용하는 것이 권장 됩니다.


다만 double형(기본) 입력시 큰따옴표(") 을 사용할 경우 어떻게 되는지도 확인해보는 것이 좋습니다.

> db.testnumber.insertOne({ "_id" : 4, "num": "1"} )


일단 4개의 값을 모두 입력한 상태이며, find() 메서드로 컬렉션을 조회한 결과는 아래와 같습니다.

> db.testnumber.find()
{ "_id" : 1, "num" : 1 }
{ "_id" : 2, "num" : 1234567890 }
{ "_id" : 3, "num" : NumberLong(1234567890) }
{ "_id" : 4, "num" : "1" }


$type 함수를 통해서 데이터 타입별로 조회해볼 수 있으며 $type 에 대해서는 아래서 더 자세하게 설명되어 있습니다.
4개의 타입에 대해서 조회해보도록 하겠습니다.

> db.testnumber.find( { "num" : { $type : "double" } } )
{ "_id" : 1, "num" : 1 }


> db.testnumber.find( { "num" : { $type : "int" } } )
{ "_id" : 2, "num" : 1234567890 }


> db.testnumber.find( { "num" : { $type : "long" } } )
{ "_id" : 3, "num" : NumberLong(1234567890) }


> db.testnumber.find( { "num" : { $type : "string" } } )
{ "_id" : 4, "num" : "1" }

입력된 4개의 도큐먼트가 다 각각의 데이터타입을 가지며, 마지막에 입력한("_id" : 4) 는 위의 조회결과 처럼 숫자가 아닌 string 데이터 타입인 것을 확인 할 수 있습니다.

NumberInt 과 NumberLong 은 큰따옴표(") 을 사용해도 string이 아닌 지정한 int 나 long 데이터타입으로 사용됩니다.
         

Decimal

Decimal 은 MongoDB 3.4 버전에서 부터 추가 된 데이터 타입 입니다.

mongo 쉘에서는 기본적으로 모든 숫자를 64비트 부동 소수점 double값으로 취급하지만, 부동 소수점이 아닌 저 정밀한 소수점 값인 고정 소수점 유형의 데이터 타입이 필요할 수 있습니다.

정확한 정밀도로 십진수 반올림을 에뮬레이트할 수 있는 128비트 십진수 기반(decimal-based) 부동 소수점 값을 명시적으로 지정할 수 있는 NumberDecimal()를 제공합니다.
NumberDecimal() 을 통해서 Decimal 데이터 타입, 즉 고정 소수점 으로 숫자를 저장할 수 있습니다.

이 기능은 정밀한 값이 필요한 재무, 세금 및 과학 계산과 같은 화폐 데이터 를 처리하는 애플리케이션을 위한 것입니다.
          

데이터 타입 확인

$type 연산자를 사용하여 데이터 타입 유형별로 필드를 쿼리 하는 것을 지원합니다.

syntax:
{ field: { $type: <BSON type> } }


사용예시)
db.testnumber.find( { "num" : { $type : "double" } } )
또는
db.testnumber.find( { "num" : { $type : 1 } } )


$type 연산자에 데이터 타입명을 쓰거나 타입 ID 를 입력 하면 됩니다.


BSON Type 정보 입니다.(블로그 처음 부분의 같은 표임)

TypeType IDAliasNotes
Double1"double"
String2"string"
Object3"object"
Array4"array"
Binary data5"binData"
Undefined6"undefined"Deprecated.
ObjectId7"objectId"
Boolean8"bool"
Date9"date"
Null10"null"
Regular Expression11"regex"
DBPointer12"dbPointer"Deprecated.
JavaScript13"javascript"
Symbol14"symbol"Deprecated.
JavaScript code with scope15"javascriptWithScope"Deprecated in MongoDB 4.4.
32-bit integer16"int"
Timestamp17"timestamp"
64-bit integer18"long"
Decimal12819"decimal"
Min key-1"minKey"
Max key127"maxKey"

            

Reference

Reference URL
mongodb.com/bson-types
mongodb.com/limits
mongodb.com/ObjectId
mongodb.com/Date
mongodb.com/shell-types
mongodb.com/type
mongodb.com/replica-set-oplog
wikipedia.org/ISO_8601


관련된 다른 글

 

 

 

 

 

                  

0
글에 대한 당신의 생각을 기다립니다. 댓글 의견 주세요!x