为什么 Casbah/MongoDB id 索引不唯一?
Why is Casbah/MongoDB id index Not Unique?
我很惊讶 _id
不是唯一索引。我正在为 _id
字段提供值,MongoDB 正在创建一个索引,但它不是唯一的。我试图更新它(通过在 _id
字段上创建一个新的唯一索引)但没有任何改变。我也没有收到任何错误。为什么会发生这种情况,如何在 _id
上创建唯一索引?
MongoDB版本(由version()
给出)3.0.6,Casbah版本2.8.2,Scala版本2.11.7.
我的文档结构:
{_id=1, firstName=John, lastName=Doe, phoneNum=111-111-1111, active=true, email=test@gmail.com}
日志中转储的索引(为简洁起见省略了时间戳等)。我不确定为什么每个索引都打印两次,但这是另一个问题。作为记录,这就是我打印索引的方式:collection.indexInfo.foreach { index => logger.debug(s"Index: ${index.toMap}") }
Index: {v=1, key={ "_id" : 1}, name=_id_, ns=akka.users}
Index: {v=1, unique=true, key={ "phoneNum" : 1}, name=phoneNum_1, ns=akka.users}
Index: {v=1, unique=true, key={ "email" : 1}, name=email_1, ns=akka.users, sparse=true}
Index: {v=1, key={ "_id" : 1}, name=_id_, ns=akka.users}
Index: {v=1, unique=true, key={ "phoneNum" : 1}, name=phoneNum_1, ns=akka.users}
Index: {v=1, unique=true, key={ "email" : 1}, name=email_1, ns=akka.users, sparse=true}
在 mongo 课程视频中,指出“_id”索引未使用命令 db.collection.getIndexes()
标记为唯一,即使它 是 唯一.
我在官方文档中找不到这个信息。
如果您想确定,请尝试添加另一个具有现有 _id
字段的文档。
我的 _id
索引未标记为唯一:
> db.products.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.products"
}
]
添加现有索引并获取重复键错误:
> db.products.insert({ "_id" : ObjectId("55ed6ccc20a18b075ba683b2")})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.products.$_id_ dup key: { : ObjectId('55ed6ccc20a18b0
75ba683b2') }"
}
})
当我看到上面的 @codename44 insert 语句时,我的脑子里突然冒出一个灯泡。事实证明,不仅 Mongo 的文档中有一个唯一的 _id
字段来确保唯一性,该字段还必须是 ObjectId
类型。我的问题是我将字段作为 String
.
插入
就是说,我现在遇到的问题是 none 的插入有效。没有错误,没有违反索引,但根本没有插入文档。请参阅下面我更新的代码,该代码始终进入第二种情况(writeResult.getN
为 0):
Edit: 事实证明,失败的插入实际上并没有失败。根据 this SO post,对于插入的行数,Java 驱动程序总是 returns 0。所以除非有异常,否则总是假定插入成功。
override def createUser(user: User) = {
val dbObj = userToDbObj(user)
val result = Try(collection.insert(dbObj, WriteConcern.Safe))
val newUser = user.copy(userId = Some(dbObj.get(USER_ID).toString))
result match {
case Success(writeResult) if (writeResult.getN == 1) => Some(newUser)
case Success(writeResult) =>
logger.error(s"Failed to create user: ${newUser}, write result: ${writeResult}."); None
case Failure(ex) => logger.error("Failed to create user.", ex); None
}
}
private def userToDbObj(user: User) = {
val builder = MongoDBObject.newBuilder
builder += USER_ID -> (user.userId match {
case Some(userId) if (ObjectId.isValid(userId)) => logger.info("Using given user id."); new ObjectId(userId)
case _ => logger.info("Generating new user id."); new ObjectId()
})
builder += (FIRST_NAME.toString -> user.firstName,
LAST_NAME.toString -> user.lastName,
PHONE_NUM.toString -> user.phoneNum)
user.email match {
case Some(email) => builder += EMAIL.toString -> user.email.get
case _ =>
}
builder.result
}
我很惊讶 _id
不是唯一索引。我正在为 _id
字段提供值,MongoDB 正在创建一个索引,但它不是唯一的。我试图更新它(通过在 _id
字段上创建一个新的唯一索引)但没有任何改变。我也没有收到任何错误。为什么会发生这种情况,如何在 _id
上创建唯一索引?
MongoDB版本(由version()
给出)3.0.6,Casbah版本2.8.2,Scala版本2.11.7.
我的文档结构:
{_id=1, firstName=John, lastName=Doe, phoneNum=111-111-1111, active=true, email=test@gmail.com}
日志中转储的索引(为简洁起见省略了时间戳等)。我不确定为什么每个索引都打印两次,但这是另一个问题。作为记录,这就是我打印索引的方式:collection.indexInfo.foreach { index => logger.debug(s"Index: ${index.toMap}") }
Index: {v=1, key={ "_id" : 1}, name=_id_, ns=akka.users}
Index: {v=1, unique=true, key={ "phoneNum" : 1}, name=phoneNum_1, ns=akka.users}
Index: {v=1, unique=true, key={ "email" : 1}, name=email_1, ns=akka.users, sparse=true}
Index: {v=1, key={ "_id" : 1}, name=_id_, ns=akka.users}
Index: {v=1, unique=true, key={ "phoneNum" : 1}, name=phoneNum_1, ns=akka.users}
Index: {v=1, unique=true, key={ "email" : 1}, name=email_1, ns=akka.users, sparse=true}
在 mongo 课程视频中,指出“_id”索引未使用命令 db.collection.getIndexes()
标记为唯一,即使它 是 唯一.
我在官方文档中找不到这个信息。
如果您想确定,请尝试添加另一个具有现有 _id
字段的文档。
我的 _id
索引未标记为唯一:
> db.products.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.products"
}
]
添加现有索引并获取重复键错误:
> db.products.insert({ "_id" : ObjectId("55ed6ccc20a18b075ba683b2")})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.products.$_id_ dup key: { : ObjectId('55ed6ccc20a18b0
75ba683b2') }"
}
})
当我看到上面的 @codename44 insert 语句时,我的脑子里突然冒出一个灯泡。事实证明,不仅 Mongo 的文档中有一个唯一的 _id
字段来确保唯一性,该字段还必须是 ObjectId
类型。我的问题是我将字段作为 String
.
就是说,我现在遇到的问题是 none 的插入有效。没有错误,没有违反索引,但根本没有插入文档。请参阅下面我更新的代码,该代码始终进入第二种情况(writeResult.getN
为 0):
Edit: 事实证明,失败的插入实际上并没有失败。根据 this SO post,对于插入的行数,Java 驱动程序总是 returns 0。所以除非有异常,否则总是假定插入成功。
override def createUser(user: User) = {
val dbObj = userToDbObj(user)
val result = Try(collection.insert(dbObj, WriteConcern.Safe))
val newUser = user.copy(userId = Some(dbObj.get(USER_ID).toString))
result match {
case Success(writeResult) if (writeResult.getN == 1) => Some(newUser)
case Success(writeResult) =>
logger.error(s"Failed to create user: ${newUser}, write result: ${writeResult}."); None
case Failure(ex) => logger.error("Failed to create user.", ex); None
}
}
private def userToDbObj(user: User) = {
val builder = MongoDBObject.newBuilder
builder += USER_ID -> (user.userId match {
case Some(userId) if (ObjectId.isValid(userId)) => logger.info("Using given user id."); new ObjectId(userId)
case _ => logger.info("Generating new user id."); new ObjectId()
})
builder += (FIRST_NAME.toString -> user.firstName,
LAST_NAME.toString -> user.lastName,
PHONE_NUM.toString -> user.phoneNum)
user.email match {
case Some(email) => builder += EMAIL.toString -> user.email.get
case _ =>
}
builder.result
}