Get data from a JSON Array - json

I have a JSON array:
response = [
%{
"created_at" => 1542757526,
"email" => "bcs#yahoo.com",
"first_name" => "rana",
"id" => "YW1pcnBheWFyeUB5YWhvby5jb20=",
"last_clicked" => nil,
"last_emailed" => nil,
"last_name" => "amir",
"last_opened" => nil,
"updated_at" => 1542759123
},
%{
"created_at" => 1542757457,
"email" => "abc#gmail.com",
"first_name" => "rana",
"id" => "cmFtaXIyNDI2QGdtYWlsLmNvbQ==",
"last_clicked" => nil,
"last_emailed" => nil,
"last_name" => "amir",
"last_opened" => nil,
"updated_at" => 1542759001
},
# .......
]
I'm trying to get the email field of all items in the response variable. Example:
["bcs#yahoo.com", "xyz#gmail.com", ....]

You're looking for Enum.map/2. This method calls the passed function on every item in the given list/enumerable:
Enum.map(response, fn item -> item["email"] end )
Alternatively, you can use the shorthand and make it concise:
Enum.map(response, &(&1["email"]))
External Resources: See this and also this to understand the concept of mapping in functional programming in general.
Side note: flat_map/2 is a variation of map/2 that expects the "mapped result" to be another list (so it can be joined and flattened with the rest of the mapped results).

In addition to map, you could also look at comprehensions. Essentially they combine the functionality of Enum.map/2 & Enum.filter/2.
They allow you to do something like this:
for %{"email" => email} <- response, do: email
or this:
for item <- response, do: item["email"]
Note there's a subtle difference in behavior between the result of the two: the former will filter out any items that do not match the left-hand side (it will only keep maps with an "email" key), but the latter will map the items lacking an email to nil.

Related

Manipulating and Outputting JSON in Ruby

I have a JSON return (is it a hash? array? JS object?) where every entry is information on a person and follows the following format:
{"type"=>"PersonSummary",
"id"=>"123", "properties"=>{"permalink"=>"personname",
"api_path"=>"people/personname"}}
I would like to go through every entry, and output only the "id"
I've put the entire JSON pull "response" into "result"
result = JSON.parse(response)
then, I'd like to go through result and do print the ID and "api_path" of the person:
result.each do |print id AND api_path|
How do I go about doing this in Ruby?
The only time you would need to use JSON.parse is if you have a string you need to parse into a Hash. For Example:
result = JSON.parse('{ "type" : "PersonSummary", "id" : 123, "properties" : { "permalink" : "personname", "api_path" : "people/personname" } }')
Once you have the Hash, result could be accessed by giving it the key, like result[:id] or result['id'] (both will work), or you can iterate through the hash too using the following code.
If you need to access the api_path value you would do so by using result['properties']['api_path']
result = { 'type' => 'PersonSummary', 'id' => 123, 'properties' => { 'permalink' => 'personname', 'api_path' => 'people/personname' } }
result.each do |key, value|
puts "Key: #{key}\t\tValue: #{value}"
end
You could even do something like puts value if key == 'id' if you just want to show certain values.

Jira API | Error: "Operation value must be a string" - trying to set value nested two levels deep

Trying to create a new jira ticket of specific requestType, but it is nested two levels deep. Tried few possible alterations, but no luck. Here's the code I have,
require 'jira-ruby' # https://github.com/sumoheavy/jira-ruby
options = {
:username => jira_username,
:password => jira_password,
:site => 'https://jiraurl/rest/api/2/',
:context_path => '',
:auth_type => :basic,
:read_timeout => 120
}
client = JIRA::Client.new(options)
issue = client.Issue.build
fields_options = {
"fields" =>
{
"summary" => "Test ticket creation",
"description" => "Ticket created from Ruby",
"project" => {"key" => "AwesomeProject"},
"issuetype" => {"name" => "Task"},
"priority" => {"name" => "P1"},
"customfield_23070" =>
{
"requestType" => {
"name" => "Awesome Request Type"
}
}
}
}
issue.save(fields_options)
"errors"=>{"customfield_23070"=>"Operation value must be a string"}
Also tried passing a JSON object to customfield_23070,
"customfield_23070": { "requestType": { "name": "Awesome Request Type" } }
still no luck, get the same error message.
If it helps, this is how customfield_23070 looks like in our Jira,
Does anyone know how to set requestType in this case, please? Any help is greatly appreciated!!
It seems that for custom fields with specific data types (string/number), you must pass the value as:
"customfield_1111": 1
or:
"customfield_1111": "string"
instead of:
"customfield_1111":{ "value": 1 }
or:
"customfield_1111":{ "value": "string" }
I'm not sure but you can try this possible examples:
eg.1:
"customfield_23070"=>{"name"=>"requestType","value"=>"Awesome Request Type"}
eg.2:
"customfield_23070"=>{"requestType"=>"Awesome Request Type"}
eg.3:
"customfield_23070"=>{"value"=>"Awesome Request Type"}
eg.4
"customfield_23070"=>{"name"=>"Awesome Request Type"}
for ref there are 2 methods depending upon the fields you are interacting with
have a look here '
updating-an-issue-via-the-jira-rest-apis-6848604
' for the applicable fields for update via verb operations, the other fields you can use examples as per above,
you can use both methods within the same call
{
"update": {"description": [{"set": "Description by API Update - lets do this thing"}]},
"fields": {"customfield_23310": "TESTING0909"}
}
Ok, I think I found how to do it.
You need to provide a string, and that string is the GUID of the RequestType.
In order to get that GUID. You need to run the following in a scriptrunner console:
import com.atlassian.jira.component.ComponentAccessor
def issue = ComponentAccessor.issueManager.getIssueByCurrentKey("ISSUE-400546") //Issue with the desired Request Type
def cf = ComponentAccessor.customFieldManager.getCustomFieldObjectByName("Tipo de solicitud del cliente") //Change it to the name of your request type field
issue.getCustomFieldValue(cf)
Source: https://community.atlassian.com/t5/Jira-Software-questions/how-to-set-request-type-value-in-while-create-jira-issue/qaq-p/1106696

