Ruby Getting Deeply Nested JSON API Data

Ruby: Extract elements from deeply nested JSON structure based on criteria

I love nested maps and selects :D

require 'json'

hash = JSON.parse(File.read('data.json'))

moneyline_market_ids = hash["eventTypes"].map{|type|
type["eventNodes"].map{|node|
node["marketNodes"].select{|market|
market["description"]["marketName"] == 'Moneyline'
}.map{|market| market["marketId"]}
}
}.flatten

puts moneyline_market_ids.join(', ')
#=> 1.128255531, 1.128272164, 1.128255516, 1.128272159, 1.128278718, 1.128272176, 1.128272174, 1.128272169, 1.128272148, 1.128272146, 1.128255464, 1.128255448, 1.128272157, 1.128272155, 1.128255499, 1.128272153, 1.128255484, 1.128272150, 1.128255748, 1.128272185, 1.128278720, 1.128272183, 1.128272178, 1.128255729, 1.128360712, 1.128255371, 1.128255433, 1.128255418, 1.128255403, 1.128255387

Ruby: Extract from deeply nested JSON structure based on multiple criteria

Based on this previous answer, you just need to add a select on eventNodes :

require 'json'

json = File.read('data.json')
hash = JSON.parse(json)

moneyline_market_ids = hash["eventTypes"].map{|type|
type["eventNodes"].select{|event_node|
['US', 'GB'].include?(event_node["event"]["countryCode"]) || event_node["event"]["eventName"].include?(' @ ')
}.map{|event|
event["marketNodes"].select{|market|
market["description"]["marketName"] == 'Moneyline'
}.map{|market|
market["marketId"]
}
}
}.flatten

puts moneyline_market_ids.join(', ')
#=> 1.128255531, 1.128272164, 1.128255516, 1.128272159, 1.128278718, 1.128272176, 1.128272174, 1.128272169, 1.128272148, 1.128272146, 1.128255464, 1.128255448, 1.128272157, 1.128272155, 1.128255499, 1.128272153, 1.128255484, 1.128272150, 1.128255748, 1.128272185, 1.128278720, 1.128272183, 1.128272178, 1.128255729, 1.128360712, 1.128255371, 1.128255433, 1.128255418, 1.128255403, 1.128255387

If you want to keep the country code and name information with the id:

moneyline_market_ids = hash["eventTypes"].map{|type|
type["eventNodes"].map{|event_node|
[event_node, event_node["event"]["countryCode"], event_node["event"]["eventName"]]
}.select{|_, country, event_name|
['US', 'GB'].include?(country) || event_name.include?(' @ ')
}.map{|event, country, event_name|
event["marketNodes"].select{|market|
market["description"]["marketName"] == 'Moneyline'
}.map{|market|
[market["marketId"],country,event_name]
}
}
}.flatten(2)

require 'pp'
pp moneyline_market_ids
#=> [["1.128255531", "US", "Philadelphia @ Seattle"],
# ["1.128272164", "US", "Arkansas @ Mississippi State"],
# ["1.128255516", "US", "New England @ San Francisco"],
# ["1.128272159", "US", "Indiana @ Michigan"],
# ["1.128278718", "CA", "Edmonton @ Ottawa"],
# ["1.128272176", "US", "Arizona State @ Washington"],
# ["1.128272174", "US", "Alabama A&M @ Auburn"],
# ...

How can I access (and save to my database) nested objects/properties within a JSON array via an API GET request in Ruby on Rails?

This was resolved by creating a Property and then using its ID in Units:

require 'rest-client'
require 'json'

# Define Method - API Request
def properties

response = RestClient.get('https://api.valoff.ie/api/Property/GetProperties?Fields=*&LocalAuthority=CAVAN%20COUNTY%20COUNCIL&CategorySelected=OFFICE&Format=csv&Download=false')
json = JSON.parse(response)

json.each do |property|
puts "Creating property #{property['PropertyNumber']}"

