【问题标题】:add a document in mongodb using Play/reactivemongoplugin使用 Play/reactivemongoplugin 在 mongodb 中添加一个文档
【发布时间】:2017-09-12 11:21:58
【问题描述】:

我正在 Play 中编写一个 Action,如果 MongoDB 中不存在 Document,它应该添加一个 Document。我尝试了两种方法,但都没有奏效。我被困在如何处理由响应式mongoplugin返回的未来

Action 获取 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 部分

案例: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


//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) )
  }
})})
  }

  }

我知道代码中的问题所在。我不知道如何解决它。我认为我的方法还不错 - 我想在插入数据库之前检查数据库,但我无法将其安装在响应式mongo apis 和 Futures 周围

【问题讨论】:

  • 它看起来并不是 ReactiveMongo 特有的,而是异步结果通用的。
  • 你是对的。我该如何解决这个问题?
  • 看来您的问题是将Future[Future[T]] 转换为Future[T]。为此,您应该在定义insertFuture 时使用flatMap 而不是map
  • .flatMap更早
  • @ManuChadha 请尝试将问题中的代码示例减少到重现问题的最小情况。

标签: scala playframework future


【解决方案1】:

flatMap 工作。谢谢 Cyrille Corpet 和 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))
      })
    }
  }
  }

【讨论】:

    猜你喜欢
    • 2017-02-17
    • 1970-01-01
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-11
    • 1970-01-01
    • 2018-08-09
    相关资源
    最近更新 更多