Scala Playframework - How to Modify Json and remove element form JsArray (Seq[JsObject]) based on attribute value

155 Views Asked by At

I have a json file something like this.

    {
    "data": [
        {
            "id": 1001,
            "processes": [
                {
                    "process_id": 301,
                    "status": "accepted"
                },
                {
                    "process_id": 302,
                    "status": "accepted"
                },
                {
                    "process_id": 303,
                    "status": "failed"
                },
                {
                    "process_id": 304,
                    "status": "failed"
                }
            ]
        }
    ]
}

I want to iterate through the Json and remove all the processes which have failed status, So my modified Json should be

 {
    "data": [
        {
            "id": 1001,
            "processes": [
                {
                    "process_id": 301,
                    "status": "accepted"
                },
                {
                    "process_id": 302,
                    "status": "accepted"
                }
            ]
        }
    ]
}

I have tried with ScalaJsonTransformers but the prune and update works on JsObject, and not on JsArray.

I did try to use

1)

val inputJsonObj = Json.parse(inputJsonStr).as[Seq[JsObject]
val modifiedJson = inputJsonObj.map(model => (model \ "processes").as[Seq[JsObject]].filter(info => {
          val status = (info \ "status").as[String]
          status match {
            case "accepted" => true
            case _ =>
              // I tried to prune/update here, but its not working 
              false
          }
        }))

The code filter out correctly, but does not modify my actual Json.

  1. I created a mutable JsObject and tried to overwrite the value of Processes but this also does not work. Json.parse(resp).as[mutable.Seq[JsObject]] ++ Json.obj("processes" -> modifiedJson)

Can someone please help in this, how to update my json. I want to modify the Json without using any case classes.

1

There are 1 best solutions below

0
Michał Pawlicki On

If the object with the processes key weren't nested inside an array, you could use JSON transformers:

import play.api.libs.json._

val inputJsonStr = """{
    "id": 1001,
    "processes": [
        {
            "process_id": 301,
            "status": "accepted"
        },
        {
            "process_id": 302,
            "status": "accepted"
        },
        {
            "process_id": 303,
            "status": "failed"
        },
        {
            "process_id": 304,
            "status": "failed"
        }
    ]
}"""
val inputJsonObj = Json.parse(inputJsonStr)

val transformer = (__ \ "processes").json.update(
  __.read[JsArray].map { case JsArray(arr) =>
    JsArray(
      arr.filter(
        info => (info \ "status").as[String].equals("accepted")
      )
    )
  }
)

inputJsonObj
  .transform(transformer)
  .map(Json.prettyPrint)

See https://scastie.scala-lang.org/um08R9qTTnSIvrs97FWg3A

However, modifying an object nested in an array may be impossible (or difficult) due to this bug: https://github.com/playframework/play-json/issues/82.