我正在写一个Action in Play应该在MongoDB中添加一个文档,如果它不存在的话。我尝试了两种方法,但都没有工作。我卡住周围如何处理未来响应mongoplugin使用Play添加文档/ reactivemongoplugin
行动获取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))
}
})})
}
}
我知道问题出在什么代码。我不知道如何解决它。我认为我的方法并不差 - 我想在插入数据库之前检查数据库,但我无法适应它反应mongo apis和期货
它看起来不是特定于ReactiveMongo,而是异步结果。 – cchantep
你是对的。我该如何解决这个问题? –
看来你的问题是将未来[未来[T]]转变为未来[T]。为此,在定义'insertFuture'时,应该使用'flatMap'而不是'map'。 –