I'm having an issue like this. Not all zones are returning with:
ActiveSupport::TimeZone.all.sort_by {|t| t.name}.map { |tz|
#symbol = tz.tzinfo.identifier.gsub(/[^_a-zA-Z0-9]/, '_').squeeze('_').upcase!
tz.to_s #> (GMT+00:00) Edinburgh for example
}
I need to use the .to_s to get the UTC (GMT+00:00). With the above, London is missing and I assume others. This one works great:
ActiveSupport::TimeZone::MAPPING.sort_by {|k,v| k}.map { |k,v|
#symbol = k.gsub(/[^_a-zA-Z0-9]/, '_').squeeze('_').upcase!
k #> London London is included with this method
}
I cannot use this method because I do not know how to get the (GMT+00:00) in (GMT+00:00) London
Has the bug return? How to get all the zones show for the first example?
Edit.
I'm using GraphQL-ruby. I've created an enum to return a list of time zones:
# Taken from: https://gist.github.com/pedrocarmona/f41d25e631c1144045971c319f1c9e17
class Types::TimeZoneEnumType < Types::BaseEnum
ActiveSupport::TimeZone.all.sort_by {|t| t.name}.map { |tz|
symbol = tz.tzinfo.identifier.gsub(/[^_a-zA-Z0-9]/, '_').squeeze('_').upcase
value("TZ_#{symbol}", tz.to_s)
}
end
Then inside query_type.rb
[..]
field :time_zones, Types::TimeZoneEnumType, null: false
[..]
Next, inside graphiql, I make the query:
query timeZones{
__type(name: "TimeZoneEnum") {
enumValues {
name
description
}
}
}
Which returns something like, except London:
[
[..]
{
"name": "TZ_AMERICA_LA_PAZ",
"description": "(GMT-04:00) La Paz"
},
{
"name": "TZ_AMERICA_LIMA",
"description": "(GMT-05:00) Lima"
},
{
"name": "TZ_EUROPE_LISBON",
"description": "(GMT+00:00) Lisbon"
},
{
"name": "TZ_EUROPE_LJUBLJANA",
"description": "(GMT+01:00) Ljubljana"
},
{
"name": "TZ_EUROPE_MADRID",
"description": "(GMT+01:00) Madrid"
},
[..]
]
After Ljubljana I should see "London" but it's not there.
If I run
ActiveSupport::TimeZone.all.sort_by {|t| t.name}.map { |tz|
[ tz.tzinfo.identifier.gsub(/[^_a-zA-Z0-9]/, '_').squeeze('_').upcase, tz.to_s ]
}.sort
the result includes the entries ["EUROPE_LONDON", "(GMT+00:00) Edinburgh"], ["EUROPE_LONDON", "(GMT+00:00) London"], i.e. EUROPE_LONDON is duplicated.
I don't know how the GraphQL library is operating, but I'm assuming it's deduplicating the data and returning a single entry for EUROPE_LONDON (enums are normally unique). Moscow is the same - it has values for Moscow and St Petersburg - so you could test by looking at the results for EUROPE_MOSCOW.
Related
Please tell me, if there are any errors here and how to make the code more clean.
There is a space "company". Inside it's a string "type" and "information" map. Inside this map is a "job" object and an array of "users" objects. The "users" array consists of 2 objects. Each object has 4 fields.
I need to add a new field:
status = "UPDATED"
inside each object in the "users" array, under a certain condition
"company": {
"type" : "01",
"information":
{
"job":
{
"job_name": "N",
"job_address": 1670392687114,
"job_salary": 1234567890123,
"contacts": 0
},
"users":
[
{
"id": 1,
"name": "Alex",
"rate": 4,
"address": "bla bla bla"
},
{
"id": 2,
"name": "Jenifer",
"rate": 5,
"address": "bla bla bla"
}
]
}
}
My logic is next:
if tuple.type == "01" or tuple.type == "02" or tuple.type == "03" or tuple.type == "04" then
for _, attr in pairs(users) do
attr.status = "UPDATED"
end
end
Is it correct to add a new status="UPDATED" field to each object in the array "users" here?
Does this entry exist?
And yet, tell me please, can I somehow make the condition in if more beautiful? For example analog in Java list.contains()
Updated:
The final version after adding new field "status" should look like this (see image)
Is it correct to add a new status="UPDATED" field to each object in
the array "users" here? Does this entry exist?
If you want the table to have a status field with value "UPDATED" then attr.status = "UPDATED"is correct.
This only makes sense if you'll add more non-updated users to that table later though as you're updating the entire list. you could as well just mark the users table object as updated.
And yet, tell me please, can I somehow make the condition in if more
beautiful? For example analog in Java list.contains()
No but you could write your own function.
function table.contains(tbl, value)
for _, v in pairs(tbl) do
if (v == value) then return true end
end
return false
end
if table.contains({"01", "02", "03", "04"}, tuple.type) then
for _, attr in pairs(users) do
attr.status = "UPDATED"
end
end
Alternatively you could use a lookup table
local isUpdateType = {
["01"] = true,
["02"] = true,
["03"] = true,
["04"] = true,
}
and later
if isUpdateType[tuple.type] then end
How to solve this depends very much on what you consider "beautiful" here.
Above are two different records from a Posts model we have stored in elasticsearch. We're trying to put in logic that will put our sticky posts in the feed like regular posts after they've expired.
We want to have it say
"If is_sticky AND stickied_until is in the future sort by stickied_until, else sort by created_at"
I think I have it working in SQL (since we store the bulk of the data there and only the searchable fields in ES), which looks like
ORDER BY
CASE
WHEN stickied_until >= '#{DateTime.now.utc}'
THEN stickied_until
ELSE created_at
END DESC
but then there's two things controlling the sort, which I'm pretty sure will cause bugs, and also just feels wrong.
Is it possible to do this kind of conditional sorting in ES?
You'll have to use a sort script for this.
{
"sort": [
{
"_script": {
"type": "number",
"script": {
"lang": "painless",
"source": """
def is_sticky = doc['is_sticky'].value;
def created_at = doc['created_at'].value.getMillis();
if (!is_sticky) {
return created_at;
}
def stickied_until = doc['stickied_until'].value.getMillis();
def now = params['now'];
if (is_sticky && stickied_until > now) {
return stickied_until;
}
return created_at;
""",
"params": {
"now": 1586798403888
}
},
"order": "desc"
}
}
]
}
Note that I've used query-time constant params['now'] due to reasons explained in the docs.
I have a third party JSON feed which is huge - lots of data. Eg
{
"data": [{
"name": "ABC",
"price": "2.50"
},
...
]
}
I am required to strip the quotation marks from the price as the consumer of the JSON feed requires it in this way.
To do this I am performing a regex to find the prices and then iterating over the prices and doing a string replace using gsub. This is how I am doing it:
price_strings = json.scan(/(?:"price":")(.*?)(?:")/).uniq
price_strings.each do |price|
json.gsub!("\"#{price.reduce}\"", price.reduce)
end
json
The main bottle neck appears to be on the each block. Is there a better way of doing this?
If this JSON string is going to be serialised into a Hash at some point in your application or in another 3rd-party dependency of your code (i.e. to be consumed by your colleagues or modules), I suggest negotiating with them to convert the price value from String to Numeric on demand when the json is already a Hash, as this is more efficient, and allows them to...
...handle edge-case where say if "price": "" of which my code below will not work, as it would remove the "", and will be a JSON syntax error.
However, if you do not have control over this, or are doing once-off mutation for the whole json data, then can you try below?
json =
<<-eos
{
"data": [{
"name": "ABC",
"price": "2.50",
"somethingsomething": {
"data": [{
"name": "DEF",
"price": "3.25", "someprop1": "hello",
"someprop2": "world"
}]
},
"somethinggggg": {
"price": "123.45" },
"something2222": {
"price": 9.876, "heeeello": "world"
}
}]
}
eos
new_json = json.gsub /("price":.*?)"(.*?)"(.*?,|})/, '\1\2\3'
puts new_json
# =>
# {
# "data": [{
# "name": "ABC",
# "price": 2.50,
# "somethingsomething": {
# "data": [{
# "name": "DEF",
# "price": 3.25, "someprop1": "hello",
# "someprop2": "world"
# }]
# },
# "somethinggggg": {
# "price": 123.45 },
# "something2222": {
# "price": 9.876, "heeeello": "world"
# }
# }]
# }
DISCLAIMER: I am not a Regexp expert.
This is truly a fools errand.
JSON.parse('{ "price": 2.50 }')
> {price: 2.5}
As you can see from this javascript example the parser on the consuming side will truncate the float to whatever it wants.
Use a string if you want to provide a formatted number or leave formatting up to the client.
In fact using floats to represent money is widely known as a really bad idea since floats and doubles cannot accurately represent the base 10 multiples that we use for money. JSON only has a single number type that represents both floats and integers.
If the client is going to do any kind of calculations with the value you should use an integer in the lowest monetary denomation (cents for euros and dollars) or a string that's interpreted as a BigDecimal equivilent type by the consumer.
I'm working with sabre api ( test licence ) in my rails application,
i get a JSON response and when I parse it a get this hash
{
"OriginLocation"=>"DEN",
"Destinations"=>[
{
"Rank"=>1,
"Destination"=>{
"DestinationLocation"=>"LAX",
"AirportName"=>"Los Angeles International Airport",
"CityName"=>"Los Angeles",
"CountryCode"=>"US",
"CountryName"=>"United States",
"RegionName"=>"North America",
"Type"=>"Airport"
}
},
{
"Rank"=>2,
"Destination"=>{
"DestinationLocation"=>"LAS",
"AirportName"=>"McCarran International Airport",
"CityName"=>"Las Vegas",
"CountryCode"=>"US",
"CountryName"=>"United States",
"RegionName"=>"North America",
"Type"=>"Airport"
}
},
{
"Rank"=>3,
"Destination"=>{
"DestinationLocation"=>"CHI",
"CountryCode"=>"US",
"CountryName"=>"United States",
"RegionName"=>"North America",
"MetropolitanAreaName"=>"Chicago",
"Links"=>[
{
"rel"=>"airportsInCity",
"href"=>"https://api.test.sabre.com/v1/lists/supported/cities/CHI/airports"
}
],
"Type"=>"City"
}
}
...
}
How can i extract the data (ex: destination) information from it?
I tried this code but i get an error " undefined method ``each' for nil:NilClass "
#hash['Destinations'].each do |key, value|
puts key
value.each do |k,v|
puts k
puts v
end
end
Even though you've specified key and value, only key is populated (with the entire hash data), and value is nil. That's why you're getting an error.
Assuming you're on Ruby 2.3 or above, I suggest you use something like this instead:
#hash['Destinations'].map { |d| d.dig('Destination', 'CityName') }
#=> ["Los Angeles", "Las Vegas", nil]
You can read up more on dig here. It's useful for this kind of deeply nested data, and will protect you from keys that don't exist (and return nil instead); as long as you don't mix its usage on arrays and hashes.
I'm using a Ruby script to interface with an application API and the results being returned are in a JSON format. For example:
{
"incidents": [
{
"number": 1,
"status": "open",
"key": "abc123"
}
{
"number": 2,
"status": "open",
"key": "xyz098"
}
{
"number": 3,
"status": "closed",
"key": "lmn456"
}
]
}
I'm looking to search each block for a particular "key" value (yzx098 in this example) and return the associated "number" value.
Now, I'm very new to Ruby and I'm not sure if there's already a function to help accomplish this. However, a couple days of scouring the Googles and Ruby resource books hasn't yielded anything that works.
Any suggestions?
First of all, the JSON should be as below: (note the commas)
{
"incidents": [
{
"number": 1,
"status": "open",
"key": "abc123"
},
{
"number": 2,
"status": "open",
"key": "xyz098"
},
{
"number": 3,
"status": "closed",
"key": "lmn456"
}
]
}
Strore the above json in a variable
s = '{"incidents": [{"number": 1,"status": "open","key": "abc123"},{"number": 2,"status": "open","key": "xyz098"},{"number": 3,"status": "closed","key": "lmn456"}]}'
Parse the JSON
h = JSON.parse(s)
Find the required number using map
h["incidents"].map {|h1| h1['number'] if h1['key']=='xyz098'}.compact.first
Or you could also use find as below
h["incidents"].find {|h1| h1['key']=='xyz098'}['number']
Or you could also use select as below
h["incidents"].select {|h1| h1['key']=='xyz098'}.first['number']
Do as below
# to get numbers from `'key'`.
json_hash["incidents"].map { |h| h['key'][/\d+/].to_i }
json_hash["incidents"] - will give you the value of the key "incidents", which is nothing but an array of hash.
map to iterate thorough each hash and collect the value of 'key'. Then applying Hash#[] to each inner hash of the array, to get the value of "key". Then calling str[regexp], to get only the number strings like '098' from "xyz098", finally applying to_i to get the actual integer from it.
If the given hash actually a json string, then first parse it using JSON::parse to convert it to a hash.Then do iterate as I said above.
require 'json'
json_hash = JSON.parse(json_string)
# to get values from the key `"number"`.
json_hash["incidents"].map { |h| h['number'] } # => [1, 2, 3]
# to search and get all the numbers for a particular key match and take the first
json_hash["incidents"].select { |h| h['key'] == 'abc123' }.first['number'] # => 1
# or to search and get only the first number for a particular key match
json_hash["incidents"].find { |h| h['key'] == 'abc123' }['number'] # => 1