Laravel/PHPUnit: Assert json element exists without defining the value

I'm sending a post request in a test case, and I want to assert that a specific element, let's say with key 'x' exists in the response. In this case, I can't say seeJson(['x' => whatever]); because the value is unknown to me. and for sure, I can't do it with seeJson(['x']);.
Is there a way to solve this?
If it matters:
Laravel: v5.2.31
PHPUnit: 5.3.4
May it will be helpful for anyone else. You can write this test for your check response json structure
$this->post('/api/login/', [
'email' => 'customer3#example.com',
'password' => '123123123',
])->assertJsonStructure([
'status',
'result' => [
'id',
'email',
'full_name',
],
]);
Although it's not optimal at all, I chose to use this code to test the situation:
$this->post(URL, PARAMS)->see('x');
X is a hypothetical name, and the actual element key has a slim chance of popping up in the rest of the data. otherwise this nasty workaround wouldn't be practical.
UPDATE:
Here's the solution to do it properly:
public function testCaseName()
{
$this->post(route('route.name'), [
'param1' => 1,
'param2' => 10,
], [
'headers_if_any' => 'value'
]);
$res_array = (array)json_decode($this->response->content());
$this->assertArrayHasKey('x', $res_array);
}

Display table data from RethinkDB in Phoenix Framework

I'm attempting to display data from my databases in RethinkDB (using the rethinkdb-elixir package from Hamiltop https://github.com/hamiltop/rethinkdb-elixir) in Phoenix. I'm relatively new to both, but I already managed to insert two tables and some data into those tables. I know this because I checked it through RethinkDB's web GUI.
Now I want to display table data in an html page of my project.
I've reduced the errors to one:
protocol Phoenix.HTML.Safe not implemented for %RethinkDB.Collection{data: [%{"first_name" => "Carlos", "id" => "4be8adc3-0973-45dc-bdb8-7a4dac6528d5", "last_name" => "Santos"}, %{"first_name" => "Carlos", "id" => "c84658fc-e4a4-4cb6-8107-b011ca996abd", "last_name" => "Santos"}, %{"first_name" => "Carlos", "id" => "c09fe081-379a-4334-97a3-31c5503c8c61", "last_name" => "Santos"}, %{"first_name" => "Carlos", "id" => "cf0c0ad3-3152-40f0-b613-5b051a314b51", "last_name" => "Santos"}, %{"first_name" => "Carlos", "id" => "ca28a714-ed54-4ebd-8707-d53170ead0f7", "last_name" => "Santos"}, %{"first_name" => "Carlos", "id" => "1ea77c0f-538c-4663-be92-499f16996594", "last_name" => "Santos"}, %{"first_name" => "Carlos", "id" => "1ea74846-0860-4ae5-95f5-674860cf7fc6", "last_name" => "Santos"}]}
Clearly it is fetching all the inserted Carlos Santos persons from the table (which I also must prevent but that is not my main issue) but having an error retrieving them to my Phoenix project.
I've got an index page in whose controller I create the tables and data.
Then I added a new page:
router.ex:
get "/users", UsersController, :users
/views/users_view.ex:
defmodule RethinkExample.UsersView do
use RethinkExample.Web, :view
end
users.html.eex:
<div class="jumbotron">
<p><%= #users %>!</p>
</div>
users_controller.ex
defmodule RethinkExample.UsersController do
use RethinkExample.Web, :controller
use RethinkDB.Query
def users(conn, _params) do
q = table("users")
|> filter(%{last_name: "Santos"})
|> RethinkExample.Database.run
|> IO.inspect
render conn, "users.html", users: q
end
end
I deduce that the html code is also incorrect, because this is how I would display the route specific id inside the html tags.
How can I fetch the data successfully and then display it in a html tag?
The problem here is that your data structure in #users is of type %RethinkDB.Collection{} (source) which cannot be output using <%=...%>
You will likely want to iterate over your users to output them. Something like:
<%= for user <- #users.data do %>
<p><%= "#{user["first_name"]} #{user["last_name"]}" %>!</p>
<% end %>
Here we are using a list comprehension to iterate over all the items on the #users.data array. This is a common way to output an array of elements (such as users, blog posts, comments, etc.) in EEx.
You might also want to consider passing q.data though as #users instead of q to prevent having to do #users.data.
As an aside, you can also use pattern matching inside the list comprehension:
<%= for %{"first_name" => first_name, "last_name" => last_name} <- #users.data do %>
<p><%= "#{first_name} #{last_name}" %>!</p>
<% end %>
This is useful if you don't plan on using many of the fields in the map.

