How can I add fields to a Json object if the field is nested?
This is similar to this forum: Adding field to a JSON using Circe
but instead of:
{
ExistingField: {},
"Newfield" : {}
}
my end goal is something like:
{
ExistingField: {},
"A" : {
"B" : {
"C" : "myStringValue"
}
},
"AA" : {
"BB" : "myStringValue"
}
}
I have a list of nested fields of type String that I would like to iterate through and add.
Instead of them being nested, I just got:
{
ExistingField: {},
"A.B.C" : "myStringValue"
}
my list of fields look like:
val listOfFields: List[String] = List("A.B.C", "AA.BB")
EDIT: What if the added field is an array? for example:
{
ExistingField: {},
"A" : {
"B" : {
"C" : "myStringValue"
}
},
"AA" : {
"BB" : [
{
"CC": "myStringValue"
},
{
"CC": "myStringValue"
}
]
}
}
The recursive function uses pattern matching to convert a list of subfields (from splitting fields by the delimiter) into a nested Json which can then be deepMerge
d into the original Json. The foldLeft
does this repeatedly for each field originally listed.
import io.circe.generic.auto._
import io.circe.parser
import io.circe.syntax._
import io.circe.Json
val jsonStr = """{"Fieldalreadythere": {}}"""
val jsonParse = parser.parse(jsonStr)
val listOfFields: List[String] = List("A.B.C", "AA.BB")
val listOfSplitFields = listOfFields.map(_.split("\\.").toList)
def makeJson(list: List[String]): Json = {
list match {
case h :: Nil => Json.fromFields(List((h, Json.fromString("stringValue"))))
case h :: t => Json.fromFields(List(h -> makeJson(t)))
case Nil => Json.fromFields(Nil)
}
}
val originalJson = jsonParse match {
case Right(value) => value.asObject
case Left(error) => throw error
}
val updateJsons = listOfSplitFields.map(makeJson(_))
updateJsons.foldLeft(originalJson.asJson)(_.deepMerge(_))
Result (of type io.circe.Json
):
{
"AA" : {
"BB" : "stringValue"
},
"A" : {
"B" : {
"C" : "stringValue"
}
},
"Fieldalreadythere" : {
}
}