2014-01-12 7 views
2

내가 같이 User 문서를 저장 MongoDB를 수집했습니다 삽입 할 때 데이터베이스 오류를 처리하는 방법 :ReactiveMongo : 새 문서

{ 
    "_id" : ObjectId("52d14842ed0000ed0017cceb"), 
    "email": "[email protected]", 
    "firstName": "Joe" 
    ... 
} 

사용자의 이메일 주소로 고유해야합니다, 그래서에 대한 인덱스를 추가 email 필드 :

def insert(user: User): Future[User] = { 
    val json = user.asJson.transform(generateId andThen copyKey(publicIdPath, privateIdPath) andThen publicIdPath.json.prune).get 
    collection.insert(json).map { lastError => 
    User(json.transform(copyKey(privateIdPath, publicIdPath) andThen privateIdPath.json.prune).get).get 
    }.recover { 
    throw new IllegalArgumentException(s"an user with email ${user.email} already exists") 
    } 
} 
: 여기

collection.indexesManager.ensure(
    Index(List("email" -> IndexType.Ascending), unique = true) 
) 

그리고 내가 새 문서를 삽입하는 방법입니다

오류가 발생하면 위의 코드는 IllegalArgumentException을 던지고 발신자가 적절하게 처리 할 수 ​​있습니다. 나는이 같은 recover 섹션 ...

def insert(user: User): Future[User] = { 
    val json = user.asJson.transform(generateId andThen copyKey(publicIdPath, privateIdPath) andThen publicIdPath.json.prune).get 
    collection.insert(json).map { lastError => 
    User(json.transform(copyKey(privateIdPath, publicIdPath) andThen privateIdPath.json.prune).get).get 
    }.recover { 
    case e: Throwable => throw new IllegalArgumentException(s"an user with email ${user.email} already exists") 
    } 
} 

을 수정한다면 ... 나는 더 이상 IllegalArgumentException를 얻을,하지만 난 이런 걸 얻을 :

play.api.Application$$anon$1: Execution exception[[IllegalArgumentException: DatabaseException['E11000 duplicate key error index: gokillo.users.$email_1 dup key: { : "[email protected]" }' (code = 11000)]]] 

을 ... 그리고 발신자가 더 이상 예외를 처리 할 수 ​​없습니다. 이제 실제 질문은 다음과 같습니다

  1. 가 어떻게이 recover 섹션에서 다양한 오류 유형 (LastError에서 제공 즉 사람을) 처리하나요?
  2. 호출자가 예상 예외 (예 : IllegalArgumentException)를 받도록하려면 어떻게해야합니까?
+1

문제가 이상하게 보입니다. 고유 한 인덱스를 가진 반응성 문합 (mongo)을 사용합니다. 이미 존재하는 값을 사용하여 문서를 삽입하려고 할 때'insert'를 호출 한 후에 실패한 미래를 얻습니다. 그럼 나는 '회복'이라고 부를 수있다. 나는 미래의 범위를 '벗어나는'예외를 결코 얻지 못했습니다. – vptheron

+0

recover를 사용하여 예외를 throw하지 마십시오. 그 목적은 예외를 잡아서 정확한 결과를 반환하는 것입니다 (귀하의 경우 사용자). 맵 블록에서 try-catch를 사용하고 대신 거기에서 던져주십시오. –

+0

try-catch를 사용해도 결과가 변경되지 않습니다 ... "play.api.Application $$ anon $ 1 : 실행 예외 [[LastError ..." – j3d

답변

2

나는 물건을 올바르게 관리 할 수있었습니다.그것은 생성 및 검증되기 때문에

val idPath = __ \ 'id 
val oidPath = __ \ '_id 

/** 
    * Generates a BSON object id. 
    */ 
