Play Framework: how to filter values of a json?

515 views Asked by At

I want to filter my json in the attributes field.

The json is like this :

"subject": "cars",
"price": [25],
"location":{city: "Oslo", postalcode :441},
"attributes" :
[{"key":"tc", "value":2, "key_label":typecars", "value_label":"WPD"}, 
{"key":"lk", "value":1, "key_label":"lookupcars", "valnotEqualReadsue_label":"fed"}
{"key":, "value":6, "key_label":"year", "value_label":"fzef"}
{"key":"nc", "value":3, "key_label":ncars", "value_label":"POD"}
{"key":"tc", "value":4, "key_label":plcars", "value_label":"LOD"}
{"key":"pm", "value":5, "key_label":pomcars", "value_label":"PLD"}]

I want to keep only key_label and value_label where key_label ="year" and "pomcars". How can I do that ?

I tried

case class Attribut(key_label: Option[String]                    
                   , value_label: Option[String]
)

case class Ads(subject: Option[String]
           , price: Option[Int]
           , location: Option[Location]
           , attribut: Option[Seq[Attribut]]

)

 implicit val adsReads: Reads[Ads] = (
 (JsPath \ "subject").readNullable[String] and
 (JsPath \ "price" \ 0).readNullable[Int] and
 (JsPath \ "location").readNullable[Location] and
 (JsPath \ "attributes").readNullable[Seq[Attribut]].filter {
 case Some(Attribut(Some(key_label), _)) => (key_label == "year") || key_label == "pomcars")
 case _                                  => false
                }  
 ) (Ads.apply _)

I have the following error : constructor cannot be instantiated to expected type; found : Attribut required: Seq[Attribut]

Thank you for your help.

1

There are 1 answers

4
James Whiteley On BEST ANSWER

The easiest way to do this would be to just read in the JSON and deal with it once it's a Seq of case classes.

For example, read it in like this:

case class Attribute(key_label: Option[String], value_label: Option[String])

object Attribute {
  implicit val reads: Reads[Attribute] = Json.reads[Attribute]
}

json.as[Seq[Attribute]] // or `.asOpt` if you can't guarantee that it'll work

Then you can do something like filtering out values you don't want or folding over the Seq, for example:

json.as[Seq[Attribute]].filter {
  case Attribute(Some(key_label), _) => (key_label == "year") || (key_label == "pomcars")
  case _                             => false
}

or:

json.as[Seq[Attribute]].foldLeft(Seq[Attribute]()) {
  case (acc, curr@Attribute(Some(key_label), _))
    if (key_label == "year") || (key_label == "pomcars") => acc :+ curr

  case (acc, _)                                          => acc
}

These both result in res0: Seq[Attribute] = List(Attribute(Some(year),Some(fzef)), Attribute(Some(pomcars),Some(PLD))).

See live on Scastie