Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play [Scala]: How to flatten a JSON object

Given the following JSON...

{
  "metadata": {
    "id": "1234",
    "type": "file",
    "length": 395
  }
}

... how do I convert it to

{
  "metadata.id": "1234",
  "metadata.type": "file",
  "metadata.length": 395
}

Tx.

like image 961
j3d Avatar asked Jun 17 '14 21:06

j3d


1 Answers

You can do this pretty concisely with Play's JSON transformers. The following is off the top of my head, and I'm sure it could be greatly improved on:

import play.api.libs.json._

val flattenMeta = (__ \ 'metadata).read[JsObject].flatMap(
  _.fields.foldLeft((__ \ 'metadata).json.prune) {
    case (acc, (k, v)) => acc andThen __.json.update(
      Reads.of[JsObject].map(_ + (s"metadata.$k" -> v))
    )
  }
)

And then:

val json = Json.parse("""
  {
    "metadata": {
      "id": "1234",
      "type": "file",
      "length": 395
    }
  }
""")

And:

scala> json.transform(flattenMeta).foreach(Json.prettyPrint _ andThen println)
{
  "metadata.id" : "1234",
  "metadata.type" : "file",
  "metadata.length" : 395
}

Just change the path if you want to handle metadata fields somewhere else in the tree.


Note that using a transformer may be overkill here—see e.g. Pascal Voitot's input in this thread, where he proposes the following:

(json \ "metadata").as[JsObject].fields.foldLeft(Json.obj()) {
  case (acc, (k, v)) => acc + (s"metadata.$k" -> v)
}

It's not as composable, and you'd probably not want to use as in real code, but it may be all you need.

like image 157
Travis Brown Avatar answered Sep 30 '22 14:09

Travis Brown