john
john

Reputation: 1075

get nested fields of Scala map

I have the following Map Object :

val ad = node.asInstanceOf[Map[String, Any]]

and a printed example of ad object is:

ListMap(userId -> 1234, userName -> Jason, location -> ListMap(longitude -> -79.234264, latitude -> 37.2395), email -> Some([email protected]))

I am trying to access the nested fields of the location field and cast it as a double. I have the following:

ad.get("location") match {
          case Some(i) => i match {
            case j: Map[Any, Any] => j("longitude").asInstanceOf[Double]
          }

My question is there another more graceful/cleaner syntax way to get the nested objects of the location field?

Upvotes: 1

Views: 839

Answers (2)

Ziyang Liu
Ziyang Liu

Reputation: 810

You can't really do anything graceful with a type like Map[String, Any]. I would consider using a more type-safe Json library in the first place, such as Circe.

Otherwise, it depends on what you know statically about your Map. If you know for certain that "location" exists in the Map, and that it always contains a nested Map with the "longitude" key, and that "longitude" is indeed always a Double, then it's OK to return a Double. Otherwise, you should consider returning an Option[Double] or something like Either[String, Double]. For example:

ad.get("location").flatMap {
  case location: Map[String, _] => Try(location("longitude").asInstanceOf[Double]).toOption
  case _ => None
}

This will return a None if the desired value cannot be obtained for whatever reason: "location" doesn't exist, "location" is not a map, the "location" map does not contain "longitude", etc.

Upvotes: 0

Polentino
Polentino

Reputation: 907

It depends on the concept of "graceful/cleaner" because that kind of data structure doesn't smell good.

Anyway, the inner pattern match can be merged with the outer one, like this:

ad.get("location") match  {
    case Some(i: Map[Any,Any]) => i("longitude").asInstanceOf[Double]
    case _ => // do nothing
}

Upvotes: 2

Related Questions