2017-04-16 1 views
-1

MongoDB에 문서를 추가해야하는 Play의 액션을 작성 중입니다. 나는 두 가지 접근법을 시도했지만 그들 중 누구도 일하지 않고있다. 내가 처리하는 방법 주위에 붙어있어 Futuremouldn 반환 reactmongoplugin에 의해Play/reactivemongoplugin을 사용하여 mongodb에 문서 추가

액션 JSON 데이터를 가져옵니다. 그것은 그것을 달래줍니다. JSON이 정상이면 사용자가 있는지 확인합니다 (이름 찾기). 그렇지 않은 경우 오류를 반환하려면 추가하고 싶습니다. 동일한 동작에서 ReactiveMongoPlugin의 '찾기'및 '삽입'메소드를 결합 할 수 없습니다.

접근법 1 ** - 코드가 scala.concurrent.Future [Play.api.mvc.SimpleResult]를 반환하기 때문에 컴파일되지 않습니다. play.api.mvc.SimpleResult가 필요합니다. 나는 그것이지도 내에서지도를 사용하고 있기 때문에 그것이 있음을 안다.

def registrationRequest = Action.async(parse.json) { request => { 
    Logger.debug("received message:" + request) 
    Logger.debug("received message:" + request.body) 
    val jr: JsResult[User2] = request.body.validate[User2] 
    Logger.debug("jr is " + jr) 

    jr match { 
     case s: JsSuccess[User2] => { 

     val user = s.get 
     Logger.debug("opening database connection") 
     val driver = new MongoDriver() 
     val connection = driver.connection(List("localhost")) 
     val db = connection.db("website-db") 
     val collection = db.collection[BSONCollection]("users") 

     val query = BSONDocument("user.firstname" -> user.firstName) 

     Logger.debug("query is:" + query) 

     //result is of type Future[Option[BSONDocument]] 
     val findFuture:Future[Option[BSONDocument]] = collection.find(query).one 

     findFuture.map(option => option match { 
      case None => { 
      //no record. Can add 
      Logger.debug("No record from mongo: Can add") 
      val newUserDoc = BSONDocument (
       "id" -> user.id, 
       "user" -> BSONDocument (
       "firstname" -> user.firstName, 
       "lastname" -> user.lastName, 
       "email" -> BSONArray (user.email (0)), 
       "password" -> user.password, 
       "address" -> BSONDocument (
        "street" -> user.address.street, 
        "country" -> user.address.country 
       ) 
      ) 
      ) 

      //addResult is of type Future[LastError] 
//this code is problamatic. I am calling a map within a map which creates a Future[Future[Result]]. I need only Future[Result] 
      val insertResult = collection.insert (newUserDoc) 
      insertResult.map(le=>{ 
       if(le.ok) { 
       Logger.debug("insertFuture map") 
       val ack = Acknowledgment(0, "insert success: ") 
       Logger.debug("insert success:" + Json.toJson(ack)) 
       Ok(Json.toJson(ack)) 
       }else { 
       Logger.debug("not inserting") 
       val ack = Acknowledgment (0, "duplicate: ") 
       Logger.debug ("fail ack:" + Json.toJson (ack)) 
       BadRequest (Json.toJson (ack)) 
       } 
      })} 
      case Some(x) => { 
      //duplicae record 
      Logger.debug("error from Mongo. Duplicate:" + x) 

      val ack = Acknowledgment(0, "duplicate: " + x.toString()) 
      Logger.debug("fail ack:" + Json.toJson(ack)) 
      BadRequest(Json.toJson(ack)) 
      } 
     }) 

     //findFutureResult is a Future[Int] 

     case f: JsError => Future.successful({ 
     Logger.debug("error: " + JsError.toFlatJson(f)) 
     val ack = Acknowledgment(0, JsError.toFlatJson(f).toString()) 
     Logger.debug("fail ack:" + Json.toJson(ack)) 
     BadRequest(Json.toJson(ack)) 
     }) 
    } 
    } 
    } 

접근 방식 2 -이 접근 방식에서는지도 내에서지도를 호출하지 않도록 단계를.습니다. 다음 코드는 JsSuccess 부분입니다

경우 S : JsSuccess [사용자 2] => {

val user = s.get 
Logger.debug("opening database connection") 
val driver = new MongoDriver() 
val connection = driver.connection(List("localhost")) 
val db = connection.db("website-db") 
val collection = db.collection[BSONCollection]("users") 

val query = BSONDocument("user.firstname" -> user.firstName) 

Logger.debug("query is:" + query) 

//result is of type Future[Option[BSONDocument]] 
val findFuture:Future[Option[BSONDocument]] = collection.find(query).one 


//findFutureResult is a Future[Int] 
//to avoid calling map within map, I am creating single Futures which would convey result of one Future to another. 
val findFutureResult:Future[Int] = findFuture.map(option => option match { 
    case None => { 
    //no record. Can add 
    Logger.debug("No record from mongo: Can add") 
    1 //return of 1 means record can be added 
    } 
    case Some(x) => { 
    //duplicae record 
    Logger.debug("error from Mongo. Duplicate:" + x) 
    2 //return of 2 means record cannot be added. 

    } 
}) 

//this code would return LastError. the value of LastError can be used to check if insert was performed or not. Accordingly, I want to send OK or BadRequest 
val insertFuture:Future[Future[LastError]] = findFutureResult.map(r => {r match { 
    case 1 => { 
    Logger.debug("findFutureResult map. Adding doc") 
    val newUserDoc = BSONDocument (
    "id" -> user.id, 
    "user" -> BSONDocument (
    "firstname" -> user.firstName, 
    "lastname" -> user.lastName, 
    "email" -> BSONArray (user.email (0)), 
    "password" -> user.password, 
    "address" -> BSONDocument (
    "street" -> user.address.street, 
    "country" -> user.address.country 
) 
) 
) 

    //addResult is of type Future[LastError] 
    collection.insert (newUserDoc) 

} 
    case 2 => Future.successful({ 
    Logger.debug("findFutureResultmap. Not adding a duplicate") 
    LastError(false,None, None, None, None, 0,false) 
}) 
} 
}) 

//this is the problematic code. How do i check value of LastError? insertFuture is Future[Future[LastError]] and not Future[LastError] 
insertFuture.map(lef=>{ lef.map(le=>{ // I cannot call map inside map as explained in approach 1 

    if(le.ok) { 
    Logger.debug("insertFuture map") 
    val ack = Acknowledgment(0, "insert success: ") 
    Logger.debug("insert success:" + Json.toJson(ack)) 
    Ok(Json.toJson(ack)) 
    } 
    else { 
    Logger.debug("not inserting") 
    val ack = Acknowledgment (0, "duplicate: ") 
    Logger.debug ("fail ack:" + Json.toJson (ack)) 
    BadRequest (Json.toJson (ack)) 
    } 
})}) 
    } 

    } 

