Extracting data from Deeply Nested JSON in Ruby on Rails - ruby

Have a Json out put like
{
"query": {
"results": {
"industry": [
{
"id": "112",
"name": "Agricultural Chemicals",
"company": [
{
"name": "Adarsh Plant",
"symbol": "ADARSHPL"
},
{
"name": "Agrium Inc",
"symbol": "AGU"
}
},
]
{
"id": "914",
"name": "Water Utilities",
"company": [
{
"name": "Acque Potabili",
"symbol": "ACP"
},
{
"name": "Water Resources Group",
"symbol": "WRG"
}
]
}
]
}
}
}
Need the out put like - Company Name, Company Symbol, Company id,
Company id name
and example of output would be
Adarsh Plant, ADARSHPL, 112, Agricultural Chemicals
Agrium Inc, AGU, 112, Agricultural Chemicals
Acque Potabili, ACP, 914, Water Utilities
Water Resources Group, WRG, 914, Water Utilities
Any suggestions

There's a typo in your sample json, but we'll talk about it later.
Assuming your json data converted to hash object already like this:
json={
"query"=> {
"results"=> {
"industry"=> [
{
"id"=> "112",
"name"=> "Agricultural Chemicals",
"company"=> [
{
"name"=> "Adarsh Plant",
"symbol"=> "ADARSHPL"
},
{
"name"=> "Agrium Inc",
"symbol"=> "AGU"
}
]
},
{
"id"=> "914",
"name"=> "Water Utilities",
"company"=> [
{
"name"=> "Acque Potabili",
"symbol"=> "ACP"
},
{
"name"=> "Water Resources Group",
"symbol"=> "WRG"
}
]
}
]
}
}
}
You can use inject and map to handle the two level array of industry, inject will iterate the outer array:
json["query"]["results"]["industry"].inject([]){|m,o|
m += o["company"].map{|x| [x["name"],x["symbol"],o["id"],o["name"]]}
}
result is an array of arrays with the order as you wish:
=> [["Adarsh Plant", "ADARSHPL", "112", "Agricultural Chemicals"],
["Agrium Inc", "AGU", "112", "Agricultural Chemicals"],
["Acque Potabili", "ACP", "914", "Water Utilities"],
["Water Resources Group", "WRG", "914", "Water Utilities"]]
If you want get a string delimited by comma, you could chain on .flatten.join(",") at the end.
json["query"]["results"]["industry"].inject([]){|m,o|
m += o["company"].map{|x| [x["name"],x["symbol"],o["id"],o["name"]]}
}.flatten.join(",")
Result:
=> Adarsh Plant,ADARSHPL,112,Agricultural Chemicals,Agrium Inc,AGU,112,Agricultural Chemicals,Acque Potabili,ACP,914,Water Utilities,Water Resources Group,WRG,914,Water Utilities
The typo of your json data:
In the middle }, ] { should be changed to ] },{ .
Convert json to hash
https://stackoverflow.com/a/7964378/3630826

Related

Going from a flat stucture to a hierarchy using jsonata

I am tryig to use jsonata to to transform a flat json result set to something that aggregates some items and creates arrays.
Any advice on how I go from a source like this
`
{
"name": "myname",
"payload": [
{
"role": "Testrole 1",
"permission": "Testpermission 1"
},
{
"role": "Testrole 1",
"permission": "Testpermission 2"
},
{
"role": "Testrole 2",
"permission": "Testpermission 3"
}
]
}
`
to a target like this
`
{
"name": "myname",
"roles": [
{
"rolename": "Testrole 1",
"permissions": [
{
"permissionname": "Testpermission 1"
},
{
"permissionname": "Testpermission 2"
}
]
},
{
"rolename": "Testrole 2",
"permissions": [
{
"permissionname": "Testpermission 3"
}
]
}
]
}
`
I've checked the jsonata documentation but cannot find a good way to achieve this.
You can use the reduce operator to group by a role as described in the Grouping docs here, and then map it to your desired shape:
{
"name": name,
"roles": payload{
role: permission
} ~> $each(function($permissions, $role) {
{
"rolename": $role,
"permissions": $permissions.{ "permissionname": $ }
}
})
}
Live example on the playground: https://stedi.link/WFEPgxp

Delete existing Records if they are not in sent array Rails 5 API

I need help on how to delete records that exist in the DB but not in array sent in a request;
My Array:
[
{ "id": "509",
"name": "Motions move great",
"body": "",
"subtopics": [
{
"title": "Tywan",
"url_path": "https://ugonline.s3.amazonaws.com/resources/6ca0fd64-8214-4788-8967-b650722ac97f/WhatsApp+Audio+2021-09-24+at+13.57.34.mpeg"
},
{
"title": "Transportations Gracious",
"url_path": "https://ugonline.s3.amazonaws.com/resources/6ca0fd64-8214-4788-8967-b650722ac97f/WhatsApp+Audio+2021-09-24+at+13.57.34.mpeg"
},
{
"title": "Transportation part",
"url_path": "https://ugonline.s3.amazonaws.com/resources/6ca0fd64-8214-4788-8967-b650722ac97f/WhatsApp+Audio+2021-09-24+at+13.57.34.mpeg"
}
]
},
{
"name": "Motions kkk",
"body": "",
"subtopics": [
{
"title": "Transportations",
"url_path": "https://ugonline.s3.amazonaws.com/resources/6ca0fd64-8214-4788-8967-b650722ac97f/WhatsApp+Audio+2021-09-24+at+13.57.34.mpeg"
}
]
}
]
Below is my implementation: where am going wrong?
#topics = #course.topics.map{|m| m.id()}
#delete= #topics
puts #delete
if Topic.where.not('id IN(?)', #topics).any?
#topics.each do |topic|
topic.destroy
end
end
it's not clear to me where, in your code, you pick the ids sent in the array you showed before... so I'm assuming like this:
objects_sent = [
{ "id": "509",
"name": "Motions move great",
"body": "",
"subtopics": [
{
"title": "Tywan",
"url_path": "https://ugonline.s3.amazonaws.com/resources/6ca0fd64-8214-4788-8967-b650722ac97f/WhatsApp+Audio+2021-09-24+at+13.57.34.mpeg"
},
{
"title": "Transportations Gracious",
"url_path": "https://ugonline.s3.amazonaws.com/resources/6ca0fd64-8214-4788-8967-b650722ac97f/WhatsApp+Audio+2021-09-24+at+13.57.34.mpeg"
},
{
"title": "Transportation part",
"url_path": "https://ugonline.s3.amazonaws.com/resources/6ca0fd64-8214-4788-8967-b650722ac97f/WhatsApp+Audio+2021-09-24+at+13.57.34.mpeg"
}
]
},
{
"name": "Motions kkk",
"body": "",
"subtopics": [
{
"title": "Transportations",
"url_path": "https://ugonline.s3.amazonaws.com/resources/6ca0fd64-8214-4788-8967-b650722ac97f/WhatsApp+Audio+2021-09-24+at+13.57.34.mpeg"
}
]
}
]
since you have your array like this, the only information you need to query on database is the ids (also, assuming the id's in the array are the id's on database, otherwise it wouldn't make sense). You can get them like this:
sent_ids = objects_sent.map{|o| o['id'].to_i}
Also, it seems to me that, for the code you showed, you want to destroy them based on a specific course. There would be 2 ways to do that. First, using the relationship (I prefer like this one):
#course.topics.where.not(id: sent_ids).destroy_all
Or you can do the query directly on the Topic model, but passing the course_id param:
Topic.where(course_id: #course.id).where.not(id: sent_ids).destroy_all
ActiveRecord is smart enough to mount that query correctly in both ways. Give it a test and see which works better for you

how to sort Data Sources in terraform based on arguments

I use following terraform code to get a list of available db resources:
data "alicloud_db_instance_classes" "resources" {
instance_charge_type = "PostPaid"
engine = "PostgreSQL"
engine_version = "10.0"
category = "HighAvailability"
zone_id = "${data.alicloud_zones.rds_zones.ids.0}"
multi_zone = true
output_file = "./classes.txt"
}
And the output file looks like this:
[
{
"instance_class": "pg.x4.large.2",
"storage_range": {
"max": "500",
"min": "250",
"step": "250"
},
"zone_ids": [
{
"id": "cn-shanghai-MAZ1(b,c)",
"sub_zone_ids": [
"cn-shanghai-b",
"cn-shanghai-c"
]
}
]
},
{
"instance_class": "pg.x8.medium.2",
"storage_range": {
"max": "250",
"min": "250",
"step": "0"
},
"zone_ids": [
{
"id": "cn-shanghai-MAZ1(b,c)",
"sub_zone_ids": [
"cn-shanghai-b",
"cn-shanghai-c"
]
}
]
},
{
"instance_class": "rds.pg.c1.xlarge",
"storage_range": {
"max": "2000",
"min": "5",
"step": "5"
},
"zone_ids": [
{
"id": "cn-shanghai-MAZ1(b,c)",
"sub_zone_ids": [
"cn-shanghai-b",
"cn-shanghai-c"
]
}
]
},
{
"instance_class": "rds.pg.s1.small",
"storage_range": {
"max": "2000",
"min": "5",
"step": "5"
},
"zone_ids": [
{
"id": "cn-shanghai-MAZ1(b,c)",
"sub_zone_ids": [
"cn-shanghai-b",
"cn-shanghai-c"
]
}
]
}
]
And I want to get the one that's cheapest.
One way to do so is by sorting with storage-range.min, but how do I sort this list based on 'storage_range.min'?
Or I can filter by 'instance_class', but "alicloud_db_instance_classes" doesn't seem to like filter as it says: Error: data.alicloud_db_instance_classes.resources: : invalid or unknown key: filter
Any ideas?
The sort() function orders lexicographical and you have no simple key here.
You can use filtering with some code like this (v0.12)
locals {
best_db_instance_class_key = "rds.pg.s1.small"
best_db_instance_class = element( alicloud_db_instance_classes.resources, index(alicloud_db_instance_classes.resources.*.instance_class, best_db_instance_class_key) )
}
(Untested code)

Transferring JSON Data into an array using ruby

This is my JSON code
{
"jobs": [
{
"id": 1,
"title": "Software Developer",
"applicants": [
{
"id": 1,
"name": "Rich Hickey",
"tags": ["clojure", "java", "immutability", "datomic", "transducers"]
},
{
"id": 2,
"name": "Guido van Rossum",
"tags": ["python", "google", "bdfl", "drop-box"]
}
]
},
{
"id": 2,
"title": "Software Architect",
"applicants": [
{
"id": 42,
"name": "Rob Pike",
"tags": ["plan-9", "TUPE", "go", "google", "sawzall"]
},
{
"id": 2,
"name": "Guido van Rossum",
"tags": ["python", "google", "bdfl", "drop-box"]
},
{
"id": 1337,
"name": "Jeffrey Dean",
"tags": ["spanner", "BigTable", "MapReduce", "deep learning", "massive clusters"]
}
]
}
]
}
I want to put the list of "Jobs" in an array using ruby.
I have the following code so far.
require 'json'
file = File.read(filepath)
data_hash = JSON.parse(file)
How do I iterate on the data_hash and chose what information I want and place it in an array?
You can use Array#each because data_hash['jobs'] contains an array of jobs:
data_hash['jobs'].each {|job| ... }
Like this,
arr = Array.new
data_hash.each { |job|
arr.insert(job['name'])
}
use Array#map for shorter code
data_hash['jobs'].map do |job|
# Do whatever you want with the job here
properties = %w(title applicants)
job.select{ |key| properties.include?(key) }
end

Server side template is replaced with uploaded document

I'm am trying to create an envelope for embedded signing with two sever-side templates and a pdf document I generated all in one request. One of the server-side templates has a DOB tab that will be filled in with the data specified in the request.
I've reviewed some other questions related to the docusign api and composite templates with documents here and here I've used these examples to format my request.
Here is the request: NOTE: I'm using the multipart-post gem here to create the request, so some of this request is pseudo HTTP with some multipart-post info. I'm not sure how to get a fully formed HTTP request out in order to post it here.
POST http://localhost/restapi/v2/accounts/2/envelopes
X-DocuSign-Authentication: [omitted]
-------------RubyMultipartPost
Content-Type: application/json
Content-Disposition: form-data;
name="post_body"
{
"compositeTemplates": [
{
"serverTemplates": [
{
"sequence": 1,
"templateId": "3093E017-2E18-4A30-A104-0201C601CE5F"
}
],
"inlineTemplates": [
{
"sequence": 1,
"recipients": {
"signers": [
{
"email": "jond#gmail.com",
"name": "Jon D. Doe",
"recipientId": "1",
"roleName": "Proposed Insured",
"clientUserId": "jond#gmail.com",
"tabs": {
"textTabs": [
],
"checkboxTabs": [
],
"fullNameTabs": [
],
"dateTabs": [
{
"tabLabel": "DOB",
"name": null,
"value": "1-21-1974",
"documentId": null,
"selected": null
}
]
}
}
]
}
}
],
"document": {
"documentId": "1",
"name": "test.pdf"
}
},
{
"serverTemplates": [
{
"sequence": 2,
"templateId": "63CA2E24-BBB8-499F-A884-021580DF54AF"
}
],
"inlineTemplates": [
{
"sequence": 2,
"recipients": {
"signers": [
{
"email": "jond#gmail.com",
"name": "Jon D. Doe",
"recipientId": "1",
"roleName": "Proposed Insured",
"clientUserId": "jond#gmail.com",
"tabs": {
"textTabs": [
],
"checkboxTabs": [
],
"fullNameTabs": [
],
"dateTabs": [
{
"tabLabel": "DOB",
"name": null,
"value": "1-21-1974",
"documentId": null,
"selected": null
}
]
}
}
]
}
}
]
}
],
"status": "sent"
}
-------------RubyMultipartPost
Content-Disposition: file;filename="test.pdf";documentid=1;name="file1"
Content-Length: 34967
Content-Type: application/pdf
Content-Transfer-Encoding: binary
[pdf bytes omitted]
The resulting embedded view only has two documents in it. The 1st is the test.pdf I uploaded in the request and the 2nd is the server-side template specified by templateId=63CA2E24-BBB8-499F-A884-021580DF54AF
I'm not sure what I'm doing wrong .. according to the other questions I referenced above, this should work.
Each compositeTemplate object can only supply files from a single source -- and if a compositeTemplate object specifies a document, then that's considered the document source for that compositeTemplate object. In that case, any documents that happen to be part of a serverTemplate within the same compositeTemplate object will be ignored. This seems to be what you're experiencing.
The request you posted only contains two compositeTemplate objects, so the resulting Envelope only contains documents from two document sources:
The document that's specified in the first compositeTemplate object.
The file(s) contained in the serverTemplate that's specified in the second compositeTemplate object.
If you want the Envelope to also contain the file(s) contained in serverTemplate 3093E017-2E18-4A30-A104-0201C601CE5F, you'll need to add a third compositeTemplate object to the request that specifies 3093E017-2E18-4A30-A104-0201C601CE5F as the server template, and uses the inlineTemplate info to provide necessary recipient and tab information (as you've done with the other compositeTemplate objects in the request you posted). [See below for full request example.]
Finally, note that the value of the sequence properties within each compositeTemplate object specify the order in which the serverTemplates and inlineTemplates will be applied within the scope of that specific compositeTemplate -- it does nothing to influence the sequence of documents in the Envelope. It's the order of the compositeTemplate objects in the request JSON/XML itself that determines sequence of documents in the resulting Envelope.
The following request will result in an Envelope that contains the following files (in this order):
Files from template 3093E017-2E18-4A30-A104-0201C601CE5F
The document that's specified by the request (documentId=1)
Files from template 63CA2E24-BBB8-499F-A884-021580DF54AF
Request body (JSON part):
{
"compositeTemplates": [
{
"serverTemplates": [
{
"sequence": 1,
"templateId": "3093E017-2E18-4A30-A104-0201C601CE5F"
}
],
"inlineTemplates": [
{
"sequence": 2,
"recipients": {
"signers": [
{
"email": "jond#gmail.com",
"name": "Jon D. Doe",
"recipientId": "1",
"roleName": "Proposed Insured",
"clientUserId": "jond#gmail.com",
"tabs": {
"dateTabs": [
{
"tabLabel": "DOB",
"name": null,
"value": "1-21-1974",
"documentId": null,
"selected": null
}
]
}
}
]
}
}
]
},
{
"serverTemplates": [
{
"sequence": 1,
"templateId": "3093E017-2E18-4A30-A104-0201C601CE5F"
}
],
"inlineTemplates": [
{
"sequence": 2,
"recipients": {
"signers": [
{
"email": "jond#gmail.com",
"name": "Jon D. Doe",
"recipientId": "1",
"roleName": "Proposed Insured",
"clientUserId": "jond#gmail.com",
"tabs": {
"dateTabs": [
{
"tabLabel": "DOB",
"name": null,
"value": "1-21-1974",
"documentId": null,
"selected": null
}
]
}
}
]
}
}
],
"document": {
"documentId": "1",
"name": "test.pdf"
}
},
{
"serverTemplates": [
{
"sequence": 1,
"templateId": "63CA2E24-BBB8-499F-A884-021580DF54AF"
}
],
"inlineTemplates": [
{
"sequence": 2,
"recipients": {
"signers": [
{
"email": "jond#gmail.com",
"name": "Jon D. Doe",
"recipientId": "1",
"roleName": "Proposed Insured",
"clientUserId": "jond#gmail.com",
"tabs": {
"dateTabs": [
{
"tabLabel": "DOB",
"name": null,
"value": "1-21-1974",
"documentId": null,
"selected": null
}
]
}
}
]
}
}
]
}
],
"status": "sent"
}

Resources