How to wrap Datamapper to_json response in a object-key hash

I'm working with a json parser that requires my response to be wrapped in an object-key hash. When I use DataMapper's .to_json method(datamapper/dm-serializer) the repsone I get is correct
get '/plane/all' do
#plane = Plane.all(:order => :id.desc).to_json(:relationships => {:pilots => {}, :passengers => {}, :cabin => {}})
#plane
end
The response in JSON
[{"id":2,"name":"Plane 2","picture_url":"https://s3.amazonaws.com","pilots":[{"pilot_id":2,"header":"Bruce Wayne","details":"Bruce loves his batwing that flies at an average speed of 200 mph","picture_url":"www.marvel.com","plane_id":2}],"passengers":[{"passenger_id":2,"name":"Passenger 2","details":"These are the details for passenger 2","picture_url":"www.toobar.com/","plane_id":2}],"cabin":[{"cabin_id":2,"details":"Great Details for has been put in this cabin","picture_url":"www.seatingchart.com","video_link":"www.skyview.com","passenger_passenger_id":2}]},{"id":1,"name":"Plane 1","picture_url":"https://s3.amazonaws.com","pilots":[{"pilot_id":1,"header":"Jack Smith","details":"Jack Smith description","picture_url":"https://www.foobar.com","plane_id":1}],"passengers":[{"passenger_id":1,"name":"Passenger 1","details":"Passenger 1 details","picture_url":"www.toobar.com/","passenger_id":1}],"cabin":[{"cabin_id":1,"details":"Flight details","picture_url":"www.seatingchart.com","video_link":"www.skyview.com","passenger_passenger_id":1}]}]
To wrap this response as a key I used the 'json' gem which has it's own to_json method
get '/plane/all' do
#plane = Plane.all(:order => :id.desc).to_json(:relationships => {:pilots => {}, :passengers => {}, :cabin => {}})
{ "planes" => #plane }.to_json
end
Here is the response
{"planes":"[{\"id\":2,\"name\":\"Plane 2\",\"picture_url\":\"https://s3.amazonaws.com\",\"pilots\":[{\"pilot_id\":2,\"header\":\"Bruce Wayne\",\"details\":\"Bruce loves his batwing that flies at an average speed of 200 mph\",\"picture_url\":\"www.marvel.com\",\"plane_id\":2}],\"passengers\":[{\"passenger_id\":2,\"name\":\"Passenger 2\",\"details\":\"These are the details for passenger 2\",\"picture_url\":\"www.toobar.com/\",\"plane_id\":2}],\"cabin\":[{\"cabin_id\":2,\"details\":\"Great Details for has been put in this cabin\",\"picture_url\":\"www.seatingchart.com\",\"video_link\":\"www.skyview.com\",\"passenger_passenger_id\":2}]},{\"id\":1,\"name\":\"Plane 1\",\"picture_url\":\"https://s3.amazonaws.com\",\"pilots\":[{\"pilot_id\":1,\"header\":\"Jack Smith\",\"details\":\"Jack Smith description\",\"picture_url\":\"https://www.foobar.com\",\"plane_id\":1}],\"passengers\":[{\"passenger_id\":1,\"name\":\"Passenger 1\",\"details\":\"Passenger 1 details\",\"picture_url\":\"www.toobar.com/\",\"plane_id\":1}],\"cabin\":[{\"cabin_id\":1,\"details\":\"Flight details\",\"picture_url\":\"www.seatingchart.com\",\"video_link\":\"www.skyview.com\",\"passenger_passenger_id\":1}]}]"}
Long story short, the JSON response I get has backslashes in it and JSON parser I'm using states it's only one object instead of the two I had previously.
Anyone who can help me out, it would be greatly appreciated.
Here is my workaround. If there is no view, then no need to use an instance variable.
def '/plane/all' do
planes = Plane.all(:order => :id.desc).to_json(:relationships => {:pilots => {}, :passengers => {}, :cabin => {}})
{ "planes" => JSON.parse(planes) }.to_json
end