score:2

Accepted answer

Taking following as input (where attr is an array of objects):

   val input =
      """
        |{
        |   "id":123,
        |   "students":[
        |      {
        |         "collected":{
        |            "field":"field_1"
        |         },
        |         "attr":[{
        |            "name":"test_name",
        |            "age":"17",
        |            "color":"blue"
        |         }]
        |      },
        |      {
        |         "collected":{
        |            "field":"field_2"
        |         },
        |         "attr":[{
        |            "name":"test_name2",
        |            "age":"18",
        |            "color":"red"
        |         }]
        |      }
        |   ]
        |}
        |""".stripMargin

We can apply following transformer to get the required results:

    val attrTransformer = (__ \ "attr").json.update {
      __.read[JsArray].map {
        case JsArray(values) =>

          val updatedValues = values.map { x =>
            JsObject(x.as[JsObject].fields.map { z =>
              val (key, value) = z
              (key, JsString(key + value.as[String]))
            })
          }

          JsArray(updatedValues)
      }
    }

    val transformer = (__ \ "students").json.update(Reads.list(attrTransformer).map(x => JsArray(x)))

    val output = json.transform(transformer).get

The output after transformation will be:

{
  "students" : [ {
    "collected" : {
      "field" : "field_1"
    },
    "attr" : [ {
      "name" : "nametest_name",
      "age" : "age17",
      "color" : "colorblue"
    } ]
  }, {
    "collected" : {
      "field" : "field_2"
    },
    "attr" : [ {
      "name" : "nametest_name2",
      "age" : "age18",
      "color" : "colorred"
    } ]
  } ],
  "id" : 123
}

Old Answer

Considering the below input (where attr is not an array of JsObject):

    val input =
      """
        |{
        |   "id":123,
        |   "students":[
        |      {
        |         "collected":{
        |            "field":"field_1"
        |         },
        |         "attr":{
        |            "name":"test_name",
        |            "age":"17",
        |            "color":"blue"
        |         }
        |      },
        |      {
        |         "collected":{
        |            "field":"field_2"
        |         },
        |         "attr":{
        |            "name":"test_name2",
        |            "age":"18",
        |            "color":"red"
        |         }
        |      }
        |   ]
        |}
        |""".stripMargin

A simple solution would be to create a new JsObject with updated values as below. (without any validations)

    val students = (Json.parse(input) \ "students").as[JsArray]
    val requiredStudents = students.value.map { student =>
      val attr = student \ "attr"

      val updatedAttributes = attr.get.as[JsObject].fields.map { x =>
        val (key, value) = x
        (key, JsString(key + value.as[String]))
      }

      val requiredStudent = student.as[JsObject] ++ Json.obj("attr" -> JsObject(updatedAttributes))
      requiredStudent
    }

    requiredStudents.foreach(println)

The output for each student will be as follows:

{"collected":{"field":"field_1"},"attr":{"name":"nametest_name","age":"age17","color":"colorblue"}}
{"collected":{"field":"field_2"},"attr":{"name":"nametest_name2","age":"age18","color":"colorred"}}

Related Query

More Query from same tag