15

我记得在某处读到过,当文档的整个结构已经到位以备更新时,mongo 引擎会更加舒适,所以这是问题所在。

在处理“空”数据时,例如插入空字符串时,我应该将其默认为null""还是根本不插入?

{
    _id: ObjectId("5192b6072fda974610000005"),
    description: ""
}

或者

{
    _id: ObjectId("5192b6072fda974610000005"),
    description: null
}

或者

{
    _id: ObjectId("5192b6072fda974610000005")
}

您必须记住,该description字段可能会或可能不会在每个文档中填写(基于用户输入)。

4

2 回答 2

33

介绍

如果文档没有值,则数据库认为其值为null. 假设一个包含以下文档的数据库:

{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }

如果您创建一个查询来查找字段desc不同于null的文档,您将只得到一个文档:

db.test.find({desc: {$ne: null}})
// Output:
{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }

数据库不会区分没有desc字段的文档和带有desc字段且值为null的文档。再来一项测试:

db.test.find({desc: null})
// Output:
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }

但差异仅在查询中被忽略,因为如上面最后一个示例所示,字段仍保存在磁盘上,您将收到与发送到 MongoDB 的文档具有相同结构的文档。

问题

在处理“空”数据时,例如插入空字符串时,我应该将其默认为 null、“”还是根本不插入?

{desc: null}与to没有太大区别{},因为大多数运算符都会得到相同的结果。您应该只特别注意这两个运算符:

我会保存没有desc字段的文档,因为操作员将继续按预期工作并且我会节省一些空间。

填充因子

如果您知道数据库中的文档经常增长,那么 MongoDB 可能需要在更新期间移动文档,因为之前的文档位置没有足够的空间。为了防止移动文档,MongoDB 为每个文档分配额外的空间。

MongoDB 为每个文档分配的额外空间量由填充因子控制。您不能(也不需要)选择填充因子,因为 MongoDB 会自适应地学习它,但是您可以通过使用值填充可能的未来字段来帮助 MongoDB 为每个文档预分配内部空间。差异非常小(取决于您的应用程序),并且在 MongoDB 学习最佳填充因子后可能会更小。

稀疏索引

本节对您目前的具体问题不太重要,但在您遇到类似问题时可能会对您有所帮助。

如果您在字段desc上创建唯一索引,那么您将无法保存多个具有相同值的文档,并且在之前的数据库中,我们在字段desc上拥有多个具有相同值的文档。让我们尝试在前面介绍的数据库中创建一个唯一索引,看看我们得到了什么错误:

db.test.ensureIndex({desc: 1}, {unique: true})
// Output:
{
    "err" : "E11000 duplicate key error index: test.test.$desc_1  dup key: { : null }",
    "code" : 11000,
    "n" : 0,
    "connectionId" : 3,
    "ok" : 1
}

如果我们希望能够在某个字段上创建唯一索引让某些文档将该字段为空,我们应该创建一个稀疏索引。让我们再次尝试创建唯一索引:

// No errors this time:
db.test.ensureIndex({desc: 1}, {unique: true, sparse: true})

到目前为止,一切都很好,但我为什么要解释这一切呢?因为稀疏索引有一种晦涩的行为。在以下查询中,我们希望所有文档都按desc排序。

db.test.find().sort({desc: 1})
// Output:
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }

结果似乎很奇怪。丢失的文件怎么了?让我们试试不排序的查询:

{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }

这次所有文件都归还了。发生了什么?这很简单,但不是那么明显。当我们按desc对结果进行排序时,我们使用之前创建的稀疏索引,并且没有desc字段的文档没有条目。以下查询向我们展示了使用索引对结果进行排序

db.test.find().sort({desc: 1}).explain().cursor
// Output:
"BtreeCursor desc_1"

我们可以使用提示跳过索引:

db.test.find().sort({desc: 1}).hint({$natural: 1})
// Output:
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }
{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }

概括

  • 如果包含,稀疏唯一索引不起作用{desc: null}
  • 如果包含,稀疏唯一索引不起作用{desc: ""}
  • 稀疏索引可能会改变查询结果
于 2013-05-15T01:34:32.957 回答
7

空值字段没有该字段的文档之间几乎没有区别。主要区别在于前者消耗很少的磁盘空间,而后者则完全不消耗。它们可以通过使用$exists运算符来区分。

带有空字符串的字段与它们完全不同。虽然这取决于目的,但我不建议将其用作null. 准确地说,它们应该用来表示不同的事物。例如,考虑投票。投空白票的人和不被允许投票的人是不同的。前一票是空字符串,后一票是null.

这里已经有一个类似的问题

于 2013-05-15T00:37:47.780 回答