Mongo稀疏索引无法正常工作

时间:2015-11-09 12:20:05

标签: mongodb indexing mongoose

我说'正如我所料',因为我可能会误解它应该如何运作。

我有一个包含这样的对象的模型:

{
    "_id" : ObjectId("56408d76ef82679937000008"),
    "_type" : "ford",
    "year" : 1986,
    "model" : "sierra",
    "model_unique" : 1,
    "__v" : 0
}

我需要一个复合唯一索引,除非指定,否则不允许插入具有相同_typemodel组合的两个对象。

我认为我可以指定的方式是使用model_unique列并使索引稀疏,因此添加前两次文档应该失败,而应该允许以下内容(请注意,没有{{ 1}} field):

model_unique

我认为这适用于这个索引:

{
    "_id" : ObjectId("56408e0d636779c83700000a"),
    "_type" : "veridianDynamics",
    "year" : 1986,
    "model" : "sierra",
    "__v" : 0
}
{
    "_id" : ObjectId("another ID"),
    "_type" : "veridianDynamics",
    "year" : 2003,
    "model" : "sierra",
    "__v" : 0
}

但实际上它失败了:

Schema.index({"_type": 1, "model": 1, "model_unique": 1}, { unique: true, sparse: true });

显然,它正在考虑未定义的字段具有空值。

我正在使用[MongoError: insertDocument :: caused by :: 11000 E11000 duplicate key error index: mongoose-schema-extend.vehicles.$_type_1_model_1_model_unique_1 dup key: { : "veridianDynamics", : "sierra", : null }]

mongod --version db version v2.6.11

2 个答案:

答案 0 :(得分:4)

来自sparse复合索引上的documentation

  

仅包含升序/降序索引的稀疏复合索引   只要文档至少包含,键就会索引文档   其中一把钥匙。

在您的情况下,这意味着只有当文档中缺少复合索引的所有三个组件时,文档才会从索引中排除,从而免除唯一约束。

因此,您尝试添加的稀疏索引将允许多个文档而不包含三个键中的任何,但对于所有其他情况,所有三个字段的组合必须是唯一的,任何缺少字段的值为null

在您的示例文档中,从唯一索引的角度来看,它们看起来都如下所示:

{
    "_type" : "veridianDynamics",
    "model" : "sierra",
    "model_unique : null
}

因此,并非独一无二。

仅供参考,此规则存在例外情况,即复合中存在地理空间或文本索引,稀疏索引会将规则更改为仅在考虑是否在索引中包含文档时考虑特殊索引字段。

答案 1 :(得分:0)

根据unique index documentation for missing fields

  

唯一索引和缺少字段

     

如果某个文档没有字段值,则该项目的索引条目将在包含该字段的任何索引中为空。因此,在许多情况下,您需要将唯一约束与稀疏选项组合在一起。 稀疏索引会跳过缺少索引字段的任何文档,而不是为索引条目存储null 。由于唯一索引不能具有字段的重复值,因此没有稀疏选项,MongoDB将拒绝没有索引字段的第二个文档和所有后续文档。考虑以下原型。

因此,认为这也适用于复合索引似乎是合理的。

这是was reported as a bug jira。

MongoDB开发人员决定不包含此功能并关闭请求

  

如果缺少索引中的所有字段,则从索引中排除文档更有意义。复合索引还为索引中的第一个,第一个+第二个等字段提供查询,因此a,b,c上的索引应该能够找到a = 1的所有文档,而不仅仅是b和/或者c也有价值。这更直观,应该是默认行为。

虽然为了定义适当的语义以区分两种可能的情况而做出了一些建议

  

{sparse:true,sparseIfAnyValueMissing:true}

它不仅可以用于我在问题中描述的内容,还可以用于文档继承和支持部分索引

  

我遇到的情况是,当我第一次创建它时,其中一列是null,但可能会在以后设置为ID。当它被设置为ID时,它需要与另一列唯一。

     

不幸的是,我无法使用唯一索引强制执行此操作,因为它会失败,因为许多行可能在其中一列中为空。如果我使用具有稀疏唯一多列索引的常规RDBMS,这将正常工作。不幸的是,Mongo选择以与所有RDBMS不同的方式工作,并且不支持这种情况。

     

鉴于部分索引不是一个快速添加的东西,似乎不会很快添加它们,为什么这个问题会被关闭?请重新开启并考虑实施此问题。

不幸的是,它还不可能(我希望它会在某个时候出现)