property_model = Property.create!(

publication_date: property['PublicationDate'],
property_number: property['PropertyNumber'],
county: property['County'],
local_authority: property['LocalAuthority'],
valuation: property['Valuation'],
category: property['Category'],
uses: property['Uses'],
address_1: property['Address1'],
address_2: property['Address2'],
address_3: property['Address3'],
address_4: property['Address4'],
address_5: property['Address5'],
car_park: property['CarPark'],
xitm: property['Xitm'],
yitm: property['Yitm']
)

property['ValuationReport'].each do |unit|
puts "Creating unit."
property_model.units.create!(
level: unit['Level'],
floor_use: unit['FloorUse'],
area: unit['Area'],
nav_per_m2: unit['NavPerM2'],
nav: unit['Nav']
)
end
end
end

# Call Method
properties

Reference: Ruby on Rails: How can I use JSONPath to access (and save to database) nested objects/properties within a JSON array?

ruby: Extracting fields from nested json

Try this:

# just for demonstration, you would probably do json = JSON.parse(response)
json = {
"status": 200,
"data": {
"total": 251,
"alerts": [
{
"dataPoint": "x",
"ackedBy": "x",
...

For just the total:

total = json['data']['total']

For the other values you asked about:

json['data']['alerts'].each do |alerts|
# do whatever you want with these...
alerts['dataPoint']
alerts['startOn']
alerts['ackedOn']

Now the question is, what do you want to do with the results? Do you want to collect them into a new hash? The json['data']['alerts'] is an array so you have to decide how you want to collect them. You could do:

collected_alerts = { 'dataPoints' => [], 'startOns' => [], 'ackedOns' => [] }
json['data']['alerts'].each do |alerts|
collected_alerts['dataPoints'] << alerts['dataPoint']
collected_alerts['startOns'] << alerts['startOn']
collected_alerts['ackedOns'] << alerts['ackedOn']
end

Now you can get all those values in collected_alerts

How to get **nested** objects as JSON from Ruby on the backend to AJAX in the front-end

Your jsonify method is hurting you.

You should call sample_data.to_json directly and let the JSON module deal with the nesting.


EDIT (JSON with custom data type):

To support #to_json within your custom class / object, you need to add a #to_json method to your class. i.e.:

require 'json'
class MyClass
def initialize name, age
@name = name
@age = age
end
def to_json(*a)
{name: @name, age: @age}.to_json(*a)
end
end

[ MyClass.new("John", 24) ].to_json

Filtering nested attributes in rails API json output

I doubt you actually want to nest those resources more then one level deep:

Rule of thumb: resources should never be nested more than 1 level deep. A collection may need to be scoped by its parent, but a specific member can always be accessed directly by an id, and shouldn’t need scoping (unless the id is not unique, for some reason).

- Jamis Buck

Given the domain here it does not make sense that you would have to specify the studio to get the characters for a given movie. The goal of nesting in REST is to make the relationships between two entities explicit by making them part of the URL structure - not to be overly explicit.

Excessive nesting leads to some very overcomplicated code when it comes to stuff like url generation - I mean do you really want to write?

 url_for [:ap1, :v1, studio, movie, :characters]

You can fix these issues by using the shallow: true option:

resources :studios do
resources :movies, shallow: :true do
resources :characters
end
end

or by avoiding "russian doll" calls to resources:

resources :studios do
resources :movies, only: [:new, :create]
end

resources :movies, only: [:show, :update, :destroy] do
resources :characters, only: [:create, :index]
end

You also really should be using assocations to fetch the nested items.

class CharactersController
before_action :set_movie, only: [:index, :create]

# GET /api/v1/movies/1/characters.json
def index
@characters = @movie.characters
end

private

def set_movie
@movie = Movie.find(params[:movie_id])
end
end

In general code like Character.where(studio_id: @studio.id) should be avoided as it leaks the implementation details of the relationship. Your controller should not need to know how characters and studios are related - it just knows that movie has a method named characters.

And I don't really want to get into the details of your modeling here but Character.where(studio_id: @studio.id) will not work with the requirement that movies most likely contains a subset of the characters of a studio - not their entire cinematic universe. Instead you need a join table that links movies and characters.



Related Topics



Leave a reply



Submit