i'm writing a Play 2.3.2 application in Scala. I use the reactivemongo driver to access to a mongodb database. I've write that query the db to obtain the most used tag in the database. This method is an Action.async and is implemented as the following:
def max = Action.async { request =>
var max: Int = 0
var tagFound: Tag = null
//obtain all the tags in the db.
val futureTags: Future[List[Tag]] = Tags.all.toList
futureTags map{ (tags: List[Tag]) =>
tags map { (tag: Tag) =>
//create the tag String
val tagName = tag.category + ":" + tag.attr
//search in the db the documents where tags.tag == tag.
val futureRequests : Future[List[recommendationsystem.models.Request]]= Requests.find(Json.obj("tags.tag" -> tagName)).toList
futureRequests map { (requests: List[recommendationsystem.models.Request]) =>
//get the numbers of documents matching the tag
val number: Int= requests.size
if(number > max) {
max = number
tagFound = tag
}
println(max)
}
}
val jsonObject = if(max > 0) Json.obj("tag" -> tagFound, "occurencies" -> max) else Json.obj("tag" -> "NoOne", "occurencies" -> 0)
Ok(jsonObject)
}
}
But the behavior of this method is not deterministic, what's wrong?? I can't understand why the
val jsonObject = if(max > 0) Json.obj("tag" -> tagFound, "occurencies" -> max) else Json.obj("tag" -> "NoOne", "occurencies" -> 0)
Ok(jsonObject)
}
is execute asynchronous and don't wait that the tags map
statement finished.
I have found a few problems with your code:
Here's a rewritten piece of code, I haven't compiled it, but you can get an idea of how it should work:
def max = Action.async { request =>
Tags.all.toList.flatMap { case tags =>
val xs = tags map { case tag =>
val tagName = tag.category + ":" + tag.attr
Requests.find(Json.obj("tags.tag" -> tagName)).toList.map (requests => (tag, requests.size) )
}
val f = Future.sequence(xs)
f.map { case ys =>
val res = ys.foldLeft(Option.empty[(Tag, Int)]) {
case (Some((maxTag, maxOcc)), (tag, occ)) if occ > maxOcc => Some(tag, occ)
case (s@Some(_), _) => s
case (None, (tag, occ)) => Some(tag, occ)
}
val jsonObject = res.map { case (tag, maxOcc) =>
Json.obj("tag" -> tagFound, "occurencies" -> maxOcc)
} getOrElse {
Json.obj("tag" -> "NoOne", "occurencies" -> 0)
}
Ok(jsonObject)
}
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句