ruby Datamapper is not inserting all records - ruby

I have this ruby function which yields 1095 records MusicTab::FOps.gen_list('/fun/Music')
and I want to store them using datamapper. When I do this
MusicTab::FOps.gen_list('/fun/Music') do |arr_f|
#files=Files.create(
:file_path => arr_f[0],
:title => arr_f[1],
:album => arr_f[2],
:artist => arr_f[3] )
end
only 154 records are inserted, I don't understand what is so special about these records.
If I do this I get nil for p #files.id all the other records other than those 154 records which gets stored.
MusicTab::FOps.gen_list('/fun/Music') do |arr_f|
#files=Files.create(
:file_path => arr_f[0],
:title => arr_f[1],
:album => arr_f[2],
:artist => arr_f[3] )
p #files.id
p #files.title
p #files.album
end
If I just print the values I can see all the values like
counter=0
MusicTab::FOps.gen_list('/fun/Music') do |arr_f|
p arr_f
counter=counter+1
end
counter
please help..
Regards

try looking at #files.errors. My guess is that you are failing a validation and it isn't getting saved.
You can try enabling some Debug logging and see if that helps to isolate the problem.
DataMapper::Logger.new($stdout, :debug)
It would be helpful to see your Model Definition for the Files object, and a sample of the data that doesn't get saved, and one that does. The last time I ran into this issue was when I needed to set the size on my text fields as I was overflowing the default.

Related

How to parse a Hash of Hashes from a CSV file

I have a CSV file that I need to read and extract all rows which have a "created_at" within a certain range. The CSV itself is about 5000 lines in Excel.
This is how I am pulling the info from the file:
CSV.foreach("sample_data.csv", :headers => true, :header_converters => :symbol, :converters => :all) do |row|
data[row.fields[0]] = Hash[row.headers[1..-1].zip(row.fields[1..-1])]
end
Here's the last Hash created after using CSV.foreach:
2760=>{:created_at=>1483189568, :readable_date=>"12/31/2016", :first_name=>"Louise", :last_name=>"Garza", :email=>"lgarza24n#drupal.org", :gender=>"Female", :company=>"Cogilith", :currency=>"EUR", :word=>"orchestration", :drug_brand=>"EPIVIR", :drug_name=>"lamivudine", :drug_company=>"State of Florida DOH Central Pharmacy", :pill_color=>"Maroon", :frequency=>"Yearly", :token=>"_", :keywords=>"in faucibus", :bitcoin_address=>"19jTjXLPQUL1nEmHrpqeqM1FdtDFZmUZ2E"}}
When I run data[2759].first I get:
created_at
1309380645
I need to pull every hash where created_at is between range = 1403321503..1406082945. I tried about twenty different methods using each and collect on the data hash with no success. My last attempt printed out an empty {} for each original hash.
I'm trying to test this with no success:
data.each do |hash|
if hash.first.to_s.to_i > 1403321503 && hash.first.to_s.to_i < 1406082945
puts hash
end
end
I'm not sure how to isolate the value of key:created_at and then see if it is within the range. I also tried doing hash.first.to_s.to_i =/== range.
I am able to get just the :created_at value by using data[1].first.last but when I try to use that in a method it errors out.
Here is a link to the original CSV: goo.gl/NOjAPo
It is not on my work computer so I can't do a pastebin of it.
I would only store rows in the data hash that are within the range. IMO that performs betters, because it needs less memory than reading all data into data and remove the unwanted entries in a second step.
DATE_RANGE = (1403321503..1406082945)
CSV.foreach("sample_data.csv",
:headers => true,
:header_converters => :symbol,
:converters => :all) do |row|
attrs = Hash[row.headers[1..-1].zip(row.fields[1..-1])]
data[row.fields[0]] = attrs if DATE_RANGE.cover?(attrs[:created_at])
end
It might make sense to check the condition before actually creating the hash by checking DATE_RANGE.cover? against the column number (is created_at in row.fields[1]?).
Use Enumerable#select
hash.select do |_, v|
(1403321503..1406082945) === v[:created_at]
end
Here we also use Range#=== also known as case-equal, or triple-equal, to check if the value is inside the range.

Ruby DataMapper::ImmutableError

