Iterating through JSON array for a List in Dashing - ruby

I'm trying to create a List in Dashing and I've managed to bring in my external JSON, but I'm having problems iterating through it to create the new JSON array to post it out to my List widget. Here's the current code:
require 'rubygems'
require 'json'
require 'pp'
name_list = Hash.new({ value: 0 })
SCHEDULER.every '10s' do
json = File.read('/Users/research/inoutdash/sweet_dashboard_project/jobs/list.json')
response = JSON.parse(json)
name_list[response] = {label: response.keys, value: response.values}
send_event('whosHere', { items: name_list.values })
puts response.keys
puts response.values
end
Here's my JSON file it's reading from:
{
"Mike":"Here",
"Jon": "Out"
}
The output to the widget currently looks like this:
MikeJon Here,Out
How to I properly iterate through the parsed json response and pass it to the send_event?
Just in reply to Matt's question:
So what I need is one 'whosHere' event with all the values from the JSON file formatted for the List widget - which needs JSON formatted as label: X, value: Y.
So what I need it to do is format it as a json array with:
label: "Mike", value: "Here"
label: "Jon", value: "Out"
where now it's storing as:
label: Mike,Jon, value:Here,out

You can use collect to accomplish this. It iterates over a collection and returns an Array where each element is the result of a block.
name_list = response.collect { |(name, status)| { :label => name, :value => status } }
# [{:label=>"Mike", :value=>"Here"}, {:label=>"Jon", :value=>"Out"}]

Related

Read a value from a JSON key when the key is unknown/random

My JSON response looks like this:
{
"item": {
"-LVShDSBr5tvs0wGkc0JJ": {
"text": "H"
}
},
"item": {
"-LEVSZndgiqwhgnytO3Kr": {
"text": "Hatem"
}
}
}
I can read each item object, but I need to reach the text value. To do that, I need to get through the random ID that's one level above that. How do I read what's within that key?
I have this:
items.each do |item|
# gets one item successfully
# but im unable to read the key within since it's unknown
text = item[:unknown_key][:text]
end
Use Hash#values:
texts =
items.map do |item|
item.values.first[:text]
end
If you expect more than one item, play around with mapping values to their [:text]s.

how can I iterate through this json document using ruby?

I have a ruby code block, as follows:
require "elasticsearch"
require "json"
search_term = "big data"
city = "Hong Kong"
client = Elasticsearch::Client.new log: true
r = client.search index: 'candidates', body:
{
query: {
bool: {
must: [
{
match: {
tags: search_term
}
},
{
match: {
city: city
}
}
]
}
}
}
It produces multiple returns like this one:
{"_index":"candidates","_type":"data",
"_id":"AU3DyAmvtewNSFHuYn88",
"_score":3.889237,
"_source":{"first":"Kota","last":"Okayama","city":"Tokyo","designation":"Systems Engineer","email":"user#hotmail.co.jp","phone":"phone","country":"Japan","industry":"Technology","tags":["remarks","virtualization big data"]}}
I want to iterate through it and extract various elements. I have tried
data = JSON.parse(r)
data.each do |row|
puts row["_source"]["first"]
end
and the error is:
no implicit conversion of Hash into String (TypeError)
What's the best way forward on this chaps?
I have the solution, I hope it helps somebody else. It took me hours of fiddling and experimentation. Here it is:
require "elasticsearch"
require "json"
search_term = "big data"
city = "Tokyo"
client = Elasticsearch::Client.new log: true
h = client.search index: 'swiss_candidates', body:
{
query: {
bool: {
must: [
{
match: {
tags: search_term
}
},
{
match: {
city: city
}
}
]
}
}
}
data = JSON.parse(h.to_json)
data["hits"]["hits"].each do |r|
puts r["_id"]
puts r["_source"]["first"]
puts r["_source"]["tags"][1]
puts r["_source"]["screened"][0]
end
The important thing seems to be to convert the elasticsearch result into something ruby friendly.
JSON.parse expects a String containing a JSON document, but you are passing it the Hash which was returned from client.search.
I'm not entirely sure what you are trying to achieve with that, why you want to parse something which is already a Ruby Hash into a Ruby Hash.

Seeding a Dashing list from an External JSON file