나는 문제가 코드가 뭔지 알아. 나는 그것을 해결하는 방법을 모른다. 내 접근 방식이 나쁘지 않다고 가정합니다. 데이터베이스를 삽입하기 전에 데이터베이스를 확인하려고 합니다만, API와 선물을 반응 형으로 둘러 볼 수 없습니다.

+0

어쨌든 ReactiveMongo에만 해당되는 것은 아니지만 비동기 결과와 공통점이 있습니다. – cchantep

+0

정확합니다. 문제를 어떻게 해결할 수 있습니까? –

+0

당신의 문제는'미래 [미래형]'을'미래형'T 형으로 변형시키는 것입니다. 이렇게하려면,'insertFuture'를 정의 할 때'map' 대신에'flatMap'을 사용해야합니다. –

답변

0

flatMap이 작동했습니다. Cyrille Coret and cchantep

def registrationRequest = Action.async(parse.json) { request => { 
    Logger.debug("received message:" + request) 
    Logger.debug("received message:" + request.body) 
    val jr: JsResult[User2] = request.body.validate[User2] 
    Logger.debug("jr is " + jr) 

    jr match { 
     case s: JsSuccess[User2] => { 

     val user = s.get 
     Logger.debug("opening database connection") 
     val driver = new MongoDriver() 
     val connection = driver.connection(List("localhost")) 
     val db = connection.db("website-db") 
     val collection = db.collection[BSONCollection]("users") 

     val query = BSONDocument("user.firstname" -> user.firstName) 

     Logger.debug("query is:" + query) 

     //result is of type Future[Option[BSONDocument]] 
     val findFuture: Future[Option[BSONDocument]] = collection.find(query).one 

     val insertFuture: Future[Future[LastError]] = findFuture.map(option => option match { 
      case None => { 
      //no record. Can add 
      Logger.debug("No record from mongo: Can add") 
      //1 
      Logger.debug("findFutureResult map. Adding doc") 
      val newUserDoc = BSONDocument(
       "id" -> user.id, 
       "user" -> BSONDocument(
       "firstname" -> user.firstName, 
       "lastname" -> user.lastName, 
       "email" -> BSONArray(user.email(0)), 
       "password" -> user.password, 
       "address" -> BSONDocument(
        "street" -> user.address.street, 
        "country" -> user.address.country 
       ) 
      ) 
      ) 

      //addResult is of type Future[LastError] 
      collection.insert(newUserDoc) 
      } 
      case Some(x) => { 
      //duplicae record 
      Logger.debug("error from Mongo. Duplicate:" + x) 
      //2 
      Future.successful({ 
       Logger.debug("findFutureResultmap. Not adding a duplicate") 
       LastError(false, None, None, None, None, 0, false) 
      }) 

      } 
     }) 

     insertFuture.flatMap(lef => { 
      lef.map(le => { 
      if (le.ok) { 
       Logger.debug("insertFuture map") 
       val ack = Acknowledgment(0, "insert success: ") 
       Logger.debug("insert success:" + Json.toJson(ack)) 
       Ok(Json.toJson(ack)) 
      } 
      else { 
       Logger.debug("not inserting") 
       val ack = Acknowledgment(0, "duplicate: ") 
       Logger.debug("fail ack:" + Json.toJson(ack)) 
       BadRequest(Json.toJson(ack)) 
      } 
      }) 

      //findFutureResult is a Future[Int] 

     }) 

     } 

     case f: JsError => Future.successful({ 
     Logger.debug("error: " + JsError.toFlatJson(f)) 
     val ack = Acknowledgment(0, JsError.toFlatJson(f).toString()) 
     Logger.debug("fail ack:" + Json.toJson(ack)) 
     BadRequest(Json.toJson(ack)) 
     }) 
    } 
    } 
    } 
관련 문제