package controllers import javax.inject._ import play.api.Logger import play.api.libs.functional.syntax._ import play.api.libs.json.Reads._ import play.api.libs.json._ import play.api.mvc._ import play.modules.reactivemongo._ import reactivemongo.api.ReadPreference import reactivemongo.play.json._ import reactivemongo.play.json.collection.JSONCollection import scala.concurrent.{ExecutionContext, Future} /** * A bit more complex controller using a Json Coast-to-coast approach. There is no model for Person and some data is created dynamically on creation * Input is directly converted to JsObject to be stored in MongoDB */ @Singleton class PersonController @Inject()(val reactiveMongoApi: ReactiveMongoApi)(implicit exec: ExecutionContext) extends Controller with MongoController with ReactiveMongoComponents { val transformer: Reads[JsObject] = Reads.jsPickBranch[JsString](__ \ "name") and Reads.jsPickBranch[JsNumber](__ \ "age") and Reads.jsPut(__ \ "created", JsNumber(new java.util.Date().getTime())) reduce def personsFuture: Future[JSONCollection] = database.map(_.collection[JSONCollection]("persons")) def create(name: String, age: Int) = Action.async { val json = Json.obj( "name" -> name, "age" -> age, "created" -> new java.util.Date().getTime()) for { persons <- personsFuture lastError <- persons.insert(json) } yield Ok("Mongo LastError: %s".format(lastError)) } def createFromJson = Action.async(parse.json) { request => request.body.transform(transformer) match { case JsSuccess(person, _) => for { persons <- personsFuture lastError <- persons.insert(person) } yield { Logger.debug(s"Successfully inserted with LastError: $lastError") Created("Created 1 person") } case _ => Future.successful(BadRequest("invalid json")) } } def createBulkFromJson = Action.async(parse.json) { request => //Transformation silent in case of failures. val documents = for { persons <- request.body.asOpt[JsArray].toStream maybePerson <- persons.value validPerson <- maybePerson.transform(transformer).asOpt.toList } yield validPerson for { persons <- personsFuture multiResult <- persons.bulkInsert(documents = documents, ordered = true) } yield { Logger.debug(s"Successfully inserted with multiResult: $multiResult") Created(s"Created ${multiResult.n} person") } } def findByName(name: String) = Action.async { // let's do our query val cursor: Future[List[JsObject]] = personsFuture.flatMap{ persons => // find all people with name `name` persons.find(Json.obj("name" -> name)). // sort them by creation date sort(Json.obj("created" -> -1)). // perform the query and get a cursor of JsObject cursor[JsObject](ReadPreference.primary).collect[List]() } // everything's ok! Let's reply with a JsValue cursor.map { persons => Ok(Json.toJson(persons)) } } }