MongoDB $type 操作符完全解析
(MongoDB 8.0+,2025 年最新实践)
核心结论:
$type= 查询或匹配特定 BSON 数据类型的字段**,防止类型混淆,保障数据一致性。
支持 *数字代码* 和 字符串别名 两种写法。
一、$type 基本语法
{ field: { $type: <BSON type number 或 string> } }
二、BSON 类型对照表(重点记忆!)
| 类型 | 数字代码 | 字符串别名 | 示例 |
|---|---|---|---|
| Double | 1 | "double" | 3.14 |
| String | 2 | "string" | "hello" |
| Object | 3 | "object" | { name: "张三" } |
| Array | 4 | "array" | ["a", "b"] |
| Binary data | 5 | "binData" | BinData(0, "...") |
| ObjectId | 7 | "objectId" | ObjectId("...") |
| Boolean | 8 | "bool" | true |
| Date | 9 | "date" | ISODate("2025-01-01") |
| Null | 10 | "null" | null |
| Regex | 11 | "regex" | /^a/i |
| Int32 | 16 | "int" | 42 |
| Timestamp | 17 | "timestamp" | Timestamp(1, 1) |
| Int64 | 18 | "long" | 9007199254740992 |
| Decimal128 | 19 | "decimal" | Decimal128("3.14") |
| Min key | -1 | "minKey" | MinKey |
| Max key | 127 | "maxKey" | MaxKey |
三、基本使用示例
use testdb
// 插入混杂类型数据
db.types.insertMany([
{ name: "A", age: 25 }, // age: double (1)
{ name: "B", age: "30" }, // age: string (2)
{ name: "C", age: null }, // age: null (10)
{ name: "D", age: 35 }, // age: int (16)
{ name: "E", age: true }, // age: bool (8)
{ name: "F", age: [20, 30] }, // age: array (4)
{ name: "G", age: new Date() } // age: date (9)
])
查询 age 是 数字 的文档(推荐)
// 方法 1:匹配 double 或 int(最常用)
db.types.find({ age: { $type: ["double", "int"] } })
// 或
db.types.find({ age: { $type: [1, 16] } })
// 方法 2:使用 $in
db.types.find({ age: { $in: [{ $type: 1 }, { $type: 16 }] } })
查询 age 是 字符串 的文档
db.types.find({ age: { $type: "string" } })
// 或
db.types.find({ age: { $type: 2 } })
查询 age 是 null 的文档
db.types.find({ age: { $type: "null" } })
// 或
db.types.find({ age: null }) // 注意:这也匹配 { age: { $exists: false } }
警告:
{ age: null }会匹配:
age: nullage字段不存在
推荐用$type: "null"+$exists: true精确匹配
db.types.find({ age: { $type: "null", $exists: true } })
四、高级用法
1. 查询数组中包含特定类型的元素
// scores 数组中包含 double 类型
db.students.find({
scores: { $elemMatch: { $type: "double" } }
})
2. 查询嵌套字段类型
// address.zip 是 string
db.users.find({
"address.zip": { $type: "string" }
})
3. 查询 ObjectId 类型
// _id 是 ObjectId(默认就是)
db.users.find({
_id: { $type: "objectId" }
})
4. 查询 Decimal128(高精度金额)
db.transactions.find({
amount: { $type: "decimal" }
})
五、$type 在更新中的应用
// 只更新 age 是数字的文档
db.types.updateMany(
{ age: { $type: ["double", "int"] } },
{ $inc: { age: 1 } }
)
// 将 age 是字符串的转为数字(需 $convert 或聚合)
db.types.updateMany(
{ age: { $type: "string" } },
[
{ $set: { age: { $toInt: "$age" } } }
]
)
六、常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
age: null 匹配了不存在的字段 | null 匹配 missing | 用 { age: { $type: "null", $exists: true } } |
想查“数字”但漏了 int | 只查了 double | 用 [1, 16] 或 ["double", "int"] |
$type: 2 没匹配到 | 字段是 number 但实际是 int | 明确类型 |
| 查询慢 | 无索引 | 为频繁查询字段建索引 |
七、性能建议:建索引
// 为 age 字段建索引(支持 $type 查询)
db.types.createIndex({ age: 1 })
// 复合索引
db.users.createIndex({ status: 1, createdAt: 1 })
注意:
$type查询在有索引时仍需扫描,但可配合其他字段加速。
八、GUI 工具使用 $type
| 工具 | 操作 |
|---|---|
| MongoDB Compass | Filter → { age: { $type: "string" } } |
| MongoDB Atlas | Aggregations → $match: { age: { $type: 1 } } |
| VS Code | 直接输入 JSON 过滤 |
九、完整实战脚本
// type_demo.js
use demo
// 插入测试数据
db.mixed.insertMany([
{ item: "A", qty: 10 }, // double
{ item: "B", qty: "20" }, // string
{ item: "C", qty: null }, // null
{ item: "D", qty: 30 }, // int
{ item: "E", qty: [1, 2, 3] }, // array
{ item: "F", qty: true }, // bool
{ item: "G", qty: new Date() } // date
])
print("=== $type 查询示例 ===\n")
// 1. qty 是数字(double 或 int)
print("1. 数字类型 (double/int):")
db.mixed.find({ qty: { $type: ["double", "int"] } })
.projection({ item: 1, qty: 1, _id: 0 })
.forEach(printjson)
// 2. qty 是字符串
print("\n2. 字符串类型:")
db.mixed.find({ qty: { $type: "string" } })
.projection({ item: 1, qty: 1, _id: 0 })
.forEach(printjson)
// 3. qty 是 null 且字段存在
print("\n3. null 类型(字段存在):")
db.mixed.find({ qty: { $type: "null", $exists: true } })
.projection({ item: 1, qty: 1, _id: 0 })
.forEach(printjson)
// 4. 统计各种类型数量
print("\n4. 类型统计:")
db.mixed.aggregate([
{ $group: {
_id: { $type: "$qty" },
count: { $sum: 1 }
}},
{ $sort: { count: -1 } }
]).forEach(d => print(`${d._id}: ${d.count} 条`))
运行:
mongosh type_demo.js
十、一句话总结
**“
$type= 精确匹配字段 **BSON 类型,防止25和'25'混淆,保障数据一致性”
快速 $type 模板
// 数字(推荐)
{ field: { $type: ["double", "int"] } }
// 字符串
{ field: { $type: "string" } }
// null(字段存在)
{ field: { $type: "null", $exists: true } }
// 数组
{ field: { $type: "array" } }
// ObjectId
{ _id: { $type: "objectId" } }
官方文档:
https://www.mongodb.com/docs/manual/reference/operator/query/type/
如需 批量转换类型、Schema 验证 + $type、从 SQL 类型映射 或 实时监控类型异常,欢迎继续提问!