Import json data into redis - ruby

i'm new to redis and ruby i'm using the following code
response = HTTParty.get('posts.json')
json = JSON(response.body)
json.each do |item|
puts item
puts json[item]
puts item['content']
redis.hset 'latest_posts', item, item['title']
end
puts json[item]
returns the following error no implicit conversion of Hash into Integer
inside each loop i want to output the keys for example id, title, content with puts item (now returns the whole object) and with json[item] data in keys any help? if i try for example
%w{id title content}.each do |key|
puts key
puts json[key]
end
again no implicit conversion of String into Integer

From your code it seems that you expect an array of hashes in your JSON.
I see two problems here:
1.
puts json[item]
puts item['content']
an item is a hash. json[item] makes no sense to me.
2.
redis.hset 'latest_posts', item, item['title']
is supposed to set a key item in the Redis hash 'latest_posts' to the value item['title']. But item is a hash, and, I think, Redis expects a string as the filed name.
BTW, is not it JSON.parse response.body?

Related

Fetching values based on keys from hash

I am using roo gem for reading an xlsx file.
sheet.each(identifier: 'identifier',name: 'name') do |hash|
puts hash.inspect
puts hash['identifier'] => prints empty
end
inspect correctly gives all the hash with all the key/ value pairs
{:identifier=>"3254",:name=>"Ins"}.....so on
I need to fetch the value based on key at every loop. Did something like this puts hash['identifier'] which does not print anything.
How to achieve this.

In Ruby, group_by where I know there's only 1 element per group

I have a CSV file where one column is a primary key. When I do this:
CSV.read(ARGV[0], headers: true).group_by {|r| r['myKey']}
I get a hash table from key to a list of rows, where the list is always length 1.
Is there a version of group_by which asserts that there's only a single value per key, and creates a hash from key to that single value?
Failing that, is there something like .first which asserts that there's exactly one element in the array/enumerable? I like my scripts to fail when my assumptions are wrong, rather than silently return the wrong thing.
If you use Rails you can use index_by method.
If you know the values r['myKey'] are unique, there's no point in using group_by. As I understand the question, you could do this:
rows = CSV.read(ARGV[0], headers: true)
Hash[rows.map { |r| r['myKey'] }.zip(rows)]
In Ruby 2.0+ the second row could be written:
rows.map { |r| r['myKey'] }.zip(rows).to_h
No. I don't believe there is. But you can solve your problem with each_with_object like so:
CSV.
read(ARGV[0], headers: true).
each_with_object({}) do |r, hash|
key = r['myKey']
value = r
hash[key] = value
end
It's a shame Ruby doesn't have this. Here's what I decided to go on, based on Humza's answer:
module Enumerable
def group_by_uniq
each_with_object({}) do |value, hash|
key = yield value
raise "Multiple values for key \"{key}\"!" unless ! hash.key?(key)
hash[key] = value
end
end
end
If you use your code in you first example you can run this code to check that all hashes are of length 1:
raise 'multiple entries per key!' unless my_hash.values.any?{|val| val.size!=1}
IF you can get the keys into an array you can check that they do not iclude duplicates by:
raise 'multiple entries per key!' unless my_keys.uniq.size == my_keys.size

Convenient way of obtaining the specific object being used for a key in a hash in Ruby?

