唯一索引可确保索引字段不存储重复值,并且一个值对于给定字段最多出现一次。唯一复合复合索引可确保索引键值的任何给定组合最多只出现一次。默认下, MongoDB在创建集合期间在 _id字段上创建唯一索引。
您可以在用户界面中为 MongoDB Atlas 中托管的部署创建和管理唯一索引。
创建唯一索引
要创建唯一索引,请使用 db.collection.createIndex() 方法,并将 unique 选项设置为 true。
db.collection.createIndex( <key and index type specification>, { unique: true } )
单个字段上的唯一索引
例如,要对 users 集合的 email 字段创建唯一索引,请在 mongosh 中使用以下操作:
db.users.createIndex( { "email": 1 }, { unique: true } )
唯一符合索引
还可以在复合索引上强制执行唯一性约束。唯一复合索引强制要求索引键值的组合具有唯一性。
例如,要在 users 集合的 name、email 和 password 字段上创建唯一索引,请在 mongosh 中使用以下操作:
db.users.createIndex( { name: 1, email: 1, password: 1 }, { unique: true } )
创建的索引强制 name、email 和 password 值的组合具备唯一性。
在 email 和 name 上创建唯一的复合多键索引:
db.users.createIndex( { "email": 1, "name": 1 }, { unique: true } )
唯一索引允许将以下文档插入集合,因为该索引强制 email 和 name 值的组合有唯一性:
db.users.insertMany( [ { name: "Catelyn Stark", email: [ "[email protected]", "[email protected]" ], password: "$2b$12$hash2" }, { name: "Arya Stark", email: [ "[email protected]" ], password: "$2b$12$hash3" } ] )
即使两个文档的"[email protected]" email数组中都有 ,操作仍会成功,因为每个电子邮件值与 name字段的组合都是唯一的。
行为
限制
如果集合中已经包含会违反索引唯一性约束的数据,则 MongoDB 无法在指定的索引字段上创建唯一索引。
您不能在哈希索引上指定唯一约束。
在副本集和分片集群上构建唯一索引
对于副本集和分片集群,使用滚动过程创建唯一索引要求您在该过程中停止对集合的所有写入。如果在此过程中无法停止对集合的所有写入,请勿使用滚动过程。相反,要为集合构建唯一索引,您必须执行以下操作之一:
在副本集的主节点上运行
db.collection.createIndex()。在
mongos上为分片集群运行db.collection.createIndex()
跨单独文档的唯一性约束
唯一约束适用于集合中的独立文档。换言之,唯一索引可以防止独立文档为该索引键具有相同的值。
由于该约束适用于独立文档,因此对于唯一多键索引,只要某文档的索引键值与其他文档的索引键值不重复,该文档就可能包含导致重复索引键值的数组元素。在这种情况下,重复的索引条目仅插入索引一次。
示例,在 email 和 name 上创建唯一复合多键索引:
db.users.createIndex( { "email": 1, "name": 1 }, { unique: true } )
如果此集合中没有其他文档的索引键值为 { "email": "[email protected]", "name": null },则该唯一索引允许将以下文档插入集合:
db.users.insertOne( { _id: ObjectId("59b99db4cfa9a34dcd7885b9"), email: [ "[email protected]", "[email protected]" ] } )
唯一单字段索引中缺失文档字段
对于唯一单字段索引中的索引字段,如果某文档存在 null 或缺失值,则该索引为该文档存储 null 值。由于唯一性约束,单字段唯一索引只能包含一份文档,且该文档在其索引条目中包含 null 值。如果索引条目中存在多份具有 null 值的文档,则索引构建会失败并出现重复键错误。
例如,集合在 email 上具有唯一单字段索引:
db.users.createIndex( { "email": 1 }, { unique: true } )
如果集合尚未包含缺少字段 email 的文档,则该唯一索引允许插入不带字段 email 的文档:
db.users.insertOne( { name: "Arya Stark" } )
但是,如果集合已包含一个缺少字段password 的文档,则无法插入没有字段email 的第二个文档。尝试插入另一个不带 email字段的文档的第二个操作无法插入该文档,因为违反了 email字段的唯一约束条件。
唯一部分索引
部分索引仅对集合中满足指定过滤表达式的文档进行索引。如果同时指定 partialFilterExpression 和唯一性约束,则该唯一性约束仅适用于符合过滤器表达式的文档。
如果文档不满足过滤条件,具有唯一约束的部分索引则不会阻止插入不满足唯一约束的文档。有关示例,请参阅具有唯一约束的部分索引。
分片集群和唯一索引
不能在哈希索引上指定唯一约束。
对于有范围的分片集合,只有以下索引是唯一的:
重要
当 _id 字段不是分片键时,分片集群不会在整个集群中对 _id 字段执行唯一性约束。
如果 _id字段不是分片键,则唯一性约束仅应用于存储文档的分片。这意味着两个或多个文档可以具有相同的 _id 值,前提是它们出现在不同的分片上。
示例,考虑一个分片键为 {x:
1}的分片的集合,它跨越两个分片 A 和 B。由于 _id 键不是分片键,因此该集合可能在分片A 中包含 _id 值为 1 的文档以及分片B 中另一个 _id 值为 1 的文档。
如果 _id字段不是分片键, MongoDB希望应用程序确保各分片中 _id 值的唯一性,示例,使用唯一标识符填充 _id字段。
唯一索引约束意味着:
对于要分片的集合,如果该集合有多个唯一索引,则无法对该集合分片,除非分片键是所有唯一索引的前缀。
对于已分片的集合,除非包含分片键作为前缀,否则无法在其他字段上创建唯一索引。
唯一索引会为缺少索引字段的文档存储空值;即缺失的索引字段被视为
null索引键值的另一个实例。 有关更多信息,请参阅唯一单字段索引中缺少文档字段。
要保持分片键字段的唯一性,请参阅任意字段的唯一性约束。
稀疏和非稀疏唯一索引
从 MongoDB 5.0 开始,具有相同键模式的唯一稀疏和唯一非稀疏索引可以存在于同一个集合中。
唯一和稀疏索引创建
此示例将使用相同的键模式和不同的 sparse 选项来创建多个索引:
db.users.createIndex( { password : 1 }, { name: "unique_index", unique: true } )
db.users.createIndex( { password : 1 }, { name: "unique_sparse_index", unique: true, sparse: true } )
基本索引和稀疏索引创建
还可以使用和不使用稀疏选项创建具有相同键模式的基本索引:
db.users.createIndex( { password : 1 }, { name: "sparse_index", sparse: true } )
db.users.createIndex( { password : 1 }, { name: "basic_index" } )
具有重复键模式的基本索引和唯一索引
从 MongoDB 5.0 开始,基本索引和唯一索引可以使用相同的键模式。
这种键模式的重复允许向已索引的字段添加唯一索引。
示例,您可以创建以下两个使用相同键模式的索引:
db.users.createIndex( { email : 1 }, { name: "basic_index" } )
db.users.createIndex( { email : 1 }, { name: "unique_index", unique: true } )