确保分片集合中唯一字段的唯一性¶
概述¶
在创建索引时增加 unique 用来保证在一个 collection 中字段的唯一性.但是对于 分片集合这样的索引并不能保证字段的唯一性 ,因为插入和索引操作对于每个分片都是本地操作.
在分片集合中,不允许创建不包含全部片键的唯一索引.
如果需要在分片集合中保证字段的唯一性,有三种选项:
规程¶
片键上的唯一约束¶
过程¶
要使用 unique 条件进行分片,需要像下面这样执行 shardCollection :
db.runCommand( { shardCollection : "test.users" , key : { email : 1 } , unique : true } );
记住 _id 字段总是唯一的,默认情况下,MongoDB会将 ObjectId 写到 _id 字段.然而,你也可以将自己生成的值写到 _id 字段并用这个字段作为片键.使用以下操作将 _id 用作片键:
db.runCommand( { shardCollection : "test.users" } )
任意字段的唯一性.¶
如果不能使用片键保证唯一性或者要保证多个字段的唯一性,必须创建第二个 collection 作为 “代理集合”,代理集合需要包含对原始文档集合的引用(比如对 ObjectId 的引用),以及唯一字段.
如果必须在 “代理” 集合上分片,使用 上面的教程 用唯一字段做片键.如果不分片,可以直接在代理集合上创建多个唯一索引.
过程¶
参考以下使用”代理索引”的场景:
{
"_id" : ObjectId("...")
"email" ": "..."
}
_id 字段保存了主集合中的 ObjectId , email 字段是想要保证唯一性的字段.
要在代理集合分片,使用以下操作使用 email 字段做 shard key:
db.runCommand( { shardCollection : "records.proxy" ,
key : { email : 1 } ,
unique : true } );
如果不需要在代理集合分片,使用以下命令在 email 字段创建唯一索引:
db.proxy.ensureIndex( { "email" : 1 }, { unique : true } )
如果不需要在代理集合分片,可以在这个集合上创建多个唯一索引.
插入数据时,在 JavaScript shell: 中使用以下过程:
db = db.getSiblingDB('records');
var primary_id = ObjectId();
db.proxy.insert({
"_id" : primary_id
"email" : "example@example.net"
})
// if: the above operation returns successfully,
// then continue:
db.information.insert({
"_id" : primary_id
"email": "example@example.net"
// additional information...
})
必须首先在代理集合中插入一个数据,如果插入成功了,表明 email 字段是唯一的,之后就可以将其余的文档插入到 information 集合中.
参见
The full documentation of: ensureIndex() and shardCollection.
注意事项¶
你的应用必须能够捕获插入代理集合时产生的错误,并保证两个集合之前的一致性.
如果代理集合需要分片,必须使用你想要保证唯一性的字段做片键.
在对代理集合使用分片的情况下,如果想要保证多个字段的唯一性.必须对 每个保证唯一性的字段 都创建一个代理集合.如果使用一个代理集合用来确保多个字段的唯一性,这个代理集合 不能够 进行分片.
使用本身可以保证唯一性的标识符¶
保证唯一性最好的方法是创建自身可以保证唯一性的标识符(UUID),比如MongoDB的 ObjectId 值.
这个方法对特别适用于 _id ,在不以 _id 为片键进行分片时,应用程序依然可以保证 _id 的唯一性.