scalalift-json

Parse json and based on value return a list of keys


Scala Experts , need your help . task is to parse this json and return list of ModelIds for store 'livingstone' which has 'organic' = true.

In this case only RT001 has organic value as true.Please help.

Note: trying to use existing liftweb library .

package Exercises


import net.liftweb.json.{DefaultFormats, _}


object test1 extends App {

  val json_response =
    """{
  "requestId": "91ee60d5f1b45e#316",
  "error": null,
  "errorMessages": [
  ],
  "entries": [

  {

    "modelId":"RT001",
    "sku": "SKU-ASC001",
    "store": "livingstone",
    "ttlInSeconds": 8000,
    "metadata": {
      "manufactured_date": "2019-01-22T01:25Z",
      "organic": "true"
    }
  },
  {

    "modelId":"RT002",
    "sku": "SKU-ASC002",
    "store": "livingstone",
    "ttlInSeconds": 8000,
    "metadata": {
      "manufactured_date": "2019-10-03T01:25Z",
      "organic": "false"
    }
  }

  ] }"""


  val json = parse(json_response)

  implicit val formats = DefaultFormats

  val elements = (json \\ "entries").children


  for (subs <- elements) {
    val m = subs.extract[Subs]
    println(s"Subscriptions: ${m.modelId}, ${m.store}")
    println(" k,v: " + m.metadata.exists(_ == ("organic", "true")))
  }

  case class Subs(modelId: String, store: String, metadata: Map[String, String])


}

Getting Error. Also need help how to filter based on store=living stone and organic=true .

Exception in thread "main" net.liftweb.json.MappingException: No usable value for modelId
Do not know how to convert JArray(List(JString(RT001), JString(RT002))) into class java.lang.String

Final Working code with help from experts:

  val json = parse(json_response)

  implicit val formats = DefaultFormats


  case class Sales(modelId: String, sku: String, store: String, ttlInSeconds: Int, metadata: Map[String, String])

  case class Response(entries: List[Sales])

  val json1 = parse(json_response)
  val response = json.extract[Response]

  val subs = response.entries.filter { e =>
    e.store == "livingstone" &&
      e.metadata.get("organic").contains("true")

  }

  subs.foreach(x=>println(x.modelId))

Solution

  • When processing JSON it is best to convert the whole structure to Scala and then process the Scala, rather than directly processing the JSON.

    So create a Response class and extract that in a single operation, and then process the entries field as appropriate.

    Here is some completely untested code:

    case class Response(entries: List[Subs])
    
    val json = parse(json_response)
    val response = json.extract[Response]
    
    val subs = response.entries.filter{e =>
        e.store == "livingstone" &&
        e.metadata.get("organic").contains("true")
      }
    

    Note that this should work in any JSON library that allows you to extract a class from JSON.