merge two jsvalues dynamically and map to the child in play scala

481 Views Asked by At

I have the following:

x = [{"value":"cricket","key":"sports"},{"value":"hockey","key":"c"},{"value":"maharastra","key":"states"},{"value":"haryana","key":"states"},{"value":"facebook","key":"company"},{"value":"google","key":"company"}]
y = [{"Id":"India","label":"sports"},{"Id":"India","label":"states"},{"Id":"usa","label":"company"}]

For each label of Id of jsvalue(y) is mapped to key in in another jsValue(x), I want to map those to form below structure:

{
    "Mergedjson": [
        {
            "label": "India",
            "children": [
                {
                    "label": "Sports",
                    "children": [
                        {
                            "value": "Cricket",
                            "enable": false
                        },
                        {
                            "value": "hockey",
                            "enable": false
                        }
                    ]
                },
                {
                    "label": "sates",
                    "children": [
                        {
                            "value": "maharastra",
                            "enable": false
                        },
                        {
                            "value": "Haryana",
                            "enable": false
                        }
                    ]
                }
            ]
        },
        {
            "label": "USA",
            "children": [
                {
                    "label": "companies",
                    "children": [
                        {
                            "value": "google",
                            "enable": false
                        },
                        {
                            "value": "facebook",
                            "enable": false
                        }
                    ]
                }
            ]
        }
    ]
}

All I can think of is to directly merge these jsons where I end up with having one single jsValues of both x and y but not the above mentioned structure.

2

There are 2 best solutions below

0
On

Play itself and play json espicially not a best thing to work with but something like this will work:

val x: JsArray = ???
val y: JsArray = ???

val y1 = y.value.map{x => (x \ "key", x)}.toMap 

val x1 = Json.toJson(x.value.map{obj => 
  val v = obj.asInstanceOf[JsObject].values.toMap
  Json.toJson(v.updated("Id", y1(v("Id"))))
})

and i would advice you to throw play json to window and use circe instead.

0
On

We'll start from defining X and Y, and their formatters:

case class X(value: String, key: String)

object X {
  implicit val format: OFormat[X] = Json.format[X]
}

case class Y(Id: String, label: String)

object Y {
  implicit val format: OFormat[Y] = Json.format[Y]
}

Then, assuming we parsed x and y successfully:

val xs = Json.parse(x).validate[Seq[X]].getOrElse(???)
val ys = Json.parse(y).validate[Seq[Y]].getOrElse(???)

We can first create subLabels, from xs:

val subLabels = xs.groupBy(_.key).map {
  case (value, s) =>
    val values = s.map(x => JsObject(Map("value" -> JsString(x.value), "enable" -> JsFalse)))
    value -> JsObject(Map("label" -> JsString(value), "children" -> JsArray(values)))
}

And then use it to create the labels themselves:

val labels = ys.groupBy(_.Id).map {
  case (id, s) =>
    JsObject(Map("label" -> JsString(id), "children" -> JsArray(s.map(_.label).flatMap(subLabels.get))))
}

The final json will be:

val result = JsObject(Map("Mergedjson" -> JsArray(labels.toSeq)))

Code run at Scastie.