MongoDB数据类型 #
一、BSON简介 #
1.1 什么是BSON #
BSON(Binary JSON)是一种二进制编码的文档格式,MongoDB使用BSON存储文档。
text
JSON vs BSON
JSON:
{
"name": "John",
"age": 25
}
BSON (二进制表示):
\x16\x00\x00\x00\x02name\x00\x05\x00\x00\x00John\x00
\x10age\x00\x19\x00\x00\x00\x00
1.2 BSON特点 #
| 特点 | 说明 |
|---|---|
| 二进制 | 高效存储和传输 |
| 类型丰富 | 支持更多数据类型 |
| 有序 | 保持字段顺序 |
| 长度前缀 | 快速遍历 |
1.3 BSON类型列表 #
| 类型 | 编号 | 别名 |
|---|---|---|
| Double | 1 | “double” |
| String | 2 | “string” |
| Object | 3 | “object” |
| Array | 4 | “array” |
| Binary | 5 | “binData” |
| ObjectId | 7 | “objectId” |
| Boolean | 8 | “bool” |
| Date | 9 | “date” |
| Null | 10 | “null” |
| Regular Expression | 11 | “regex” |
| 32-bit Integer | 16 | “int” |
| Timestamp | 17 | “timestamp” |
| 64-bit Integer | 18 | “long” |
| Decimal128 | 19 | “decimal” |
| Min Key | -1 | “minKey” |
| Max Key | 127 | “maxKey” |
二、基本数据类型 #
2.1 字符串(String) #
javascript
// UTF-8编码字符串
db.users.insertOne({
name: "张三",
email: "zhangsan@example.com",
description: "这是一个很长的描述文本..."
})
// 查询字符串
db.users.find({ name: "张三" })
// 字符串长度限制
// 单个文档最大16MB
2.2 数值类型 #
32位整数(Int)
javascript
// Shell中默认将整数存储为Double
// 使用NumberInt明确指定32位整数
db.products.insertOne({
name: "Product A",
quantity: NumberInt(100),
minStock: NumberInt(10)
})
64位整数(Long)
javascript
// 使用NumberLong存储大整数
db.transactions.insertOne({
transactionId: NumberLong("9007199254740993"),
amount: NumberLong("1000000000000")
})
// 查询时需要使用NumberLong
db.transactions.find({
transactionId: NumberLong("9007199254740993")
})
浮点数(Double)
javascript
// 默认数值类型
db.products.insertOne({
name: "Product A",
price: 99.99,
discount: 0.15
})
// 科学计数法
db.scientific.insertOne({
value: 1.23e10
})
高精度小数(Decimal128)
javascript
// 金融场景使用Decimal128
db.accounts.insertOne({
accountId: "ACC001",
balance: NumberDecimal("123456789.1234567890123456789"),
interest: NumberDecimal("0.000123456789012345")
})
// 精确计算
db.accounts.aggregate([
{
$project: {
accountId: 1,
balance: 1,
interestAmount: {
$multiply: ["$balance", "$interest"]
}
}
}
])
2.3 布尔值(Boolean) #
javascript
db.users.insertOne({
name: "John",
isActive: true,
isVerified: false,
hasSubscription: true
})
// 查询布尔值
db.users.find({ isActive: true })
db.users.find({ isVerified: false })
2.4 日期(Date) #
javascript
// 当前日期
db.events.insertOne({
name: "Event A",
createdAt: new Date(),
updatedAt: ISODate()
})
// 指定日期
db.events.insertOne({
name: "Event B",
eventDate: ISODate("2024-12-31T00:00:00Z"),
deadline: new Date("2024-06-30")
})
// 日期操作
db.events.aggregate([
{
$project: {
name: 1,
year: { $year: "$eventDate" },
month: { $month: "$eventDate" },
day: { $dayOfMonth: "$eventDate" },
hour: { $hour: "$eventDate" }
}
}
])
// 日期比较
db.events.find({
eventDate: {
$gte: ISODate("2024-01-01"),
$lt: ISODate("2025-01-01")
}
})
2.5 Null #
javascript
// Null值
db.users.insertOne({
name: "John",
middleName: null,
nickname: null
})
// 查询Null值
db.users.find({ middleName: null }) // 匹配null和不存在
// 只匹配null值
db.users.find({ middleName: { $type: 10 } })
// 匹配字段不存在
db.users.find({ middleName: { $exists: false } })
三、特殊数据类型 #
3.1 ObjectId #
javascript
// 自动生成的_id
db.users.insertOne({
name: "John"
})
// _id: ObjectId("65f1a2b3c4d5e6f7g8h9i0j1")
// 手动指定_id
db.users.insertOne({
_id: ObjectId(),
name: "Jane"
})
// ObjectId结构
// 65f1a2b3c4d5e6f7g8h9i0j1
// └─────┬─────┘└┬┘└─┬─┘└┬┘
// 时间戳 机器ID 进程ID 计数器
// 提取时间戳
db.users.aggregate([
{
$project: {
name: 1,
createdTime: { $toDate: "$_id" }
}
}
])
3.2 二进制数据(Binary) #
javascript
// 存储二进制数据
db.files.insertOne({
name: "document.pdf",
data: BinData(0, "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC..."),
contentType: "application/pdf",
size: NumberInt(1024)
})
// 二进制子类型
// 0: 通用二进制
// 1: 函数
// 2: 旧二进制
// 3: 旧UUID
// 4: UUID
// 5: MD5
// 6: 加密
// UUID示例
db.sessions.insertOne({
sessionId: UUID("123e4567-e89b-12d3-a456-426614174000"),
userId: ObjectId(),
createdAt: new Date()
})
3.3 正则表达式 #
javascript
// 存储正则表达式
db.patterns.insertOne({
name: "email",
pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
})
// 查询中使用正则
db.users.find({
email: /^[a-zA-Z0-9._%+-]+@example\.com$/
})
// $regex操作符
db.users.find({
name: { $regex: /^John/i }
})
// 复杂正则查询
db.users.find({
name: {
$regex: "john",
$options: "i" // 不区分大小写
}
})
3.4 时间戳(Timestamp) #
javascript
// 内部使用,主要用于复制
db.oplog.insertOne({
ts: Timestamp(1234567890, 1),
op: "i",
ns: "mydb.users",
o: { _id: ObjectId(), name: "John" }
})
// 获取当前时间戳
db.users.insertOne({
name: "John",
createdAt: Timestamp(0, 0) // 自动设置为当前时间
})
3.5 JavaScript代码 #
javascript
// 存储JavaScript代码
db.scripts.insertOne({
name: "calculateDiscount",
code: function(price, discount) {
return price * (1 - discount);
}
})
// 使用$where执行JavaScript
db.users.find({
$where: function() {
return this.age > 20 && this.age < 30;
}
})
// 注意:$where性能较低,谨慎使用
四、复合数据类型 #
4.1 数组(Array) #
javascript
// 简单数组
db.users.insertOne({
name: "John",
tags: ["mongodb", "nosql", "database"],
scores: [85, 90, 78, 92]
})
// 对象数组
db.orders.insertOne({
orderId: "ORD001",
items: [
{ productId: ObjectId(), name: "Product A", quantity: 2, price: 99.99 },
{ productId: ObjectId(), name: "Product B", quantity: 1, price: 149.99 }
],
totalAmount: 349.97
})
// 数组查询
db.users.find({ tags: "mongodb" })
db.users.find({ tags: { $all: ["mongodb", "nosql"] } })
db.users.find({ tags: { $size: 3 } })
// 数组元素查询
db.orders.find({
"items.name": "Product A"
})
db.orders.find({
items: {
$elemMatch: {
quantity: { $gt: 1 },
price: { $lt: 100 }
}
}
})
// 数组更新
db.users.updateOne(
{ name: "John" },
{ $push: { tags: "newTag" } }
)
db.users.updateOne(
{ name: "John" },
{ $pull: { tags: "oldTag" } }
)
4.2 嵌套文档(Embedded Document) #
javascript
// 单层嵌套
db.users.insertOne({
name: "John",
address: {
street: "123 Main St",
city: "Beijing",
country: "China",
zipCode: "100000"
}
})
// 多层嵌套
db.companies.insertOne({
name: "Tech Corp",
headquarters: {
address: {
street: "456 Tech Ave",
city: "Shanghai",
country: "China"
},
coordinates: {
lat: 31.2304,
lng: 121.4737
}
}
})
// 嵌套文档查询
db.users.find({ "address.city": "Beijing" })
db.users.find({ "address.zipCode": "100000" })
// 嵌套文档更新
db.users.updateOne(
{ name: "John" },
{ $set: { "address.city": "Shanghai" } }
)
4.3 文档结构设计 #
嵌入式文档
javascript
// 一对一关系
db.users.insertOne({
name: "John",
profile: {
avatar: "avatar.jpg",
bio: "Software Developer",
website: "https://example.com"
}
})
// 一对少关系
db.posts.insertOne({
title: "My First Post",
content: "...",
comments: [
{ user: "Jane", text: "Great post!", createdAt: new Date() },
{ user: "Bob", text: "Thanks for sharing", createdAt: new Date() }
]
})
引用式文档
javascript
// 一对多关系
db.users.insertOne({
_id: ObjectId(),
name: "John"
})
db.orders.insertOne({
_id: ObjectId(),
userId: ObjectId(), // 引用用户
items: [...],
totalAmount: 199.99
})
// 使用$lookup关联
db.orders.aggregate([
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user"
}
}
])
五、类型检查与转换 #
5.1 类型检查 #
javascript
// $type操作符
db.users.find({ age: { $type: "number" } })
db.users.find({ name: { $type: "string" } })
db.users.find({ createdAt: { $type: "date" } })
// 检查多种类型
db.users.find({
field: { $type: ["string", "null"] }
})
// 使用类型编号
db.users.find({ age: { $type: 16 } }) // 32位整数
db.users.find({ age: { $type: 1 } }) // Double
5.2 类型转换 #
javascript
// $convert操作符
db.users.aggregate([
{
$project: {
name: 1,
ageString: {
$convert: {
input: "$age",
to: "string",
onError: "Error",
onNull: "Null"
}
}
}
}
])
// 便捷转换操作符
db.users.aggregate([
{
$project: {
name: 1,
ageString: { $toString: "$age" },
ageInt: { $toInt: "$ageString" },
ageDouble: { $toDouble: "$age" },
createdDate: { $toDate: "$createdAt" }
}
}
])
5.3 类型判断函数 #
javascript
// 判断类型
typeof "hello" // "string"
typeof 123 // "number"
typeof true // "boolean"
typeof {} // "object"
typeof [] // "object"
typeof null // "object"
// 判断数组
Array.isArray([1, 2, 3]) // true
// 判断ObjectId
ObjectId.isValid("507f1f77bcf86cd799439011") // true
六、数据类型选择 #
6.1 数值类型选择 #
| 场景 | 推荐类型 | 说明 |
|---|---|---|
| 计数器 | NumberInt | 整数计数 |
| 大整数 | NumberLong | 超过16位整数 |
| 价格 | NumberDecimal | 精确计算 |
| 科学计算 | Double | 浮点运算 |
| 百分比 | NumberDecimal | 精确百分比 |
6.2 日期类型选择 #
| 场景 | 推荐类型 | 说明 |
|---|---|---|
| 创建时间 | Date | 用户可见时间 |
| 更新时间 | Date | 用户可见时间 |
| 复制操作时间 | Timestamp | 内部使用 |
| 时序数据 | Date | 时序集合 |
6.3 文档结构选择 #
| 场景 | 推荐结构 | 说明 |
|---|---|---|
| 一对一 | 嵌入式 | 简单直接 |
| 一对少 | 嵌入式 | 减少查询 |
| 一对多 | 引用式 | 避免文档过大 |
| 多对多 | 引用式 | 灵活关联 |
七、数据类型限制 #
7.1 文档大小限制 #
javascript
// 单个文档最大16MB
// 超过限制需要使用GridFS
// 检查文档大小
Object.bsonsize(db.users.findOne())
// 大文件存储
// 使用GridFS
db.fs.files.insertOne({
filename: "large_file.pdf",
length: NumberLong(104857600), // 100MB
chunkSize: 261120,
uploadDate: new Date()
})
7.2 嵌套深度限制 #
javascript
// MongoDB支持最多100层嵌套
// 但实际使用中建议不超过3-4层
// 推荐
{
user: {
profile: {
address: {
city: "Beijing"
}
}
}
}
// 不推荐(嵌套过深)
{
level1: {
level2: {
level3: {
level4: {
level5: {
// ...
}
}
}
}
}
}
7.3 字段名限制 #
javascript
// 字段名不能包含.和$
// _id是保留字段
// 错误示例
{
"user.name": "John", // 包含点号
"$price": 99.99 // 包含$
}
// 正确示例
{
"userName": "John",
"price": 99.99
}
八、最佳实践 #
8.1 数据类型一致性 #
javascript
// 保持字段类型一致
// 推荐
db.users.insertMany([
{ name: "John", age: 25 },
{ name: "Jane", age: 28 }
])
// 不推荐(类型不一致)
db.users.insertMany([
{ name: "John", age: 25 },
{ name: "Jane", age: "28" } // 字符串
])
8.2 使用合适的数据类型 #
javascript
// 金额使用Decimal128
db.products.insertOne({
name: "Product A",
price: NumberDecimal("99.99")
})
// 大整数使用NumberLong
db.counters.insertOne({
name: "page_views",
value: NumberLong("9007199254740993")
})
// 日期使用Date而不是字符串
db.events.insertOne({
name: "Event A",
date: new Date() // 不是 "2024-01-01"
})
8.3 文档设计原则 #
javascript
// 1. 就近原则:相关数据放在一起
db.users.insertOne({
name: "John",
address: {
street: "123 Main St",
city: "Beijing"
}
})
// 2. 避免过深嵌套
// 3. 考虑查询模式
// 4. 考虑更新频率
九、总结 #
数据类型速查表:
| 类型 | 用途 | 示例 |
|---|---|---|
| String | 文本数据 | “Hello” |
| Int | 整数 | NumberInt(100) |
| Long | 大整数 | NumberLong(“…”) |
| Double | 浮点数 | 99.99 |
| Decimal | 高精度 | NumberDecimal(“…”) |
| Boolean | 布尔值 | true/false |
| Date | 日期时间 | new Date() |
| ObjectId | 文档ID | ObjectId() |
| Array | 数组 | [1, 2, 3] |
| Object | 嵌套文档 | |
| Binary | 二进制 | BinData(0, “…”) |
| Null | 空值 | null |
下一步,让我们学习数据库操作!
最后更新:2026-03-27