MongoDB无法创建唯一稀疏索引(重复键)

3
我想要创建一个覆盖两列的唯一索引,使得该索引允许第二个列存在多个空值。但是:
db.model.ensureIndex({userId : 1, name : 1},{unique : true, sparse : true});

抛出重复键异常:E11000,重复键错误索引:devmongo.model.$userId_1_name_1,重复键为:{ : "-1", : null }。我认为因为sparse=true选项,索引应该允许这种情况,如何实现?我使用的是MongoDB 2.6.5。

3个回答

4
稀疏的复合索引会为文档创建一个索引条目,如果任何字段存在,则在索引中将该值设置为null,对于在文档中不存在的任何字段,在索引中也将其设置为null。换句话说,只有当文档中所有索引字段都丢失时,稀疏的复合索引才会跳过该文档。
从v3.2开始,可以使用部分索引来实现您要进行的操作。您可以使用:
db.model.ensureIndex({userId : 1, name : 1}, { partialFilterExpression: { name: { $exists: true },  unique: true });

此操作将只索引具有 name 字段的文档。

注意:此索引无法被Mongo用于处理按 userId 查询的操作,因为它不包含集合中的所有文档。同时,文档中的 null 被视为值,而具有 null 值的字段是存在的


2

复合索引应被视为一个整体,因此唯一要求(userId,name)对在集合中必须是唯一的,而稀疏意味着如果文档中同时缺少userIdname,则允许。错误消息显示至少有两个文档的(userId,name)对是等效的(如果一个字段缺失,则该值可以被视为null)。


嗯,好的,所以我将所有的userId:“-1”更新为null,但仍然无法创建索引:E11000重复键错误索引:devmongo.model.$userId_1_name_1 dup key:{: null, : null}。 - KIC
@KIC,如果您可以将值更新为null,那么您是否可以删除该字段?只需删除userId和name两个字段,然后使用sparse选项,这将告诉unique该文档应该不受unique约束。因此,如果您删除所有的userId字段,确保name字段不重复,因为如果一个字段存在,另一个缺失的字段将被视为null。 - Wizard
实际上,稀疏数组只能在不存在的字段上工作。空字段被视为已存在的字段。这很愚蠢,但我必须接受它。看起来我得重构我的数据模型 :-( - KIC

0
在我的情况下,字段名称是区分大小写的。因此,在{field1 : 1, field2 : 1}上创建复合索引与{Field1 : 1, Field2 : 1}不同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接