0

그래서 JSON과 BSONDocument 형식 모두에 대한 독자와 작성자뿐만 아니라 사례 클래스도 있습니다.json 유효성 검사 및 MongoDB 지속성 (Reactivemongo)을 위해 사례 클래스를 사용하면 id는 어떻게됩니까?

문제는 MongoDB에 삽입 할 때 BSONObjectID를 지정할 수 있기를 원하기 때문에 생성시 반환 할 수 있습니다. 그러나 케이스 클래스에 id: BSONObjectID을 추가하면 작동하도록 JSON 유효성 검사/변형을 가져 오는 방법을 찾을 수 없습니다.

case class Mini(username: String, email: String, quizAnswer1: List[String]) 

implicit object MiniWriter extends BSONDocumentWriter[Mini] { 
    def write(mini: Mini): BSONDocument = BSONDocument(
    "username" -> mini.username, 
    "email" -> mini.email, 
    "quizAnswer1" -> mini.quizAnswer1 
) 
} 

implicit object MiniReader extends BSONDocumentReader[Mini] { 
    def read(doc: BSONDocument): Mini = Mini(
    doc.getAs[String]("username").get, 
    doc.getAs[String]("email").get, 
    doc.getAs[List[String]]("quizAnswer1").toList.flatten 
) 
} 

implicit val miniReads: Reads[Mini] = (
    (JsPath \ "username").read[String] and 
    (JsPath \ "email").read[String] and 
    (JsPath \ "quizAnswer1").read[List[String]] 
)(Mini.apply _) 

implicit val miniWrites: Writes[Mini] = (
    (JsPath \ "username").write[String] and 
    (JsPath \ "email").write[String] and 
    (JsPath \ "quizAnswer1").write[List[String]] 
)(unlift(Mini.unapply)) 

난 정말 같은 모델의 중복 모델 표현 작업을 피하고 싶은 :

이 내 코드입니다. 어떤 아이디어?

답변

1

: 다음과 같은 형식을 사용할 수있는 BSONObjectId의 암시 convertion를 들어

case class Mini(_id:BSONObjectId, username: String, email: String, quizAnswer1: List[String]) 

일시적으로 귀하의 작업. 아이디가 POST 요청에 의해 제공되는 업데이트에 대한

def insert(t: T)(implicit ctx: ExecutionContext): Future[BSONObjectID] = { 
    val id = BSONObjectID.generate 
    val obj = format.writes(t).as[JsObject] 
    obj \ "_id" match { 
     case _: JsUndefined => 
     coll.insert(obj ++ Json.obj("_id" -> id)).map { _ => id } 

    case JsObject(Seq((_, JsString(oid)))) => 
     coll.insert(obj).map { _ => BSONObjectID(oid) } 

    case JsString(oid) => 
     coll.insert(obj).map { _ => BSONObjectID(oid) } 

    case f => sys.error(s"Could not parse _id field: $f") 
} 

}

: 풋에 당신은 다음과 같은 기본 구현을 사용할 수 있습니다.

당신이 DB를 쿼리 할 때 임시 결과 집합

def find(sel: JsObject, limit: Int = 0, skip: Int = 0, sort: JsObject = Json.obj(), projection: JsObject = Json.obj())(implicit ctx: ExecutionContext): Future[Traversable[(T, BSONObjectID)]] = { 
    val cursor = coll.find(sel).projection(projection).sort(sort).options(QueryOpts().skip(skip).batchSize(limit)).cursor[JsObject] 
    val l = if (limit != 0) cursor.collect[Traversable](limit) else cursor.collect[Traversable]() 
    l.map(_.map(js => (js.as[T], (js \ "_id").as[BSONObjectID]))) 
} 
+0

감사합니다. 그 답은 저를 올바른 방향으로 데려갔습니다. 또한 필자는 옵션이 아닌 다른 필드의 최종 솔루션에 넣었습니다. – Wrench

0

플레이의 json으로 fomrat를 사용할 수를 재생 사용/직접 읽기/쓰기 :

https://www.playframework.com/documentation/2.3.x/ScalaJsonCombinators

예는 같을 것이다 : 나는 당신이를 선언 할 필요가 아는 한 지금까지

object Mini { 
    implicit val miniFormat: Format[Mini] = Json.format[Mini] 
} 

id 객체에 '_id'가 있습니다. 당신은 단지 그것을 사용할 수 있습니다 당신은 모델 자체의 ID가 필요하지 않은 경우

implicit object BSONObjectIDFormat extends Format[BSONObjectID] { 
def writes(objectId: BSONObjectID): JsValue = { 
    Json.obj("$oid" -> JsString(objectId.stringify)) 
} 
def reads(json: JsValue): JsResult[BSONObjectID] = json match { 
    case JsString(x) => { 
    val maybeOID: Try[BSONObjectID] = BSONObjectID.parse(x) 
    if (maybeOID.isSuccess) JsSuccess(maybeOID.get) else { 
     JsError("Expected BSONObjectID as JsString") 
    } 
    } 

    case JsObject(Seq((_, oid))) => 
    reads(oid) 

    case _ => JsError("Expected BSONObjectID as JsString") 
} 

}

+0

나는이 개 경우 클래스, 내부 사용을 위해 _id 하나를 사용하여 끝나는 것 같아의 ID를 얻기 위해 다음과 같은 기본 구현을 사용할 수 있습니다 생성시 _id를 추가하고, API에 공개 할 _id를 추가합니다. 이유는 PUT (작성) 또는 POST (갱신)를 수행 할 때 _id를 제공해서는 안됩니다. PUT에서는 생성되어 반환됩니다. POST에서 _id는 '/ mini/a675c76d576d5c'와 같은 URL 경로에서옵니다. 그래서 json 구조에 생성 된 BSONObjectID를 추가하고 내부 케이스 클래스와 그 쓰기로 유효성을 검사 한 다음 BSONDocument 라이터를 사용하여 _id로 케이스 클래스의 내부 버전을 최종 변환합니다. – Wrench

+0

모델 자체에서 ID를 필요로하지 않는다면 작업 중에 일시적으로 ID를 사용할 수 있습니다. PUT에서 다음과 같은 기본 구현을 사용할 수 있습니다. – toggm