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
Run Ruby Script That Is Stored on Internet
How to Create an Association Between Two Rails Models
Rubymine: Expected ; or End of Line Error After Some Colon
Undefined Method Error When Creating Delayed_Job Workers with Script/Delay_Job
Inserting an Array into Every Nth Element of Another
Adding Fields to Devise Sign Up Using Rails 4
How to Read a Clients Windows Login Name Using Ruby on Rails
Rails Search Query Associated Model
Rails, Ruby, How to Count and Sort, Display Top Results
Initialize the Delayed Jobs Gem by Starting the Workers on Application Start
Ruby Parenthesis Syntax Exception with I++ ++I
How to Upgrade Rvm When the Official Way Doesn't Work
How to Create Two Routes in One Block in Grape
Can't Access the Dockerized App Launched from the Command Line from Outside
How to Get Repeated Elements from Ruby Array
Ruby on Rails - £ Sign Troubles