MongoDB - データ型
概要
BSON (Binary JSON) は、MongoDBがデータを保存および転送するために使用するバイナリ形式のドキュメントフォーマットである。
JSONを拡張した形式であり、JSONにはない追加のデータ型をサポートしている。
BSONは、以下に示す特徴を持つ。
- 効率性
- バイナリ形式により、パースと生成が高速である。
- トラバース性
- ドキュメント内の要素のサイズを含むため、スキャンが容易である。
- 拡張性
- 日付型、バイナリデータ型、ObjectId型など、JSONにはない型を追加している。
JSONとBSONの主な違いを以下に示す。
- JSONはテキスト形式、BSONはバイナリ形式である。
- JSONは制限されたデータ型のみをサポートするが、BSONは豊富なデータ型を提供する。
- BSONは、MongoDBの内部表現として最適化されている。
MongoDBがBSONを採用している理由は、以下の通りである。
- パフォーマンス
- バイナリ形式により、エンコード・デコードが高速である。
- ストレージ効率
- データのサイズ情報を含むため、効率的なストレージ管理が可能である。
- 型の豊富さ
- 日付、バイナリデータ、ObjectIdなど、データベースに必要な型を直接サポートしている。
データ型の選択は、ストレージ効率とパフォーマンスに大きく影響する。
適切なデータ型を選択することで、以下に示すメリットが得られる。
- ストレージサイズの最適化
- 32ビット整数と64ビット整数の適切な使い分けによるディスク使用量の削減。
- クエリパフォーマンスの向上
- インデックスサイズの最適化による検索速度の向上。
- 精度の保証
- Decimal128型の使用による金融計算の正確性の確保。
BSONデータ型一覧
BSONでは、各データ型にType Number (整数識別子) と Alias (文字列識別子) が割り当てられている。
これらの識別子は、クエリ時に $type 演算子で使用される。
| Type Number | Alias | 型名 | 説明 |
|---|---|---|---|
| 1 | "double" | Double | 倍精度浮動小数点数 |
| 2 | "string" | String | UTF-8文字列 |
| 3 | "object" | Object | 埋め込みドキュメント |
| 4 | "array" | Array | 配列 |
| 5 | "binData" | Binary Data | バイナリデータ |
| 6 | "undefined" | Undefined | 廃止 |
| 7 | "objectId" | ObjectId | 一意識別子 |
| 8 | "bool" | Boolean | 論理型 |
| 9 | "date" | Date | 日付時刻 |
| 10 | "null" | Null | Null値 |
| 11 | "regex" | Regular Expression | 正規表現 |
| 12 | "dbPointer" | DBPointer | 廃止 |
| 13 | "javascript" | JavaScript | JavaScriptコード |
| 14 | "symbol" | Symbol | 廃止 |
| 15 | "javascriptWithScope" | JavaScript with Scope | スコープ付きJavaScript (非推奨) |
| 16 | "int" | 32-bit Integer | 32ビット整数 |
| 17 | "timestamp" | Timestamp | 内部用タイムスタンプ |
| 18 | "long" | 64-bit Integer | 64ビット整数 |
| 19 | "decimal" | Decimal128 | 128ビット10進数 |
| -1 | "minKey" | MinKey | 最小値 |
| 127 | "maxKey" | MaxKey | 最大値 |
$type 演算子を使用すると、ドキュメント内のフィールドの型を判定できる。
使用例を以下に示す。
db.collection.find({ field: { $type: "string" } })
db.collection.find({ field: { $type: 2 } })
特別なエイリアスとして number がある。
これは、int、long、double、decimal の全ての数値型にマッチする。
db.collection.find({ field: { $type: "number" } })
数値型
整数型
BSONは、32ビット整数と64ビット整数の2種類の整数型をサポートしている。
Int32 (32ビット整数)
32ビット符号付き整数型である。
- Type Number
- 16
- Alias
- "int"
- 範囲
- -2,147,483,648 〜 2,147,483,647 (-231 〜 231-1)
- ストレージサイズ
- 4バイト
MongoDB Shellでの使用例を以下に示す。
db.collection.insertOne({
count: NumberInt(100)
})
Int64 (64ビット整数)
64ビット符号付き整数型である。
- Type Number
- 18
- Alias
- "long"
- 範囲
- -9,223,372,036,854,775,808 〜 9,223,372,036,854,775,807 (-263 〜 263-1)
- ストレージサイズ
- 8バイト
MongoDB Shellでの使用例を以下に示す。
db.collection.insertOne({
largeNumber: NumberLong("9223372036854775807")
})
※注意
JavaScriptのNumber型は、精度の問題があるため、大きな整数値を扱う場合は NumberLong 関数を使用する必要がある。
浮動小数点型
Double (倍精度浮動小数点)
IEEE 754規格に準拠した64ビット倍精度浮動小数点数である。
- Type Number
- 1
- Alias
- "double"
- 範囲
- 約±1.7E+308 (15〜17桁の精度)
- ストレージサイズ
- 8バイト
MongoDBでは、数値リテラルはデフォルトでDouble型として解釈される。
db.collection.insertOne({
price: 19.99
})
Decimal128 (128ビット10進数)
IEEE 754-2008規格に準拠した128ビット10進浮動小数点数である。
金融計算など、高精度な10進演算が必要な場合に使用する。
- Type Number
- 19
- Alias
- "decimal"
- 精度
- 34桁の10進数
- 指数範囲
- -6143 〜 +6144
- ストレージサイズ
- 16バイト
MongoDB 3.4以降で利用可能である。
金額計算においては、浮動小数点数の丸め誤差を避けるため、Decimal128型の使用が強く推奨される。
使用例を以下に示す。
db.collection.insertOne({
totalAmount: NumberDecimal("12345.67")
})
Decimal128とDoubleの比較例を以下に示す。
db.test.insertOne({ doubleValue: 0.1 + 0.2 })
db.test.insertOne({ decimalValue: NumberDecimal("0.1").add(NumberDecimal("0.2")) })
db.test.find()
Double型では、0.30000000000000004 のような丸め誤差が発生する可能性があるが、Decimal128型では正確に 0.3 となる。
数値型の使い分け
各数値型の適切な使用場面を下表に示す。
| データ型 | 適切な使用場面 | 不適切な使用場面 |
|---|---|---|
| Int32 | カウンタ、小さな整数値 (-21億 〜 +21億の範囲内) |
大きな整数値 タイムスタンプ (ミリ秒) |
| Int64 | タイムスタンプ (ミリ秒) 大きな整数値 IDやキー |
金融計算 小数を含む値 |
| Double | 科学技術計算 統計値 座標値 |
金融計算 正確な10進演算が必要な場合 |
| Decimal128 | 金融計算 通貨金額 正確な10進演算 |
整数値のみの場合 高速処理が必要な場合 |
文字列型
String型
UTF-8エンコーディングの文字列を格納する型である。
- Type Number
- 2
- Alias
- "string"
- エンコーディング
- UTF-8
- 最大サイズ
- 16MB (ドキュメント全体の最大サイズ制限内)
MongoDBの文字列は、全てUTF-8としてエンコードされるため、国際文字セット (日本語、中国語、アラビア語等) を直接サポートしている。
使用例を以下に示す。
db.collection.insertOne({
name: "山田太郎",
description: "これはUTF-8でエンコードされた日本語の文字列です"
})
文字列の検索例を以下に示す。
# 通常の検索
db.collection.find({ name: "山田太郎" })
# 正規表現を使用した検索
db.collection.find({ description: { $regex: "UTF-8" } })
バイナリ型
Binary Data (binData)
任意のバイナリデータを格納する型である。
画像、ファイル、暗号化されたデータ等の格納に使用される。
- Type Number
- 5
- Alias
- "binData"
- 最大サイズ
- 16MB (ドキュメント全体の最大サイズ制限内)
Binary Data型には、用途を示すサブタイプが定義されている。
下表に、サブタイプの一覧を示す。
| サブタイプ (16進数) | 説明 | 使用状況 |
|---|---|---|
| 0x00 | Generic binary subtype | 汎用バイナリデータ 推奨 |
| 0x01 | Function | 関数データ 非推奨 |
| 0x02 | Binary (Old) | 旧形式のバイナリデータ 0x00の使用を推奨 |
| 0x03 | UUID (Old) | 旧形式のUUID 0x04の使用を推奨 |
| 0x04 | UUID | 新形式のUUID 推奨 |
| 0x05 | MD5 | MD5ハッシュ値 |
| 0x06 | Encrypted BSON value | 暗号化されたBSON値 MongoDB 4.2以降 |
| 0x80 | User defined | ユーザー定義サブタイプ (0x80以降) |
使用例を以下に示す。
db.collection.insertOne({
file: BinData(0, "aGVsbG8gd29ybGQ="),
uuid: UUID("12345678-1234-5678-1234-567812345678")
})
UUIDの生成と挿入の例を以下に示す。
var uuid = UUID()
db.collection.insertOne({
userId: uuid,
username: "user001"
})
日付・時間型
Date型
日付と時刻を表現する型である。
Unixエポック (1970年1月1日 00:00:00 UTC) からのミリ秒数を、64ビット符号付き整数として格納する。
- Type Number
- 9
- Alias
- "date"
- 内部表現
- 64ビット符号付き整数 (ミリ秒)
- 範囲
- 約2.9億年前 〜 約2.9億年後
- 精度
- ミリ秒
- タイムゾーン
- 保存されない (UTC基準)
使用例を以下に示す。
db.collection.insertOne({
createdAt: new Date(),
eventDate: ISODate("2024-12-25T09:00:00Z")
})
特定の日付を指定する例を以下に示す。
db.collection.insertOne({
birthday: ISODate("1990-05-15T00:00:00Z")
})
日付の範囲検索の例を以下に示す。
db.collection.find({
createdAt: {
$gte: ISODate("2024-01-01T00:00:00Z"),
$lt: ISODate("2025-01-01T00:00:00Z")
}
})
※注意
Dateオブジェクトは、タイムゾーン情報を保存しない。全ての日付はUTC基準で保存される。
アプリケーション側でタイムゾーン変換を行う必要がある。
Timestamp型
MongoDB内部で使用される特殊なタイムスタンプ型である。
主に、レプリケーション処理 や oplog で使用され、通常のアプリケーションでの使用は推奨されない。
- Type Number
- 17
- Alias
- "timestamp"
- 内部表現
- 64ビット値
- 用途
- MongoDB内部処理、レプリケーション、oplog
64ビット値の構成を以下に示す。
- 上位32ビット
- time_t値 (Unixエポックからの秒数)
- 下位32ビット
- 増分カウンタ (ordinal)
この構成により、同じ秒内に発生した複数の操作を区別できる。
使用例を以下に示す (通常は自動的に設定される)。
db.collection.insertOne({
ts: Timestamp(1640995200, 1)
})
※重要
通常のアプリケーションでは、Date型を使用すること。
Timestamp型は、MongoDB内部処理用である。
識別子型
ObjectId型
MongoDBのドキュメントを一意に識別するための12バイトの識別子である。
_id フィールドのデフォルト型として使用される。
- Type Number
- 7
- Alias
- "objectId"
- サイズ
- 12バイト (96ビット)
- 一意性
- グローバルに一意 (高確率)
ObjectIdの構成
12バイトのObjectIdは、以下に示すように構成される。
| バイト位置 | サイズ | 内容 | 説明 |
|---|---|---|---|
| 0〜3 | 4バイト | タイムスタンプ | Unixエポックからの秒数 |
| 4〜8 | 5バイト | ランダム値 | プロセスごとに1回生成される。 <マシン識別子> + <プロセスID> |
| 9〜11 | 3バイト | カウンター | ランダム値で初期化され、その後インクリメントされる |
この構成により、以下に示す特性が保証される。
- タイムスタンプ部分により、時系列での並び順が保たれる。
- ランダム値により、異なるマシン・プロセス間での衝突が回避される。
- カウンター部分により、同じ秒内に生成されたObjectIdの一意性が保たれる。
自動生成と手動設定
ObjectIdは、ドキュメント挿入時に自動的に生成される。
db.collection.insertOne({
name: "Alice"
})
手動でObjectIdを指定することも可能である。
db.collection.insertOne({
_id: ObjectId("507f1f77bcf86cd799439011"),
name: "Bob"
})
新しいObjectIdを生成する例を以下に示す。
var newId = ObjectId()
db.collection.insertOne({
_id: newId,
name: "Charlie"
})
ObjectIdからタイムスタンプを抽出
ObjectIdには、作成時刻の情報が含まれているため、タイムスタンプを抽出できる。
var id = ObjectId("507f1f77bcf86cd799439011")
var timestamp = id.getTimestamp()
print(timestamp)
この機能を利用して、ドキュメントの作成日時でソートすることができる。
db.collection.find().sort({ _id: 1 })
論理型
Boolean型
論理値 (真偽値) を表現する型である。
- Type Number
- 8
- Alias
- "bool"
- 値
trueまたはfalse
- ストレージサイズ
- 1バイト
使用例を以下に示す。
db.collection.insertOne({
isActive: true,
isDeleted: false
})
Boolean型を使用した検索例を以下に示す。
db.collection.find({ isActive: true })
# 論理演算子を使用した検索 (Not Equal)
db.collection.find({ isActive: { $ne: true } })
Null型
Null型
値が存在しないこと または 未定義であることを表現する型である。
- Type Number
- 10
- Alias
- "null"
- 値
null
使用例を以下に示す。
db.collection.insertOne({
name: "Alice",
middleName: null
})
Null値の検索例を以下に示す。
db.collection.find({ middleName: null })
※重要な違い
nullと、フィールドが存在しない状態は異なる。
フィールドが存在しない場合を検索する例を以下に示す。
db.collection.find({ middleName: { $exists: false } })
null または 存在しないフィールドを検索する例を以下に示す。
db.collection.find({
$or: [
{ middleName: null },
{ middleName: { $exists: false } }
]
})
配列・オブジェクト型
配列型
複数の値を順序付きで格納する型である。
- Type Number
- 4
- Alias
- "array"
- 要素
- 異なる型の値を含むことができる
- ネスト
- 配列の中に配列を含むことができる
使用例を以下に示す。
db.collection.insertOne({
tags: ["mongodb", "database", "nosql"],
scores: [85, 90, 78],
mixed: [1, "text", true, null]
})
配列要素の検索例を以下に示す。
db.collection.find({ tags: "mongodb" })
db.collection.find({ tags: { $all: ["mongodb", "database"] } })
db.collection.find({ scores: { $gt: 80 } })
ネストした配列の例を以下に示す。
db.collection.insertOne({
matrix: [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
})
オブジェクト型 (埋め込みドキュメント)
ドキュメント内に別のドキュメントを埋め込む型である。
- Type Number
- 3
- Alias
- "object"
- 構造
- キーと値のペア
- ネスト
- オブジェクトの中にオブジェクトを含むことができる
使用例を以下に示す。
db.collection.insertOne({
name: "Alice",
address: {
street: "123 Main St",
city: "Tokyo",
zipCode: "100-0001"
}
})
埋め込みドキュメントのフィールドにアクセスする例を以下に示す。
db.collection.find({ "address.city": "Tokyo" })
複数レベルのネストの例を以下に示す。
db.collection.insertOne({
user: {
profile: {
name: "Bob",
age: 30,
contact: {
email: "bob@example.com",
phone: "090-1234-5678"
}
}
}
})
db.collection.find({ "user.profile.contact.email": "bob@example.com" })
特殊型
Regular Expression (正規表現型)
正規表現パターンを格納する型である。
- Type Number
- 11
- Alias
- "regex"
- 用途
- テキスト検索、パターンマッチング
使用例を以下に示す。
db.collection.insertOne({
pattern: /^[A-Z]/i
})
db.collection.find({ name: { $regex: /^john/i } })
JavaScript型
JavaScriptコードを格納する型である。
- Type Number
- 13
- Alias
- "javascript"
- 用途
- ストアドファンクション、サーバサイドスクリプト
使用例を以下に示す。
db.collection.insertOne({
code: Code("function() { return 42; }")
})
JavaScript with Scope型 (非推奨)
スコープ (変数環境) 付きのJavaScriptコードを格納する型である。
MongoDB 4.4以降では非推奨となっている。
- Type Number
- 15
- Alias
- "javascriptWithScope"
- 状態
- 非推奨 (MongoDB 4.4以降)
廃止された型
以下に示す型は、廃止されている。
Symbol型
- Type Number
- 14
- Alias
- "symbol"
- 状態
- 廃止
DBPointer型
- Type Number
- 12
- Alias
- "dbPointer"
- 状態: 廃止
Undefined型
- Type Number
- 6
- Alias
- "undefined"
- 状態
- 廃止
比較用特殊型
MinKey型
全ての値より小さい値を表現する特殊な型である。
- Type Number
- -1
- Alias
- "minKey"
- 用途
- インデックス境界、シャーディング、比較演算
MinKeyは、BSON比較順序において最小の値として扱われる。
主に、シャーディング や インデックスの範囲指定 で使用される。
使用例を以下に示す。
db.collection.insertOne({
key: MinKey()
})
MaxKey型
全ての値より大きい値を表現する特殊な型である。
- Type Number
- 127
- Alias
- "maxKey"
- 用途
- インデックス境界、シャーディング、比較演算
MaxKeyは、BSON比較順序において最大の値として扱われる。
主に、シャーディング や インデックスの範囲指定 で使用される。
使用例を以下に示す。
db.collection.insertOne({
key: MaxKey()
})
使用場面
MinKeyとMaxKeyは、以下に示す場面で使用される。
- シャーディング
- シャードキーの範囲を定義する際に、無限小・無限大を表現するために使用される。
- インデックス境界
- インデックススキャンの範囲を指定する際に使用される。
- 比較演算
- 特殊な比較が必要な場合に使用される。
型の判定と変換
$type演算子
$type 演算子を使用すると、クエリ時にフィールドの型を判定できる。
- Type Numberを使用した例
db.collection.find({ age: { $type: 16 } })
- Aliasを使用した例
db.collection.find({ name: { $type: "string" } })
- 複数の型を指定する例
db.collection.find({ value: { $type: ["int", "long", "double"] } })
- 特別なエイリアス
numberの使用例- このクエリは、
int、long、double、decimalの全ての数値型にマッチする。 db.collection.find({ value: { $type: "number" } })
- このクエリは、
型変換
$convert 演算子を使用すると、値の型を変換できる。
基本的な構文を以下に示す。
{
$convert: {
input: <expression>,
to: <type>,
onError: <expression>,
onNull: <expression>
}
}
文字列を整数に変換する例を以下に示す。
db.collection.aggregate([
{
$project: {
convertedValue: {
$convert: {
input: "$stringValue",
to: "int",
onError: 0,
onNull: 0
}
}
}
}
])
下表に、主な変換パターンを示す。
| 変換元 | 変換先 | 例 |
|---|---|---|
| String | Int32/Int64 | "123" → 123 |
| String | Double | "123.45" → 123.45 |
| String | Decimal128 | "123.45" → NumberDecimal("123.45") |
| Int32/Int64 | String | 123 → "123" |
| Double | String | 123.45 → "123.45" |
| Date | String | ISODate("2024-01-01") → "2024-01-01T00:00:00.000Z" |
| String | Date | "2024-01-01" → ISODate("2024-01-01T00:00:00.000Z") |
| ObjectId | String | ObjectId(...) → "507f1f77bcf86cd799439011" |
より簡潔な型変換演算子も利用可能である。
$toString- 文字列に変換
$toInt- 32ビット整数に変換
$toLong- 64ビット整数に変換
$toDouble- Doubleに変換
$toDecimal- Decimal128に変換
$toDate- Dateに変換
$toObjectId- ObjectIdに変換
使用例を以下に示す。
db.collection.aggregate([
{
$project: {
stringValue: { $toString: "$numericValue" },
intValue: { $toInt: "$stringValue" }
}
}
])
RDBMSとの型対応
MongoDBのBSONデータ型と、MySQL / PostgreSQLのデータ型の対応を下表に示す。
| BSON型 | Oracle Database 23ai | SQL Server | MySQL | PostgreSQL | 備考 |
|---|---|---|---|---|---|
| Int32 | NUMBER(10) | INT | INT | INTEGER | 32ビット整数 |
| Int64 | NUMBER(19) | BIGINT | BIGINT | BIGINT | 64ビット整数 |
| Double | BINARY_DOUBLE | FLOAT | DOUBLE | DOUBLE PRECISION | 倍精度浮動小数点 |
| Decimal128 | NUMBER(34, x) (最大38桁) |
DECIMAL(34, x) (最大38桁) |
DECIMAL(34, x) (最大65桁) |
NUMERIC(34, x) (最大131072桁) |
高精度10進数 |
| String | VARCHAR2 CLOB |
VARCHAR NVARCHAR |
VARCHAR TEXT |
VARCHAR TEXT |
文字列 |
| Boolean | BOOLEAN (23ai以降) NUMBER(1) |
BIT | BOOLEAN TINYINT(1) |
BOOLEAN | 論理型 |
| Date | TIMESTAMP | DATETIME2 | DATETIME TIMESTAMP |
TIMESTAMP | 日付時刻 |
| Binary Data | BLOB RAW |
VARBINARY IMAGE |
BLOB VARBINARY |
BYTEA | バイナリデータ |
| ObjectId | CHAR(24) RAW(12) |
CHAR(24) BINARY(12) |
CHAR(24) BINARY(12) |
CHAR(24) BYTEA |
一意識別子 |
| Array | JSON | JSON (SQL Server 2016以降) |
JSON | ARRAY JSON |
配列 |
| Object | JSON | JSON (SQL Server 2016以降) |
JSON | JSON JSONB |
オブジェクト |
| Null | NULL | NULL | NULL | NULL | Null値 |
※注意
MongoDBのArrayとObjectは、ネイティブなデータ型である。
RDBMSでは、JSON型または専用のArray型を使用する必要がある。
MySQL 5.7以降、PostgreSQL 9.4以降でJSON型がサポートされている。
関連情報
- MongoDB公式ドキュメント - BSONデータ型
- MongoDB公式ドキュメント - $type演算子
- MongoDB公式ドキュメント - $convert演算子
- MongoDB公式ドキュメント - ObjectId
- BSON仕様書 (公式)