3

I have an array of json objects like this

[
  {
    "events": [
      {
        "type": "message",
        "attributes": [
          {
            "key": "action",
            "value": "withdraw_reward"
          },
          {
            "key": "sender",
            "value": "bob"
          },
          {
            "key": "module",
            "value": "distribution"
          },
          {
            "key": "sender",
            "value": "bob"
          }
        ]
      },
      {
        "type": "credit",
        "attributes": [
          {
            "key": "recipient",
            "value": "ross"
          },
          {
            "key": "sender",
            "value": "bob"
          },
          {
            "key": "amount",
            "value": "100"
          }
        ]
      },
      {
        "type": "rewards",
        "attributes": [
          {
            "key": "amount",
            "value": "100"
          },
          {
            "key": "validator",
            "value": "sarah"
          }
        ]
      }
    ]
  },
  {
    "events": [
      {
        "type": "message",
        "attributes": [
          {
            "key": "action",
            "value": "withdraw_reward"
          },
          {
            "key": "sender",
            "value": "bob"
          },
          {
            "key": "module",
            "value": "distribution"
          },
          {
            "key": "sender",
            "value": "bob"
          }
        ]
      },
      {
        "type": "credit",
        "attributes": [
          {
            "key": "recipient",
            "value": "ross"
          },
          {
            "key": "sender",
            "value": "bob"
          },
          {
            "key": "amount",
            "value": "100"
          }
        ]
      },
      {
        "type": "rewards",
        "attributes": [
          {
            "key": "amount",
            "value": "200"
          },
          {
            "key": "validator",
            "value": "Ryan"
          }
        ]
      }
    ]
  }
]

How to traverse through the types, check if it's type equals to rewards and then go through the attributes and verify if the validator equals to sarah and fetch the value of the key amount? Pretty new to scala and play framework. Any help would be great. Thanks

8
  • 1
    Did you read the JSON as case classes or as JsArray? Commented Aug 29, 2021 at 13:16
  • Tried the Json.parse(obj) but that didn't work as obj is a string array Commented Aug 29, 2021 at 13:31
  • 2
    please read the documentation Commented Aug 29, 2021 at 14:16
  • 1
    Json.parse("[]") does work. Edit your post with the code you tried, otherwise we cannot help. Commented Aug 29, 2021 at 14:20
  • What exactly do you want as a result? A list of all amount values from rewards where Sara is the "validator", or the sum of those amounts? Or a list of all the "reward objects" validated by Sara? Commented Sep 1, 2021 at 12:50

1 Answer 1

4

You could parse your JSON into a structure of case classes for easier handling and then extract the wanted field like so:

val json = 
"""[
 {"events":[
            {
              "type":"message","attributes":[
                   {"key":"action","value":"withdraw_reward"}, 
                   {"key":"sender","value":"bob"}, 
                   {"key":"module","value":"distribution"}, 
                   {"key":"sender","value":"bob"}
            ]},
           {
             "type":"credit","attributes":[
                  {"key":"recipient","value":"ross"},
                  {"key":"sender","value":"bob"},
                  {"key":"amount","value":"100"}
           ]},
           {
             "type":"rewards","attributes":[
                  {"key":"amount","value":"100"}, 
                  {"key":"validator","value":"sara"}
           ]}
        ]
 },
   {"events":[
            {
              "type":"message","attributes":[
                        {"key":"action","value":"withdraw_reward"}, 
                   {"key":"sender","value":"bob"}, 
                   {"key":"module","value":"distribution"}, 
                   {"key":"sender","value":"bob"}
            ]},
           {
             "type":"credit","attributes":[
                  {"key":"recipient","value":"ross"},
                  {"key":"sender","value":"bob"},
                  {"key":"amount","value":"100"}
           ]},
           {
             "type":"rewards","attributes":[
                  {"key":"amount","value":"200"}, 
                  {"key":"validator","value":"Ryan"}
           ]}
        ]
 }
]
"""
case class EventWrapper(events: Seq[Event])
case class KeyValue(key: String, value: String)
case class Event(`type`: String, attributes: Seq[KeyValue])
 import play.api.libs.json._

    implicit val kvReads: Reads[KeyValue] = Json.reads[KeyValue]
    implicit val eventReads: Reads[Event] = Json.reads[Event]
    implicit val eventWrapperReads: Reads[EventWrapper] = Json.reads[EventWrapper]

    val rewardAmountsValidatedBySara = Json
      .parse(json)
      .as[Seq[EventWrapper]]
      .flatMap {
        _.events.collect {
          case Event(t, attributes) if t == "rewards" && attributes.contains(KeyValue("validator", "sara")) =>
            attributes.collect {
              case KeyValue("amount", value) => value
            }
        }.flatten
      }

    val amount = rewardAmountsValidatedBySara.head

For your example, rewardAmountsValidatedBySara would yield a List of Strings containing only the String "100". Which you could retrieve (potentially unsafe) with .head as shown above.

Normally you would not do this, as it could throw an exception on an empty List, so it would be better to use .headOption which returns an Option which you can then handle safely.

Note that the implicit Reads are Macros, which automatically translate into Code, that instructs the Play Json Framework how to read the JsValue into the defined case classes, see the documentation for more info.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.