MongoDB中BSON NULL与null查询区别详解

小豆丁 10小时前 ⋅ 8 阅读
聊天记录
头像

文档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": ""}
]

查询结果对比:

  1. db.collection.find({"age": {"$type": 10}})isNullValue()

    • 匹配:文档1(Alice)
    • 不匹配:文档2(Bob,没有age字段)
  2. db.collection.find({"age": null})is(null)

    • 匹配:文档1(Alice)和文档2(Bob)
    • 不匹配:其他文档

MongoDB 查询行为解析

使用 {field: null} 查询时:

MongoDB 的查询引擎会将 {field: null} 解释为:

  1. 字段存在且值为 BSON NULL
  2. 或者 字段不存在

这是 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)

全部评论: 0

    我有话说: