处理MongoDB中的可选/空数据

Oxy*_*ore 11 optimization query-optimization mongodb nosql

我记得在某个地方读过mongo引擎在文档的整个结构已经到位的情况下更加舒适,所以这是一个问题.

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

{
    _id: ObjectId("5192b6072fda974610000005"),
    description: ""
}
Run Code Online (Sandbox Code Playgroud)

要么

{
    _id: ObjectId("5192b6072fda974610000005"),
    description: null
}
Run Code Online (Sandbox Code Playgroud)

要么

{
    _id: ObjectId("5192b6072fda974610000005")
}
Run Code Online (Sandbox Code Playgroud)

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

vin*_*ker 27

介绍

如果文档没有值,则DB会将其值视为null.假设数据库包含以下文档:

{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }
Run Code Online (Sandbox Code Playgroud)

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

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

该数据库不无不同文件递减场和文档具有递减与值字段为空.还有一个测试:

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

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

处理"空"数据时,例如插入空字符串时,我应该将其默认为null,""或者根本不插入它?

没有从太大的区别{desc: null}{},因为大多数的运营商都会有同样的结果.你应该特别注意这两个操作符:

我会在没有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
}
Run Code Online (Sandbox Code Playgroud)

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

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

到目前为止,这么好,但为什么我要解释这一切?因为稀疏索引存在一个模糊的行为.在以下查询中,我们希望按desc排序所有文档.

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

结果似乎很奇怪.丢失的文件怎么了?让我们尝试查询而不对其进行排序:

{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }
Run Code Online (Sandbox Code Playgroud)

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

db.test.find().sort({desc: 1}).explain().cursor
// Output:
"BtreeCursor desc_1"
Run Code Online (Sandbox Code Playgroud)

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

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" : "" }
Run Code Online (Sandbox Code Playgroud)

摘要

  • 如果包含,则稀疏唯一索引不起作用 {desc: null}
  • 如果包含,则稀疏唯一索引不起作用 {desc: ""}
  • 稀疏索引可能会更改查询的结果


Aki*_*RAI 6

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

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

这里已经有类似的问题了.