I'm new to Dashing (and relatively new to Ruby) so I apologize in advance if this is a dumb question. Basically I'm trying to get Dashing to read a json file that I update every 10 seconds. But I can't seem to get my job to read the file or post it out to my List widget.
Here's my job code:
require 'rubygems'
require 'json'
require 'pp'
name_list = Hash.new(0)
SCHEDULER.every '10s' do
json = File.read('list.json')
response = JSON.parse(json)
name_list[people] = {label: response.keys, value: response.keys[]}
send_event('whosHere', { items: response.values })
end
and my JSON:
{
"Mike": "Here",
"Jon": "Out",
}
And in case you need it my dashboard code:
<% content_for(:title) { "My super sweet dashboard" } %>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
<div data-id="whosHere" data-view="List" data-title="Who's Home" style="background-color:#96bf48;"></div>
</li>
</ul>
</div>
I see two issues:
1) You're sending the wrong object:
response = JSON.parse(json)
name_list[people] = {label: response.keys, value: response.keys[]}
send_event('whosHere', { items: response.values })
name_list[people] is your assumed result from processing your JSON, but you're sending response.values instead.
response is your parsed-JSON object returned. You must iterate over response to build an array of JSON objects to send to your List:
# new empty array of persons each time job is run
persons = []
# since your JSON file is single JSON object, using names for keys
person_names = response.keys
# for each name, do this
person_names.each do |name|
# use the 'name' key to get the value (their status)
person_status = response[name]
# create new Hash/JSON object for each person
# use "label" and "value" keys for Dashing List widget
person = Hash.new("label",name,"value",person_status)
# add this new person object to your persons array
persons.push(person)
end
Updated Job, which sends the persons array to Dashing instead:
require 'rubygems'
require 'json'
require 'pp'
name_list = Hash.new(0)
SCHEDULER.every '10s' do
json = File.read('list.json')
response = JSON.parse(json)
persons = []
person_names = response.keys
person_names.each do |name|
person_status = response[name]
person = Hash.new("label", name, "value", person_status)
persons.push(person)
end
send_event('whosHere', { items: persons })
end
2) Your JSON isn't formatted properly. Dashing's List widget is listening for an array of objects with "label" and "value" keys. Each person would be an individual JSON object, the person's name would be your "label" value, and their status would be their "value" value.
Here is the list-item HTML from the List widget:
<li data-foreach-item="items">
<span class="label" data-bind="item.label"></span>
<span class="value" data-bind="item.value"></span>
</li>
Each list item will display a single JSON object:
{
"label":"Mike",
"value":"Here"
}
So to display Mike and Jon's statuses in your list, you will need an array containing two JSON objects:
[
{
"label": "Mike",
"value": "Here"
},
{
"label": "Jon",
"value": "Out"
}
]
This array will be the "value" for your "items" key in your data object being sent to your List widget:
{
"items": [
{
"label": "Mike",
"value": "Here"
},
{
"label": "Jon",
"value": "Out"
}
]
}

How to add new key/value pair to existing JSON object in Ruby

How could I append a new key/value pair to an existing JSON object in Ruby?
My output is:
{
"2d967df3-ee07-4e40-8f65-7bbff59bbb7e": {
"name": "Book1",
"author": "Author1"
}
}
I want to achieve something like this when I add a new key/value pair:
{
"2d967df3-ee07-4e40-8f65-7bbff59bbb7e": {
"name": "Book1",
"author": "Author1"
},
"c55a3632-9bed-4a41-ae40-c1abfe0f332a": {
"name": "Book2",
"author": "Author2"
}
}
This is my method to write to a JSON file:
def create_book(name, author)
tempHash = {
SecureRandom.uuid => {
"name" => name,
"author" => author
}
}
File.open("./books/book.json","w") do |f|
f.write(JSON.pretty_generate(tempHash))
end
end
To clarify, I need to add a second entry to the original file. I tried using append (<<), and that's where my code fails:
file = File.read("./books/book.json")
data_hash = JSON.parse(file)
newJson = data_hash << tempHash
How could I append a new key/value pair to existing JSON object in Ruby?
If you want to add it to an existing file then you should read the JSON first, extract data from it, then add a new hash to an array.
Maybe something like this will solve your problem:
def create_book(name, author)
tempHash = {
SecureRandom.uuid => {
"name" => name,
"author" => author
}
}
data_from_json = JSON[File.read("./books/book.json")]
data_from_json = [data_from_json] if data_from_json.class != Array
File.open("./books/book.json","w") do |f|
f.write(JSON.pretty_generate(data_from_json << tempHash))
end
end
There are also some other ways like manipulating the JSON as a common string but for safety you should extract the data and then create a new JSON file.
If you need the new key/value pair to be in the same JSON element as the previous data, instead of shoveling (<<) the hashes together, merge them.
Additionally this can allow you to put the new key/value pair in the start of the element or in the end, by flipping which hash you merge first.
So, take Maxim's solution from Apr 14 '15, but modify to merge the two hashes together.
data_from_json = JSON[http://File.read("./books/book.json")]
File.open("./books/book.json","w") do |f|
f.write(JSON.pretty_generate([data_from_json.merge(tempHash)])
end

Ruby SQL Server and Do blocks

I have the following code:
sql = "select Board_Name AS 'Board Name', COUNT(Board_Name) AS 'Count' from dbo.TABLE GROUP BY Board_Name"
result = client.execute(sql)
result.each do |row|
binfo = [ label: row['Board Name'], value: row['Count'] ]
send_event('ticketsbyboard', { items: binfo })
end
I'm trying to get all of the rows passed to the send_event as one array, instead of just one row at a time.
Try a map:
binfo = result.map do |row|
{ label: row['Board Name'], value: row['Count'] }
end
send_event('ticketsbyboard', { items: binfo })
If your result object doesn't respond directly to map, just use result.to_a.map

Resources