为什么Casbah/MongoDB id索引不是唯一的?



我很惊讶地发现_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 .

也就是说,我现在的问题是没有一个插入工作。没有错误,没有索引冲突,只是没有插入文档。请参阅下面我更新的代码,总是进入第二个case (writeResult.getN为0):

Edit:结果显示失败的插入实际上并没有失败。根据这个帖子,Java驱动程序总是返回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
}

最新更新