I got two JSON that are structured like this. First one comes from an API:
[
{
"course_code":"Basic 101 - 0913",
"name":"Basic 101",
"start_at":"2013-09-16T00:00:00+02:00",
"end_at":"2013-10-13T23:55:00+02:00",
"workflow_state":"available"
},
{"course_code":"Medium 201 - 0913",
"name":"Medium 201",
"start_at":"2013-08-06T16:55:25+02:00",
"end_at":null,
"workflow_state":"available"
}
]
The second one is a JSON export from my database:
[
{
"id":1,
"course_id":"Basic 101",
"name":"Basic Level",
"description":"blablabla",
"discipline_id":"1",
"duration":"28",
"created_at":null,
"updated_at":null
},
{
"id":2,
"course_id":"Medium 201",
"name":"Medium Level",
"description":"blablabla",
"discipline_id":"1",
"duration":"28",
"created_at":null,
"updated_at":null
}
]
I would like to merge these two JSON into one, with matched :name in the first JSON and :course_id in the second one.
If you know good tutorials on using JSON in Rails, I'm really interested.
This isn't really a JSON issue.
When parsing JSON data it returns arrays and hashes.
One way of merging it in this case would be to loop through the data and check for the parameters you want/need to match. Once you find a match you can either manually create a new Hash with the needed data or you could use
hash1.merge(hash2)
http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-merge
which would return a hash consisting of both Hashes - attributes with the same name would be overwritten in the first hash.
Just a quick answer, to let you know where to go. Assuming first json is in json1 and second is in json2 variables, this code:
require 'json'
arr1 = JSON.parse(json1)
arr2 = JSON.parse(json2)
mrg = []
arr1.each do |el1|
arr2.each do |el2|
if el2['course_id'] == el1['name']
mrg.push(el1.merge(el2))
end
end
end
p mrg
Will print:
[
{
"course_code"=>"Basic 101 - 0913",
"name"=>"Basic Level",
"start_at"=>"2013-09-16T00:00:00+02:00",
"end_at"=>"2013-10-13T23:55:00+02:00",
"workflow_state"=>"available",
"id"=>1,
"course_id"=>"Basic 101",
"description"=>"blablabla",
"discipline_id"=>"1",
"duration"=>"28",
"created_at"=>nil,
"updated_at"=>nil
},
{
"course_code"=>"Medium 201 - 0913",
"name"=>"Medium Level",
"start_at"=>"2013-08-06T16:55:25+02:00",
"end_at"=>nil,
"workflow_state"=>"available",
"id"=>2,
"course_id"=>"Medium 201",
"description"=>"blablabla",
"discipline_id"=>"1",
"duration"=>"28",
"created_at"=>nil,
"updated_at"=>nil
}
]
Related
I'm new to ruby and am having difficulty with looping through deep nested hashes and arrays.
Say I have the following JSON:
{
"Resume":{
.... data ....
},
"StructuredXMLResume":{
"ContactInfo":{
.... data ....
}
]
},
"EmploymentHistory":{
"EmployerOrg":[
{
"EmployerOrgName":"ABC Corp.",
"PositionHistory":[
{
.... data ....
]
},
{
"EmployerOrgName":"National Geo.",
"PositionHistory":[
{
.... data ....
}
]
}
]
}
]
}
.
resume.["Resume"]["StructuredXMLResume"]["EmploymentHistory"]["EmployerOrg"][0]["EmployerOrgName"]
gives me ABC Corp. and
resume.["Resume"]["StructuredXMLResume"]["EmploymentHistory"]["EmployerOrg"][1]["EmployerOrgName"]
gives me National Geo.
How do I loop to print each EmployerOrgName?
Use:
resume.["Resume"]["StructuredXMLResume"]["EmploymentHistory"]["EmployerOrg"].each do |employer_org|
puts employer_org["EmployerOrgName"] # or whatever you want to do with the employer_org hash
end
You can use a enumerator, like each, on any "thing" that either is or behaves like an array/hash object, so in this case you would want to:
all_employerorgs = resume.["Resume"]["StructuredXMLResume"]["EmploymentHistory"]["EmployerOrg"]
# which is an array of hashes that then you can iterate through
# you could iterate directly on that but for readibility
# I would always assign it to a var
all_employerorgs.each do |employerorg|
puts employerorg['EmployerOrgName']
end
I have a SQL query returns some data, here is some sample output:
[
{
"AccountCode": "111123456",
"AccountID": 123456,
"BalanceCurrent": "-8.0",
"Phone": "123456888",
}
]
This is a Hash with an array. There are times when there will be multiple hashes within the array. Just one in this example though.
As stated, this data comes directly from the database.
I have a lookup_phone method in my Customer model that runs the SQL query and then executed in the customer_controller.rb file like so:
customer_phone = Customer.lookup_phone(params[:Phone])
Now, I need to append some extra data to these hash(es) that do not come from the database, like so:
data = [
:match_found => true,
:transfer_flag => false,
:confirm_id => 2
]
This data variable needs to be WITHIN each hash object, not a separate hash object on its own.
Using a simple array concat or + always makes the data a separate hash object. I've come across some good posts saying to use reduce along with merge, but those are Hash methods, not Array methods.
If I try to set data as a Hash instead of an array, I get
no implicit conversion of Hash into Array when I try to do
customer_phone.reduce({}, :merge)
after running customer_phone += data
What is the proper way to append data to an existing Hash object?
maybe combine each and merge
base = [
{
"AccountCode": "111123456",
"AccountID": 123456,
"BalanceCurrent": "-8.0",
"Phone": "123456888",
}
]
data = {:match_found=>true, :transfer_flag=>false, :confirm_id=>2}
base.each { |el| el.merge!(data) }
#=> [{:AccountCode=>"111123456", :AccountID=>123456, :BalanceCurrent=>"-8.0", :Phone=>"123456888", :match_found=>true, :transfer_flag=>false, :confirm_id=>2}]
You can add attr_accessor to your Customer model like this
class Customer
attr_accessor :data
end
With your data array:
data_array = [
:match_found => true,
:transfer_flag => false,
:confirm_id => 2
]
Then, you can execute the query combined with each function:
customer_phone = Customer.lookup_phone(params[:Phone]).each {|e| e.data = data_array}
Access it:
customer_phone.first.data
To render json:
render json: customer_phone, methods: [:data]
I have a Rails app and I am trying to render an array of items from a parsed JSON hash.
My current render statement looks like this
resp = JSON.parse(response.body)
render json: resp
I am using Typheous and this code did not work for me:
resp = JSON.parse(response.body).fetch("item")
The following is the JSON hash (the item key has many values but I'm only displaying one for brevity):
{
ebay: [{
findItemsByKeywordsResponse: [{
ack: [],
version: [],
timestamp: [],
searchResult: [{
count: "91",
item: [{
itemId: [ "321453454731" ]
}]
}]
}]
}]
}
How can I render an array of items from the parsed JSON hash?
Since there is only one value for the ebay and findItemsByKeywordsResponse keys (per the OP's comment), you could retrieve an array of items by doing something like this:
resp = JSON.parse(response.body)
resp[:ebay].first[:findItemsByKeywordsResponse].first[:searchResult].first[:item]
This will give you an array of hashes containing the itemId and any other key-value pairs.
The reason you want to include the .first (or [0]) is because based on the parsed JSON response, your hash contains an array of hashes nested all the way to the item array. If there are multiple searchResult values, you'll need to iterate through those before getting your item array.
I need to extract some data from a JSON response i'm serving up from curb.
Previously I wasn't calling symbolize_keys, but i thought that would make my attempt work.
The controller action:
http = Curl.get("http://api.foobar.com/thing/thing_name/catalog_items.json?per_page=1&page=1") do|http|
http.headers['X-Api-Key'] = 'georgeBushSucks'
end
pre_keys = http.body_str
#foobar = ActiveSupport::JSON.decode(pre_keys).symbolize_keys
In the view (getting undefined method `current_price' )
#foobar.current_price
I also tried #foobar.data[0]['current_price'] with the same result
JSON response from action:
{
"data": {
"catalog_items": [
{
"current_price": "9999.0",
"close_date": "2013-05-14T16:08:00-04:00",
"open_date": "2013-04-24T11:00:00-04:00",
"stuff_count": 82,
"minimum_price": "590000.0",
"id": 337478,
"estimated_price": "50000.0",
"name": "This is a really cool name",
"current_winner_id": 696969,
"images": [
{
"thumb_url": "http://foobar.com/images/93695/thumb.png?1365714300",
"detail_url": "http://foobar.com/images/93695/detail.png?1365714300",
"position": 1
},
{
"thumb_url": "http://foobar.com/images/95090/thumb.jpg?1366813823",
"detail_url": "http://foobar.com/images/95090/detail.jpg?1366813823",
"position": 2
}
]
}
]
},
"pagination": {
"per_page": 1,
"page": 1,
"total_pages": 131,
"total_objects": 131
}
}
Please note that accessing hash's element in Rails work in models. To use it on hash, you have to use OpenStruct object. It's part of standard library in rails.
Considering, #foobar has decoded JSON as you have.
obj = OpenStruct.new(#foobar)
obj.data
#=> Hash
But, note that, obj.data.catalog_items willn't work, because that is an hash, and again not an OpenStruct object. To aid this, we have recursive-open-struct, which will do the job for you.
Alternative solution [1]:
#foobar[:data]['catalog_items'].first['current_price']
But, ugly.
Alternative solution [2]:
Open Hash class, use method_missing ability as :
class Hash
def method_missing(key)
self[key.to_s]
end
end
Hope it helps. :)
I need to bring an array of ruby objects in JSON. I will need to find the item in the JSON object by id, so I think it is best that the id is the key of each object. This structure makes the most sense to me:
{
"1": {"attr1": "val1", "attr2": "val2"},
"2": {"attr1": "val1", "attr2": "val2"},
"3": {"attr1": "val1", "attr2": "val2"}
}
That way I can easily call into the json object like console.log(json_obj[id].attr1)
The issue is that I am not quite sure how to build this in ruby. This is as far as I have gotten:
# in ruby
#book_types = []
BookType.all.each do |bt|
#book_types << {bt.id => {:attr => bt.attr}}
end
#book_types = #book_types.to_json
// In JS
var bookTypes = JSON.parse('<%=raw #book_types %>');
2 questions: How can I build this in ruby? Is there a better way to accomplish what I am doing?
Also just a note that I am building this on the Rails framework
Thanks!
Assuming BookType is an ActiveRecord class, you can just do this:
BookType.all(:select => "attr1, attr2").to_json
...where "attr1, attr2" is a list of the attributes you want to include in your JSON.
If you want the ids as keys, you can do this instead:
BookType.all.inject({}) { |hsh, bt|
hsh[bt.id] = { "attr1" => bt.attr1, "attr2" => bt.attr2 }
hsh
}.to_json