protected val generateId = __.json.update(
    (oidPath \ '$oid).json.put(JsString(BSONObjectID.generate.stringify)) 
) 

/** 
    * Converts the current JSON into an internal representation to be used 
    * to interact with Mongo. 
    */ 
protected val toInternal = (__.json.update((oidPath \ '$oid).json.copyFrom(idPath.json.pick)) 
    andThen idPath.json.prune 
) 

/** 
    * Converts the current JSON into an external representation to be used 
    * to interact with the rest of the world. 
    */ 
protected val toExternal = (__.json.update(idPath.json.copyFrom((oidPath \ '$oid).json.pick)) 
    andThen oidPath.json.prune 
) 

... 

def insert(user: User): Future[User] = { 
    val json = user.asJson.transform(idPath.json.prune andThen generateId).get 
    collection.insert(json).transform(
    success => User(json.transform(toExternal).get).get, 
    failure => DaoServiceException(failure.getMessage) 
) 
} 

user 매개 변수 – User 인스턴스가 항상 유효 JSON을 포함 JSON의 내부 표현과 POJO와 같은 예입니다 : 여기에 아래 ReactiveMongo 가능한 예외를 사용자를 삽입하고 처리하는 방법입니다 생성자에서 더 이상 user.asJson.transform이 실패하는지 확인하지 않아도됩니다.

첫 번째 transformuser에 이미 id이 없도록하고 새로운 Mongo ObjectID를 생성합니다. 그런 다음 새 개체가 데이터베이스에 삽입되고 결과가 외부 표현 (예 : _id =>id)으로 다시 변환됩니다. 오류가 발생하면 현재 오류 메시지와 함께 사용자 지정 예외를 만듭니다. 도움이되기를 바랍니다.

+0

나는 scala와 reactmongo를 처음 사용 했으니,이 소스 코드를 좀 더 발전 시켜라 .. 미리 감사드립니다. –

1

내 경험이 더 순수 자바 드라이버, 그래서 난 단지 일반적으로 몽고 작업을위한 전략에 댓글을 달 수 -

그것은 나에게 보인다 사전에 쿼리를 수행하여 달성하고 모든 mongos 고유성 검사가 중복됩니다. 그로 인해, 실패 가능성 때문에 예외 사항을 상향 조정해야합니다. 이 속도는 느려질뿐만 아니라 쿼리 + 삽입의 조합이 원자 적이지 않기 때문에 경쟁 조건에 취약합니다. 그럴 경우

  • 요청 1 : 삽입을 시도하십시오. 이메일이 있습니까? false - 삽입을 계속하십시오.
  • 요청 2 : 삽입을 시도하십시오. 이메일이 있습니까? false - 삽입으로 진행
  • 요청 1 : 성공
  • 요청 2 : mongo가 데이터베이스 예외를 throw합니다.

mongo가 db 예외를 발생시키고 자신의 불법적 인 주장을 던지게하는 것이 더 간단하지 않습니까?

또한 ID를 생략하면 ID가 생성되고 고유성 검사를 수행하는 데 필요한 간단한 쿼리가 있는지 확인해야합니다. 코드 작성 방법은 여전히 ​​그렇습니다. 자바 드라이버에서 적어도 당신은 그냥

collection.findOne(new BasicDBObject("email",someemailAddress)) 
+0

당신이 제안한 것은 내 첫번째 시도였습니다 ...하지만 DatabaseException은 FatalError이고 따라서 scala "Failure"로 처리되지 않는다고 가정합니다. ReactiveMongo는 fineOne을 지원하지 않습니다 ... – j3d

+0

명시 적으로 DatabaseException을 잡을 수 있습니까? –

0

업데이트 방법의 upsert 모드를 살펴보세요 할 수있다 (제 "를 일치하는 (Upsert를 존재하지 않는 경우) 새 문서를 삽입") : 마지막으로 http://docs.mongodb.org/manual/reference/method/db.collection.update/#insert-a-new-document-if-no-match-exists-upsert

+0

내 업데이트 된 게시물보기 : – j3d

+0

예 알아 두었던 점 ... 제 답변으로는 사용자가 '삽입'하는 것을 예로 들었지만 동일한 원칙이 다른 작업에도 적용됩니다. ReactMongo API를 효과적으로 사용하는 방법을 공유하고 싶었습니다. Tx. – j3d

관련 문제