在MongoDb中创建索引时,有两个选项:
- 进行前台索引并在此过程中锁定所有写操作
- 进行后台索引,同时仍允许记录在此期间被写入
我的问题是:
如何在后台构建像唯一索引这样的内容?如果在索引构建过程中插入了重复的文档怎么办?
参考MongoDB文档-
如果mongod进程在后台建立索引时终止,当实例重新启动时,索引构建将重新开始作为前台索引构建。 如果索引构建遇到任何错误,例如重复键错误,则mongod将退出并显示错误。
所以有两种可能性-
后台索引操作在后台运行,以便创建索引时可以运行其他数据库操作。但是,在创建索引的mongo shell会话或连接将被阻塞,直到索引构建完成。要继续向数据库发出命令,请打开另一个连接或mongo实例。
查询不会使用部分构建的索引:只有在索引构建完成后,索引才能被使用。
这意味着发出创建索引命令的客户端将保持阻塞状态,直到索引完全创建。如果您在索引正在构建时从另一个客户端执行类似添加重复文档的操作,它将在没有错误的情况下插入文档,但最终您的初始客户端将遇到无法完成索引的错误,因为唯一索引存在重复键。
我实际上是在尝试理解MongoID的index(..., {background: true})
选项时来到这里的,因为它似乎意味着每次写入都可以在后台执行写入的索引部分,但现在我的理解是该选项仅适用于索引的初始创建。这在 MongoDB的createIndex方法的background
选项文档介绍中有解释(虽然它并不是严格等同于MongoID的background
选项,但它阐明了与该选项相关的功能概念):
MongoDB提供了几个选项,只影响索引的创建[...]本节描述了这些创建选项的用途和行为。
相关信息:您可以指定一些选项来控制索引的属性,这些选项不是索引创建选项。例如,唯一选项会影响索引创建后的行为。
@mltsy
如果从另一个客户端进行操作,例如在索引正在构建时添加重复文档,则会在没有错误的情况下插入该文档。
我不确定这是否正确,因为Mongodb Doc描述如下:
在集合上构建索引时,持有集合的数据库在索引构建完成之前无法进行读取或写入操作。
我使用mongoose进行了测试:
var uniqueUsernameSchema = new Schema({
username: {
index: { unique: true, background: false },
type: String,
required: true
}
})
var U = mongoose.model('U1', uniqueUsernameSchema)
var dup = [{ username: 'Val' }, { username: 'Val' }]
U.create(dup, function (e, d) {
console.log(e, d)
})
唯一索引构建失败。这表明 MongoDB 中的前台选项未阻止写操作。