4

I'm using Scala Play 2.7.2 and have read ScalaJsonTransformers and ScalaJson. After calling a JSON API I get back (simplified MCVE) results like this:

{
  "type": "searchset",
  "total": 5,
  "entry": [
    {
        "start": "2019-06-07T09:00:00",
        "end": "2019-06-07T11:00:00",
        "id": "55"
    },
    {
        "start": "2019-06-07T13:00:00",
        "end": "2019-06-07T15:00:00",
        "id": "56"
    },
    {
        "start": "2019-06-07T16:00:00",
        "end": "2019-06-07T17:00:00",
        "id": "60"
    },
    {
        "start": "2019-06-10T11:00:00",
        "end": "2019-06-10T12:00:00",
        "id": "58"
    },
    {
        "start": "2019-06-11T14:00:00",
        "end": "2019-06-11T15:00:00",
        "id": "61"
    }
  ]
}

and I'd like to filter the results and choose only the ones that satisfy a condition, for example, filter out the ones whose end date is greater than certain date val to = new DateTime("2019-06-10T00:00:00") and doing something alla:

(json \\ "end").filter(new DateTime(_).isBefore(to.toDate.getTime))...

but this doesn't work because the result is the selection and not the entire json node and besides it leaves the outer part too.

The solution should output the result:

{
  "type": "searchset",
  "total": 3,
  "entry": [
    {
        "start": "2019-06-07T09:00:00",
        "end": "2019-06-07T11:00:00",
        "id": "55"
    },
    {
        "start": "2019-06-07T13:00:00",
        "end": "2019-06-07T15:00:00",
        "id": "56"
    },
    {
        "start": "2019-06-07T16:00:00",
        "end": "2019-06-07T17:00:00",
        "id": "60"
    }
}

How can this be done using Play JSON?

1 Answer 1

4

For coast-to-coast design try defining update transformer like so

val to = new DateTime("2019-06-10T00:00:00")

val endDateFilterTransformer = (__ \ 'entry).json.update(__.read[JsArray].map {
  case JsArray(values) => JsArray(values.filter(v => (v \ "end").as[DateTime].isBefore(to)))
})

val outJson = json.transform(endDateFilterTransformer)
println(outJson.get)

which outputs

{
  "entry": [
    {
      "start": "2019-06-07T09:00:00",
      "end": "2019-06-07T11:00:00",
      "id": "55"
    },
    {
      "start": "2019-06-07T13:00:00",
      "end": "2019-06-07T15:00:00",
      "id": "56"
    },
    {
      "start": "2019-06-07T16:00:00",
      "end": "2019-06-07T17:00:00",
      "id": "60"
    }
  ],
  "total": 5,
  "type": "searchset"
}

Alternatively for JSON to OO design try deserialising to a model

case class Entry(start: DateTime, end: DateTime, id: String)
object Entry {
  implicit val format = Json.format[Entry]
}
case class Record(`type`: String, total: Int, entry: List[Entry])

object Record {
  implicit val format = Json.format[Record]
}

then filter using regular Scala methods

val to = new DateTime("2019-06-10T00:00:00")
val record = Json.parse(raw).as[Record]
val filteredRecord = record.copy(entry = record.entry.filter(_.end.isBefore(to)))

then deserialise back to json like so:

Json.toJson(filteredRecord)

which outputs

{
  "type": "searchset",
  "total": 5,
  "entry": [
    {
      "start": "2019-06-07T09:00:00.000+01:00",
      "end": "2019-06-07T11:00:00.000+01:00",
      "id": "55"
    },
    {
      "start": "2019-06-07T13:00:00.000+01:00",
      "end": "2019-06-07T15:00:00.000+01:00",
      "id": "56"
    },
    {
      "start": "2019-06-07T16:00:00.000+01:00",
      "end": "2019-06-07T17:00:00.000+01:00",
      "id": "60"
    }
  ]
}

where we use play-json-joda for DateTime serialisation

libraryDependencies += "com.typesafe.play" %% "play-json-joda" % "2.7.3"
import play.api.libs.json.JodaWrites._
import play.api.libs.json.JodaReads._
Sign up to request clarification or add additional context in comments.

3 Comments

Hi @Mario Galic thank you again! It's deliberate not to use serialization here. I'm building an App JSON API on top of an external JSON API provider to feed my Angular frontend. Therefore my Play side is a pass-through and don't want to be serializing it if you know what I mean.
Upvoted as this answer could be of use to others who can consider serialization.
Wow cool I knew the coast-to-coast design could cut ... just didn't manage to work out how :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.