get '/watch/:id' do |id|
#results = Twitchtvst.all( :fields => [:Twitchtv ],
:conditions => { :user_id => "#{id}" }
)
#p #results.inspect
#results.each do |result|
puts result.id
end
erb :mystream
end
I get this error message immutable resource cannot be lazy loaded. How do I fix this?
The Error message is:
DataMapper::ImmutableError at /watch/1
Immutable resource cannot be lazy loaded
According to the official documentation:
Note that if you don't include the primary key in the selected columns, you will not be able to modify the returned resources because DataMapper cannot know how to persist them. DataMapper will raise DataMapper::ImmutableError if you're trying to do so nevertheless.
I know that you are not modifying anything here but I think that the same rule applies for lazy loading. So I will suggest to try it like that:
#results = Twitchtvst.all( :fields => [:Twitchtv, :id],
:conditions => { :user_id => "#{id}" }
) ode here
Note the id as an additional field.

How can I avoid duplication in a join query using Sequel with Postgres on Sinatra?

I want to do a simple join. I have two tables: "candidates" and "notes".
Not all candidates have notes written about them, some candidates have more than one note written about them. The linking fields are id in the candidates table and candidate_id in the notes table. The query is:
people = candidates.where(:industry => industry).where("country = ?", country).left_outer_join(:notes, :candidate_id => :id).order(Sequel.desc(:id)).map do |row|
{
:id => row[:id],
:first => row[:first],
:last => row[:last],
:designation => row[:designation],
:company => row[:company],
:email => row[:email],
:remarks => row[:remarks],
:note => row[:note]
}
end
It works kind of fine and gets all the specified candidates from the candidates table and the notes from the notes table but where there is more than one note it repeats the name of the candidate. In the resulting list, person "abc" appears twice or three times depending on the number of notes associated with that person.
I am not actually printing the notes in the HTML result just a "tick" if that person has notes and "--" if no notes.
I want the person's name to appear only once. I have tried adding distinct in every conceivable place in the query but it made no difference.
Any ideas?
In order for distinct to work, you need to make sure you are only selecting columns that you want to be distinct on. You could try adding this to the query
.select(:candidates__id, :first, :last, :designation, :company, :email, :remarks, Sequel.as({:notes=>nil}).as(:notes)).distinct
But you may be better off using a subselect instead of a join to check for the existence of notes (assuming you are using a decent database):
candidates.where(:industry => industry, :country=>country).select_append(Sequel.as({:id=>DB[:notes].select(:candidate_id)}, :note)).order(Sequel.desc(:id)).map do |row|
{ :id => row[:id], :first => row[:first], :last => row[:last], :designation => row[:designation], :company => row[:company], :email => row[:email], :remarks => row[:remarks], :note => row[:note] }
end

Feed Array of Strings into Ruby Loop

I'd like to write a quick method that can help me initialize a few fields in one of my ruby tables. This is what I have so far but it does not work. I would like to be able to feed an array of field names into this function so that I can get the whole initialization done in one loop.
fields =["field1","field2","field3","field4"]
tasks = Task.all
tasks.each do |task|
fields.each do |field|
if task.field.nil?
task.update_attribute :field => true
end
end
end
Maybe this is what you mean:
fields = %w[field1 field2 field3 field4]
tasks = Task.all
tasks.each do |task|
fields.each do |field|
task.update_attribute :"#{field}" => true if task.send(field).nil?
end
end
If this is actually Rails, as it appears to be, you can use hash access:
task[field] = true if task[field].nil?
You would still need to save the modified record.
You may use task.update_attribute(field, true) instead: this will update the database immediately, but will do a transaction for each modified attribute.
Try to always use the least number of queries to the database
fields = ["field1","field2","field3","field4"]
fields.each do |field|
Task.where({field => nil}).update_all({field => true})
end

With Mongoid, can I "update_all" to push a value onto an array field for multiple entries at once?

Using Mongoid, is it possible to use "update_all" to push a value onto an array field for all entries matching a certain criteria?
Example:
class Foo
field :username
field :bar, :type => Array
def update_all_bars
array_of_names = ['foo','bar','baz']
Foo.any_in(username: foo).each do |f|
f.push(:bar,'my_new_val')
end
end
end
I'm wondering if there's a way to update all the users at once (to push the value 'my_new_val' onto the "foo" field for each matching entry) using "update_all" (or something similar) instead of looping through them to update them one at a time. I've tried everything I can think of and so far no luck.
Thanks
You need call that from the Mongo DB Driver. You can do :
Foo.collection.update(
Foo.any_in(username:foo).selector,
{'$push' => {bar: 'my_new_val'}},
{:multi => true}
)
Or
Foo.collection.update(
{'$in' => {username: foo}},
{'$push' => {bar: 'my_new_val'}},
{:multi => true}
)
You can do a pull_request or a feature request if you want that in Mongoid builtin.

Resources