0

I'm new to ruby so please excuse any ignorance I may bear. I was wondering how to parse a JSON reponse for every value belonging to a specific key. The response is in the format,

[
  {
    "id": 10008,
    "name": "vpop-fms-inventory-ws-client",
    "msr": [
      {
        "key": "blocker_violations",
        "val": 0,
        "frmt_val": "0"
      },
    ]
  },
  {
    "id": 10422,
    "name": "websample Maven Webapp",
    "msr": [
      {
        "key": "blocker_violations",
        "val": 0,
        "frmt_val": "0"
      }...

There's some other entries in the response, but for the sake of not having a huge block of code, I've shortened it.The code I've written is:

require 'uri'
require 'net/http'
require 'JSON'
url = URI({my url})

    http = Net::HTTP.new(url.host, url.port)

    request = Net::HTTP::Get.new(url)
    request["cache-control"] = 'no-cache'
    request["postman-token"] = '69430784-307c-ea1f-a488-a96cdc39e504'

    response = http.request(request)
    parsed = response.read_body

    h = JSON.parse(parsed)

    num = h["msr"].find {|h1| h1['key']=='blocker_violations'}['val']

I am essentially looking for the val for each blocker violation (the json reponse contains hundreds of entries, so im expecting hundreds of blocker values). I had hoped num would contain an array of all the 'val's. If you have any insight in this, it would be of great help!

EDIT! I'm getting a console output of

scheduler caught exception:
no implicit conversion of String into Integer
C:/dashing/test_board/jobs/issue_types.rb:20:in `[]'
C:/dashing/test_board/jobs/issue_types.rb:20:in `block (2 levels) in <top (requi
red)>'
C:/dashing/test_board/jobs/issue_types.rb:20:in `select'

I suspect that might have too much to do with the question, but some help is appreciated!

1
  • You need to iterate over the array of objects, then iterate over the array of msr, looking for each key that matches. Commented Jun 8, 2016 at 20:11

1 Answer 1

1

You need to do 2 things. Firstly, you're being returned an array and you're only interested in a subset of the elements. This is a common pattern that is solved by a filter, or select in Ruby. Secondly, the condition by which you wish to select these elements also depends on the values of another array, which you need to filter using a different technique. You could attempt it like this:

res = [
  {
    "id": 10008,
    "name": "vpop-fms-inventory-ws-client",
    "msr": [
      {
        "key": "blocker_violations",
        "val": 123,
        "frmt_val": "0"
      }
    ]
  },
  {
    "id": 10008,
    "name": "vpop-fms-inventory-ws-client",
    "msr": [
      {
        "key": "safe",
        "val": 0,
        "frmt_val": "0"
      }
    ]
  }
]

# define a lambda function that we will use later on to filter out the blocker violations
violation = -> (h) { h[:key] == 'blocker_violations' }

# Select only those objects who contain any msr with a key of     blocker_violations
violations = res.select {|h1| h1[:msr].any? &violation }

# Which msr value should we take? Here I just take the first.
values = violations.map {|v| v[:msr].first[:val] }

The problem you may have with this code is that msr is an array. So theoretically, you could end up with 2 objects in msr, one that is a blocker violation and one that is not. You have to decide how you handle that. In my example, I include it if it has a single blocker violation through the use of any?. However, you may wish to only include them if all msr objects are blocker violations. You can do this via the all? method.

The second problem you then face is, which value to return? If there are multiple blocker violations in the msr object, which value do you choose? I just took the first one - but this might not work for you.

Depending on your requirements, my example might work or you might need to adapt it.

Also, if you've never come across the lambda syntax before, you can read more about it here

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

3 Comments

Not suggesting that your suggestion is wrong, but I think I've got another error that prevents me from checking if this way works. Hopefully I can get back to this.
No, you're right. My answer wont work as msr is an array, not a hash. I'll update with a better answer.
Yes! that's exactly what I need, got it down with some tweaks. Thank you so much! Just a follow up, how do I make it so res = h or some other res = such that res is an array containing the whole api call and not a string(?), otherwise the any? function won't work.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.