Michał Jurczuk
Michał Jurczuk

Reputation: 3828

Return ReactiveMongo JSON in Play Framework

What is the fastest way to return JSON text from BSONArray?

I'm returning very big JSON document. Is it possible to omit processing Play JsValue

Now I'm returning like this:

 val result:BSONArray = ....
 Ok(Json.toJson(result))

I think faster would be something like:

 Ok(result.toTextJSON).as(MimeTypes.JSON)

Update here my full code:

val command = Json.parse( s""" {
  "aggregate": "$collection",
  "pipeline": [
  { "$$match": { "$$and" : [
      { "${RootAttrs.TIME}" : { "$$gt": $startSecTime }},
      { "${RootAttrs.TIME}" : { "$$lt": $endSecTime }},
      { "${RootAttrs.COMMAND}" : { "$$eq": ${toCmd(Command.GPS_COORDINATES)} }}
    ]
  }},
  { "$$sort": { "${RootAttrs.TIME}" : 1 }},
  { "$$limit": $MAX_GPS_ALL_DATA },
  { "$$project" : { "_id":0, "${RootAttrs.TIME}":1, "${RootAttrs.COMMAND}":1, "${RootAttrs.VALUE}":1, "${RootAttrs.IGNITION}":1, "${RootAttrs.SIM_NUMBER}":1 } }
]}""")

db.command(RawCommand(BSONDocumentFormat.reads(command).get)).map { out =>
  out.get("result").map {
    case result: BSONArray =>
      Logger.debug("Loaded all GPS history data size: " + result.length)
      Ok(Json.toJson(result)) // <- I need just return JSON, parsing to JsValue can take some time

    case _ =>
      Logger.error("Result GPS history data not array")
      BadRequest

  }.getOrElse(BadRequest)
}

Upvotes: 0

Views: 118

Answers (1)

Bruce Lowe
Bruce Lowe

Reputation: 6203

You can bypass the step of creating the intermediary JsValue if you want to create your own Writeable, and output the string more manually.

Here is a simple example which can be customised to your need

val result: BSONArray = BSONArray("one", "two", "three")

def convertBsonArrayToString(jsval: BSONArray): Array[Byte] = {
  // this method assumes I have a BSONArray of Strings (which you may not)
  var strs: Stream[String] = jsval.stream.map(_.get match { case s: BSONString => s.value })
  var json: String = strs.mkString("[\"", "\",\"", "\"]")
  json.getBytes()
}

implicit def writeableOf_BSONArray: Writeable[BSONArray] = {
  Writeable(convertBsonArrayToString ,Some("application/json"))
}

def doStuff = action {
  Results.Ok(result)
}

The response above is ["one","two","three"]

If you are dealing with massive data - you may also be better off using an Enumerator, and streaming the response.

see: https://www.playframework.com/documentation/2.5.x/ScalaStream

Upvotes: -1

Related Questions