文档1(字段存在且值为BSON NULL) 和 文档1(字段存在且值为null) 的区别是什么 举例
MongoDB 中 BSON NULL 和 null 的区别
核心区别
在 MongoDB 中,字段存在且值为 BSON NULL 和 字段存在且值为 null 本质上是同一个概念,但不同的查询方法会导致匹配结果不同。
详细解释
1. 存储层面
在 BSON 中,NULL 是一个明确的类型(类型编号 0x0a)。当我们在 MongoDB 中设置字段值为 null 时,实际存储的就是 BSON NULL。
示例文档:
JSON
{"_id": 1, "name": "Alice", "age": null}
在这个文档中,age 字段存在,其值在 BSON 中存储为 NULL 类型。
2. 查询层面的差异
问题在于不同的查询方法匹配不同的结果:
JAVA
// 查询1:使用 isNullValue() 对应 {$type: 10}
db.collection.find({"age": {"$type": 10}})
// 或等效于
Criteria.where("age").isNullValue()
// 查询2:使用 is(null) 对应 {age: null}
db.collection.find({"age": null})
// 或等效于
Criteria.where("age").is(null)
实际对比示例
测试数据:
JSON
[
{"_id": 1, "name": "Alice", "age": null},
{"_id": 2, "name": "Bob"}, // 没有 age 字段
{"_id": 3, "name": "Charlie", "age": 25},
{"_id": 4, "name": "David", "age": 0},
{"_id": 5, "name": "Eve", "age": ""}
]
查询结果对比:
db.collection.find({"age": {"$type": 10}})或isNullValue()- 匹配:文档1(Alice)
- 不匹配:文档2(Bob,没有age字段)
db.collection.find({"age": null})或is(null)- 匹配:文档1(Alice)和文档2(Bob)
- 不匹配:其他文档
MongoDB 查询行为解析
使用 {field: null} 查询时:
MongoDB 的查询引擎会将 {field: null} 解释为:
- 字段存在且值为 BSON NULL
- 或者 字段不存在
这是 MongoDB 的一个特殊设计,旨在让开发者更方便地查询"空值"。
使用 {field: {$type: 10}} 查询时:
这只会匹配字段存在且值为 BSON NULL 的文档。
代码示例演示
JAVA
// 情况1:isNullValue() -> 严格匹配 BSON NULL
Criteria.where("age").isNullValue()
// 翻译为:{"age": {"$type": 10}}
// 结果:只匹配有 age 字段且值为 null 的文档
// 情况2:is(null) -> 匹配 null 或字段不存在
Criteria.where("age").is(null)
// 翻译为:{"age": null}
// 结果:匹配有 age 字段且值为 null 的文档,也匹配没有 age 字段的文档
在您之前需求中的应用
对于"receivingTime字段不存在或为空"的需求:
JAVA
// 正确做法1:使用 is(null) 简洁明了
Criteria.where("receivingTime").is(null)
// 这会匹配:字段不存在 或 字段值为 null
// 正确做法2:使用 or 操作符明确表达
new Criteria().orOperator(
Criteria.where("receivingTime").exists(false), // 字段不存在
Criteria.where("receivingTime").isNullValue() // 字段存在且值为 BSON NULL
)
总结对比
| 查询方法 | MongoDB 查询 | 匹配条件 | 是否包含字段不存在 |
|---|---|---|---|
isNullValue() |
{"field": {"$type": 10}} |
字段存在且值为 BSON NULL | ❌ 不包含 |
is(null) |
{"field": null} |
字段不存在 或 字段值为 null | ✅ 包含 |
简单记忆:
- 如果要严格匹配 BSON NULL 值,用
isNullValue() - 如果要匹配字段不存在或值为 null,用
is(null)
"$type": 10,值一定是null吗?
是的,{"$type": 10} 在 MongoDB 中一定匹配 null 值
BSON 类型编号 10
在 BSON 规范中,每个数据类型都有对应的类型编号:
| 类型名称 | 类型编号 |
|---|---|
| Double | 1 |
| String | 2 |
| Object | 3 |
| Array | 4 |
| Binary data | 5 |
| Undefined | 6 |
| Null | 10 |
| Boolean | 8 |
| ... | ... |
注意:$type: 10 明确表示 BSON Null 类型,不匹配其他任何值。
实际测试示例
假设有以下文档:
JAVASCRIPT
// 插入测试数据
db.test.insertMany([
{_id: 1, value: null}, // BSON Null
{_id: 2, value: undefined}, // BSON Undefined (类型6)
{_id: 3, value: 0}, // 数字0
{_id: 4, value: ""}, // 空字符串
{_id: 5, value: []}, // 空数组
{_id: 6, value: {}}, // 空对象
{_id: 7, value: false}, // 布尔false
{_id: 8}, // 字段不存在
{_id: 9, value: "null"} // 字符串"null"
])
查询测试结果
JAVASCRIPT
// 查询1:$type: 10 (BSON Null)
db.test.find({value: {$type: 10}})
// 结果:只匹配 {_id: 1, value: null}
// 不匹配:undefined、0、""、[]、{}、false、"null"
// 查询2:$type: 6 (BSON Undefined)
db.test.find({value: {$type: 6}})
// 结果:只匹配 {_id: 2, value: undefined}
// 注意:在 MongoDB 的 JavaScript shell 中,undefined 会被转换为 null,
// 但通过驱动直接插入 BSON Undefined 是可能的
// 查询3:普通 null 查询
db.test.find({value: null})
// 结果:匹配 {_id: 1, value: null} 和 {_id: 8}(字段不存在)
在 Spring Data MongoDB 中的对应关系
JAVA
// 使用 isNullValue() -> 对应 $type: 10
Criteria.where("field").isNullValue()
// 生成查询:{"field": {"$type": 10}}
// 只匹配 BSON Null 类型
// 使用 is(null) -> 对应 {field: null}
Criteria.where("field").is(null)
// 生成查询:{"field": null}
// 匹配字段不存在或值为 null
常见混淆点澄清
1. 字符串 "null" 与 BSON Null
JAVA
// 文档:{value: "null"}
db.collection.find({value: {$type: 10}}) // 不匹配
db.collection.find({value: null}) // 不匹配
db.collection.find({value: "null"}) // 匹配,因为这是字符串查询
2. 数字 0 与 BSON Null
JAVA
// 文档:{value: 0}
db.collection.find({value: {$type: 10}}) // 不匹配
db.collection.find({value: 0}) // 匹配
3. Undefined 与 Null
JAVA
// 在 JavaScript 中:
// undefined 是类型6,null 是类型10
// 但在 MongoDB 查询中,{field: null} 会匹配 undefined
// 而 {field: {$type: 10}} 只匹配 null
验证代码示例
JAVA
// 验证不同类型文档
Document doc1 = new Document("_id", 1).append("value", null);
Document doc2 = new Document("_id", 2).append("value", 0);
Document doc3 = new Document("_id", 3).append("value", "");
Document doc4 = new Document("_id", 4); // 无value字段
// 查询1:使用 $type: 10
Bson query1 = Filters.type("value", BsonType.NULL);
// 结果:只匹配 doc1
// 查询2:使用 null
Bson query2 = Filters.eq("value", null);
// 结果:匹配 doc1 和 doc4
总结
关键点:
{"$type": 10}是 BSON 类型查询,严格匹配类型为 Null 的值- 这不匹配:undefined、0、空字符串、空数组、空对象、false
- 这不匹配:字段不存在的情况
- 这不匹配:字符串 "null"(这是字符串类型,编号2)
在您的需求中: 如果您想查询"字段值为 BSON Null 类型"的文档,用 isNullValue() 或 $type: 10。 如果您想查询"字段不存在或值为 null",用 is(null)。