How to update a nested json using scala play framework?

1.4k views Asked by At

I am trying to update a json value present within a json using Scala play framework.Instead of updating the value it is appending the value.

val newJsonString = """{"P123": 25}"""
val jsonStringAsJsValue = Json.parse("""{"counter_holders": {"Peter": 25}}""")
//jsonStringAsJsValue: play.api.libs.json.JsValue = {"counter_holders":{"Peter":25}}

val jsonTransformer = (__ \"counter_holders" ).json.update(__.read[JsValue].map{o => Json.parse(newJsonString)})

jsonStringAsJsValue.transform(jsonTransformer).get.as[JsValue]
//Now getting this jsvalue
//play.api.libs.json.JsValue = {"counter_holders":{"Peter":25,"P123":25}}
//But need  this jsvalue
//play.api.libs.json.JsValue = {"counter_holders":{"P123":25}}

Any help on this will be really nice.

1

There are 1 answers

0
Tomer Shetah On BEST ANSWER

Quoting from the update method docs:

(__ \ 'key).json.update(reads) is the most complex Reads[JsObject] but the most powerful:

  • copies the whole JsValue => A

  • applies the passed Reads[A] on JsValue => B

  • deep merges both JsValues (A ++ B) so B overwrites A identical branches Please note that if you have prune a branch in B, it is still in A so you'll see it in the result Example:

    {{{ val js = Json.obj("key1" -> "value1", "key2" -> "value2")
    js.validate(__.json.update((__ \ 'key3).json.put(JsString("value3"))))
    => JsSuccess({"key1":"value1","key2":"value2","key3":"value3"},) }}}
    

Therefore the behaviour you see is as expected. If you want to take that approach, of updating using the path, you can use the method prune. For example you can do:

val newJsonString = """{"P123": 25}"""
val jsonStringAsJsValue = Json.parse("""{"counter_holders": {"Peter": 25}}""")
//jsonStringAsJsValue: play.api.libs.json.JsValue = {"counter_holders":{"Peter":25}}

val jsonTransformer = (__ \"counter_holders" ).json
  .update(__.read[JsValue].map{o => Json.parse(newJsonString)})

val jsonTransformerDelete = (__ \"counter_holders" \ "Peter" ).json.prune

jsonStringAsJsValue.transform(jsonTransformer).flatMap(_.transform(jsonTransformerDelete)) match {
  case JsSuccess(value, _) =>
    println(value)
  case JsError(errors) =>
    println(errors)
}

which will produce the wanted behaviour. You can find it in scastie.