Here's an interesting one, I have a scenario in a bucket sharding system I'm writing where I maintain index hashes and storage hashes, the interrelation is a UUID generated because this is distributed and I want some confidence that new buckets gain unique references.
Early on in this exercise I started optimising the code to freeze all keys generated by SecureRandom.uuid (it produces strings) because when you use a string as a key in a hash gets duped and frozen automatically to ensure that it can't be changed. (if it's a String and not frozen).
In most cases it's easy to aggressively do this, particularly for new UUIDs (actually in my project many such values need this treatment) but in some cases I find I'm having to approach a hash with a value passed over the network and obtain then, to ensure consistent use of any strings present as keys, use a rather obtuse lookup mechanism.
My goal in this, since I want this to maintain a huge data set across multiple nodes, to reduce the overhead of key and index storage as much as possible and because it's a bucketing system the same UUID can be referenced many times and as such it's helpful to use the same reference.
Here's some code that demonstrates the issue in a simpl(ish) form. I'm just asking if there's a more optimum and convenient mechanism for obtaining any pre-existing object reference for a key that has the same string value (for the key name and not the value associated).
# Demonstrate the issue..
require 'securerandom'
index = Hash.new
store = Hash.new
key = 'meh'
value = 1
uuid = SecureRandom.uuid
puts "Ruby dups and freezes strings if used for keys in hashes"
puts "This produces different IDs"
store[uuid] = value
index[key] = uuid
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"}
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" }
puts
puts "If inconsistencies in ID occur then Ruby attempts to preserve the use of the frozen key so if it happens in one area take care"
puts "This produces different IDs"
uuid = uuid.freeze
store[uuid] = value
index[key] = uuid
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"}
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" }
puts
puts "If you start with a clean slate and a frozen key you can overcome it if you freeze the string before use"
puts "This is clean so far and produces the same object"
index = Hash.new
store = Hash.new
store[uuid] = value
index[key] = uuid
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"}
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" }
puts
puts "But if the same value for the key comes in (possibly remote) then it becomes awkward"
puts "This produces different IDs"
uuid = uuid.dup.freeze
store[uuid] = value
index[key] = uuid
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"}
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" }
puts
puts "So you get into oddities like this to ensure you standarise values put in to keys that already exist"
puts "This cleans up and produces same IDs but is a little awkward"
uuid = uuid.dup.freeze
uuid_list = store.keys
uuid = uuid_list[uuid_list.index(uuid)] if uuid_list.include?(uuid)
store[uuid] = value
index[key] = uuid
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"}
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" }
puts
Example run...
Ruby dups and freezes strings if used for keys in hashes
This produces different IDs
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325780
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880
If inconsistencies in ID occur then Ruby attempts to preserve the use of the frozen key so if it happens in one area take care
This produces different IDs
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325780
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880
If you start with a clean slate and a frozen key you can overcome it if you freeze the string before use
This is clean so far and produces the same object
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880
But if the same value for the key comes in (possibly remote) then it becomes awkward
This produces different IDs
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325000
So you get into oddities like this to ensure you standarise values put in to keys that already exist
This cleans up and produces same IDs but is a little awkward
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880
It seems, for a pure Ruby example, this can be avoided entirely due to the global nature of symbol object references. It's enough to convert strings to symbols to ensure the same reference. It's not what I was hoping for since I use Ruby to prototype for C developers sometimes but it works reliably and is suitable to help my prototype progress with a lot of additional comment for C development stage.
I would still be interested in other examples but here's a big thumbsup for Symbols although I tend to avoid them in many network cases because they marshal to String through JSON (and I like JSON since peers written in different languages can usually support it).
imac:Ruby andrews$ irb
irb(main):001:0> a = :meh
=> :meh
irb(main):002:0> b = 'meh'.to_sym
=> :meh
irb(main):003:0> a.object_id == b.object_id
=> true
Additional backup here on this approach Why use symbols as hash keys in Ruby?
In addition, need to remember that symbols, once named, aren't garbage collected.
Maybe you are looking for Enumerable#find
uuid = store.find{|k,_| k == uuid_from_network }.first
Full example:
require 'securerandom'
index = Hash.new
store = Hash.new
key = 'meh'
value = 1
uuid = SecureRandom.uuid
store[uuid] = value
index[key] = uuid
# obtained from elsewhere
uuid = uuid.dup.freeze
uuid = store.find{|k,_| k == uuid }.first
store[uuid] = value
index[key] = uuid
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"}
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" }
Output:
Store reference for value of d94390c4-7cc7-4e94-92bc-a0dd862ac6a2 70190385847520
Index reference for d94390c4-7cc7-4e94-92bc-a0dd862ac6a2 70190385847520
If you want to go crazy efficient, you can build a lightweight wrapper around the C function st_get_key, which does exactly what you want. I took the implementation of Hash#has_key? as boilerplate. You can mix C code into Ruby code for example with RubyInline.
require 'inline'
class Hash
inline do |builder|
builder.c <<-EOS
VALUE fetch_key(VALUE key) {
st_data_t result;
if (!RHASH(self)->ntbl)
return Qnil;
if (st_get_key(RHASH(self)->ntbl, key, &result)) {
return result;
}
return Qnil;
}
EOS
end
end
I couldn't find anything native in the Hash source and Symbols were unsuitable for my purposes so I adapted the answer from #p11y, thanks ^^
class Hash
def consistent_key_obj(key)
self.keys.include?(key) ? self.find{|k,_| k == key }.first : key
end
end

Ruby thinks element of hash is Integer

I have a function in Ruby:
def find_item(keyword)
potential = []
$items.each do |item|
puts item # <-- for debugging purposes
if item["name"].downcase== keyword
potential << item["name"].downcase
elsif item["keywords"].index(keyword) != nil
potential << item["name"].downcase
end
end
return potential
end
(The global variable $items is a Hash object that maps a few strings to some values that determine the properties of the item.)
When I puts the current item it is iterating over (the line with the comment does just that), it gives me:
{"name"=>"Thing1", "keywords"=>["thing", "green"], ...}
but when I try item["name"] on the next line (which should definitely return Thing1), it gives me:
C:/somepath/someprogram.rb:125:in '[]': can't convert String into Integer (TypeError)
if $items is a Hash, then $items.each do |item| will yield [key, value] pairs (Arrays) to the block. If you only want the values, use each_value.

How does one populate an array in Ruby?

Here is the code I'm working with:
class Trader
def initialize(ticker ="GLD")
#ticker = ticker
end
def yahoo_data(days=12)
require 'yahoofinance'
YahooFinance::get_historical_quotes_days( #ticker, days ) do |row|
puts "#{row.join(',')}" # this is where a solution is required
end
end
end
The yahoo_data method gets data from Yahoo Finance and puts the price history on the console. But instead of a simple puts that evaporates into the ether, how would you use the preceding code to populate an array that can be later manipulated as object.
Something along the lines of :
do |row| populate_an_array_method(row.join(',') end
If you don't give a block to get_historical_quotes_days, you'll get an array back. You can then use map on that to get an array of the results of join.
In general since ruby 1.8.7 most iterator methods will return an enumerable when they're called without a block. So if foo.bar {|x| puts x} would print the values 1,2,3 then enum = foo.bar will return an enumerable containing the values 1,2,3. And if you do arr = foo.bar.to_a, you'll get the array [1,2,3].
If have an iterator method, which does not do this (from some library perhaps, which does not adhere to this convention), you can use foo.enum_for(:bar) to get an enumerable which contains all the values yielded by bar.
So hypothetically, if get_historical_quotes_days did not already return an array, you could use YahooFinance.enum_for(:get_historical_quotes_days).map {|row| row.join(",") } to get what you want.

Resources