scalaplayframeworkplayframework-2.0playframework-2.2play-json

JsLookup on multiple level array using play Json library (or any other suggestion)


My function is receiving a JsValue, now this json have lists, and this lists element could also be lists, for example:

{
  "firstName": "Elon",
  "lastName": "Musk",
  "companies": [
    {
      "name": "Tesla",
      "city": "San Francisco",
      "offices": ["sf", "ny"],
      "management": {
        "loscation": "New York",
        "boardMembers": [
          {
            "name": "John",
            "age": 45
          },
          {
            "name": "Mike",
            "age": 55
          },
          {
            "name": "Rebecca",
            "age": 35
          }
        ]
      }
    },
    {
      "name": "SpaceX",
      "city": "San Francisco",
      "offices": ["la", "ta"],
      "management": {
        "loscation": "San Mateo",
        "boardMembers": [
          {
            "name": "Lisa",
            "age": 45
          },
          {
            "name": "Dan",
            "age": 55
          },
          {
            "name": "Henry",
            "age": 35
          }
        ]
      }
    }
  ]
}

So a company have management object, which have boardMembers list.

My function is receiving the path to this element, for example:

companies[*].management.boardMembers[*].name

I want it to return a list with all the elements of this object, so the result will be:

["John", "Mike", "Rebecca", "Lisa", "Dan", "Henry"]

It's a bit complicated, but I thought maybe play.api.libs.json._ would have some feature that could help.

thought about splitting it pathStr.split("(\\[\\*]\\.|\\[\\*])").toList and then iterate to get all elements some how and return JsLookupResult but not sure how.

Just to clarify:

My method will receive 2 parameters, the JsValue and the path as string def myFunc(json: JsValue, path: String)

every time I call myFunc it can receive different path, I'm not sure what it will be only after myFunc was called.


Solution

  • You can do:

    val jsPath = JsPath \ "companies" \\ "management" \ "boardMembers" \\ "name"
    val result = jsPath(Json.parse(input))
    println(result)
    

    Which will print the expected output. See Scastie example.

    Please note the difference between \ and \\:

    To implement myFunc you can try something like this:

    def findAllValuesAtPath(jsValue: JsValue, path: String): List[JsValue] = {
      val jsPath = JsPath(path
        .split("\\[\\*]\\.")
        .flatMap(s => s.split("\\.")
          .map(RecursiveSearch)
        ).toList)
      println(jsPath.path)
      jsPath(jsValue)
    }
    

    Here is another scastie.