如何在Play动作中处理Future [Option [BSONDocument]]

时间:2017-04-14 06:00:40

标签: scala playframework

我正在创建一个用户注册模块。在提交(使用JSON)时,我想检查JSON是否正确解析。如果JSON中存在问题,我想返回错误。如果JSON是正确的,我想检查用户是否已经存在(查看名字)。数据在MongoDB中。我正在使用ReactiveMongoPlugin 0.10。我将使用'one'方法返回Future [Option [BSONDocument]]。如何在Action完成之前等待此Future完成?

方法1 - 使用Action并尝试自己处理Future的结果。代码不编译,也不知道如何等待Future完成

  def registrationRequest = Action(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")

        // the data from client is a JSON of type {user:{firstname:"name"}}. I have created code to parse the JSON
        val query = BSONDocument("user"-> BSONDocument("firstname"->user.firstname))
        Logger.debug("query is:"+query)


        val result = collection.find(query).one

我想现在等待结果并返回Ok(Json.toJson(ack))或BadRequest(Json.toJson(ack))。我怎么做?我写了下面的代码,但我被困在两点(a)代码将等待未来完成(b)onComplete返回单位但Play的动作需要play.api.mvc.Result。我该怎么做?

//I guess data would be Success or Failure
result onComplete ( data =>
        data match {
          //If Success, value would be Some or None
          case Success(value) => {
            value match {
              case None => { //no record. Can add
                Logger.debug("No record from mongo: Can add")
                val ack = Acknowledgment (1, "Welcome " + user.firstName + " " + user.lastName)
                Logger.debug ("success ack Json:" + Json.toJson (ack) )
                Ok (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))
              }

            }
          }
          case Failure (e)=> {
            Logger.debug("error from Mongo."+e)
            val ack = Acknowledgment(0,"MongoDB Error: "+e.toString())
            Logger.debug("fail ack:"+Json.toJson(ack))
            BadRequest(Json.toJson(ack))
          }
        }) //onComplete returns Unit. Action needs play.api.mvc.Result
  case f:JsError => {
    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 - 我读到我应该使用Action.async,但我无法将各个部分放在一起。我遵循的第二种方法是使用Action.Async,但代码没有编译,因为它期望Future [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"-> BSONDocument("firstname"->user.firstName))
        Logger.debug("query is:"+query)

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

        result.map(option => option match {
          case None => {
            //no record. Can add
            Logger.debug("No record from mongo: Can add")
            val ack = Acknowledgment(1, "Welcome " + user.firstName + " " + user.lastName)
            Logger.debug("success ack Json:" + Json.toJson(ack))
            Ok(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))
          }
        }
        )
      }
      case f:JsError => {
        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)) //Action.async expect scala.concurrent.Future[play.api.mvc.SimpleResult]
  }
}


  }

1 个答案:

答案 0 :(得分:1)

解决方案是使用返回Future [SimpleResult]的Action.async。在代码内部使用map和flatMap on Future返回Future [SimpleResult]。