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

时间:2015-09-07 10:32:40

标签: mongodb scala indexing casbah unique-index

我很惊讶地看到_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}

2 个答案:

答案 0 :(得分:1)

在mongo课程视频中,声明“_id”索引未使用命令db.collection.getIndexes()标记为唯一,即使 唯一。 我在官方文档中找不到这些信息。

如果您想确定,请尝试添加另一个包含现有_id字段的文档。

我的_id索引未标记为唯一:

> db.products.getIndexes()
[
        {
                "v" : 1,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "test.products"
        }
]

添加现有索引并获取duplicat键错误:

> 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') }"
        }
})

答案 1 :(得分:0)

当我看到上面的@ codename44插入声明时,一个灯泡在我脑海中消失了。事实证明,在文档中为Mongo设置一个唯一的_id字段不仅足以确保唯一性,该字段也必须是ObjectId类型。我的问题是我将字段插入为String

那就是说,我现在遇到的问题是所有插件都不起作用。没有错误,没有索引违规但文档根本没有插入。请参阅下面的更新代码,该代码始终输入第二种情况(writeResult.getN为0):

编辑:原来失败的插件实际上并没有失败。根据{{​​3}} SO帖子,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
}