Как обновить каждое поле в списке, используя Play json in Scala - PullRequest
2 голосов
/ 29 февраля 2020

У меня есть следующая json строка:

{
   "id":123,
   "students":[
      {
         "collected":{
            "field":"field_1"
         },
         "attr":[{
            "name":"test_name",
            "age":"17",
            "color":"blue"
         }]
      }
   ]
}

Я хочу обновить все элементы объекта "attr" во всем моем списке "студентов". Под обновлением я подразумеваю, что мне нужно обновить значения в объединенную строку ключа и значение

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

Я столкнулся с методом преобразования JsValue. Это мой трансформатор:

val jsonTransformer = (__ \ 'students).json.update(
  of[JsArray].map{
    case JsArray(list) =>
      list.map(o => o)
  }
)

Мой трансформатор ничего не меняет, потому что я не могу найти способ перейти к полю "attr".

Может кто-нибудь дать мне понимание

1 Ответ

2 голосов
/ 01 марта 2020

Принимая в качестве входных данных следующее (где attr - массив объектов):

   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

Мы можем применить следующий преобразователь для получения требуемых результатов:

    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

Выход после преобразования будет:

{
  "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
}

Старый ответ

С учетом ввода ниже (где attr не является массивом 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

Простым решением было бы создать новый JsObject с обновленными значениями, как показано ниже. (без каких-либо проверок)

    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)

Результат для каждого студента будет следующим:

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