I am using Clojure with korma to store Clojure maps in a Mysql database, e.g storing maps with this structure:
(defentity users
(table :user)
(entity-fields :email
:password
:name))
In a table with four columns id (implicitly defined), email, password and name.
So, when I call this piece of code everything works fine:
(insert users (values {:email "john#example.com"
:password "____hashed_passw___"
:name "J"}))
The problem I have is that my maps may contain some keys which do not have their corresponding columns in the database (and I do not want to persist these values). For example:
(insert users (values {:email "john#example.com"
:password "____hashed_passw___"
:name "J"
:something "else"}))
Would throw an error MySQLSyntaxErrorException Unknown column 'something' in 'field list'.
Ideally, what I would like to know is if there is an option somewhere in Korma to ignore the extra keys present in the map. The problem could be solved by dissoc-ing all of them on save, but I'd prefer to find out if there is a built in way to do it before I do that (or any other better idea).
No, you have to remove extra key/value pairs from the map. Arguably Korma could be made to remove them, based on defentities.
I suggest you either bring it up on https://github.com/korma/Korma as a feature request or look into adding it yourself. Chris Granger, the maintainer, is easy to talk to and would probably consider your idea.
Related
I am trying to sort my data according to timestamp field in my controller, note that the timestamp field may be null and may have some value. I wrote the following query.
#item = Item.sort_by(&:item_timestamp).reverse
.paginate(:page => params[:page], :per_page =>5)
But this gives error when I have items that have time_timestamp field value as NULL, but following query works.
#item = Item.order(:item_timestamp).reverse
.paginate(:page => params[:page], :per_page => 5)
Can anybody tell the difference between these two queries, and in which condition to use which one?
And I am using order and reverse to get the latest items from the database, Is this the best way or there are other best ways to get the latest data from database in terms of performance?
.sort_by is a Ruby method from Enumerable that is used to sort arrays (or array like objects). Using .sort_by will cause all the records to be loaded from the database into the servers memory, which can lead to serious performance problems (as well as your issue with nil values).
.order is a ActiveRecord method that adds a ORDER BY clause to the SQL select statement. The database will handle sorting the records. This is preferable in 99% of cases.
sort_by is executed in Ruby, so if you have a nil value, things will break in a way similar to this:
[3, nil, 1].sort
#=> ArgumentError: comparison of Fixnum with nil failed
order is executed by your RDBMS, which generally will do fine with NULL values. You can even specify where you want to put the NULL VALUES, by adding NULL FIRST (usually the default) or NULL LAST to your ORDER BY clause?
Hey you needn't you sort in that query, it'll work very long, if you work with DB you should always use :order, there solution for your problem
#item = Item.order('item_timestamp DESC NULLS LAST').paginate(:page => params[:page], :per_page => 5)
As it was said before me, .order is quicker, and it's enough in most cases, but sometimes you need sort_by, if you want to sort by value in a relation for example.
If you have a posts table and a view_counters table, where you have the number of views by article, you can't easily sort your posts by total views with .order.
But with sort_by, you can just do:
posts = #user.posts.joins(:view_counter)
#posts = posts.sort_by { |p| p.total_views }
.sort_by going to browse each element, get the relation value, then sort by the value of this relation, just with one code line.
You can further reduce the code with &:[attributeName], for example:
#posts = posts.sort_by(&:total_views)
Also, for your last question about the reverse, you can do this:
Item.order(item_timestamp: :desc)
When you use sort_by you break active record caching and as pointed out before, you load all the records into RAM memory.
When writing down queries, please always think about the SQL and the memory world, they are 2 separate things. It is like having an archive (SQL) and cart (Memory) where you put the files you take out of the archive to use later.
As most people mentioned the main difference is sort_by is a Ruby method and order is Rails ActiveRecord method. However, the scenario where to use them may vary case by case. For example you may have a scenario where sort_by may be appropriate if you already retrieved the data from the DB and want to sort on the loaded data. If you use order on then you might introduce n+1 issue and go to the database again while you already have the data loaded.
For the 10th time I need to do some GIS stuff in a project, in the pass all I needed was lat/long datatypes and used Solr or something else to process them, now I don't want to that and I want to be capable of using MariaDB/Mysql GIS features.
I don't a problem on creating my queries by hand, that's cool when I need to GET something, but when I want to create or update Rails is making my life difficult.
So I'm asking if someone knows how to add code in the RAILS to DB and DB to RAILS part to correctly parse the data.
Eg:
I want to have a POLYGON in my table:
create_table :venues, options: 'ENGINE=MyISAM DEFAULT CHARSET=utf8' do |t|
t.column :name, :string
t.column :geofence, :geometry
t.timestamps
end
No problem with that, let's ditch Rails for a moment and let's do a normal insert, peace of cake:
INSERT INTO venues (name, geofence) VALUES ('A Name', PolygonFromText('POLYGON((25.774 -80.190,18.466 -66.118,32.321 -64.757,32.321 -64.757,25.774 -80.190))'));
Now if you want to this in Rails you can't, because it treats the :geometry like a string, so can't do any of these:
v = Venue.new(name: 'hello')
v.geofence = "PolygonFromText('POLYGON((25.774 -80.190,18.466 -66.118,32.321 -64.757,32.321 -64.757,25.774 -80.190))')"
v.save
Because it will add quotes and stuff to the inserts and updates. Like this:
INSERT INTO venues (name, geofence, created_at, updated_at) VALUES ('A name', 'PolygonFromText(\"POLYGON((25.774 -80.190,18.466 -66.118,32.321 -64.757,32.321 -64.757,25.774 -80.190))\")', '2016-09-21 16:56:23', '2016-09-21 16:56:23')
So, I just want to avoid Rails add those for me, and have the ability to assign EXACTLY what I need to do inserts.
Thanks guys, hope you can help me.
For the reason, I've used mysql cmd insert into table_name (....) update custom_reports ...and hence I miss out on Model validations
validates_uniqueness_of :name
validates_presence_of :name, :description
How to validate now in rails way? Or, use the mysql way to validate(needs help in this way too)?
Rails validation and other ActiveRecord and ActiveModel magic don't work if you only execute custom SQL command. None of your model classes is even instantized then.
For Mysql (or any sql like DB), you can modify the column attribute to:
Unique (this would validate uniqueness)
Not null (this would validate presence)
I know doing the above with OCI8 and oracle would result in exceptions which I am guessing should be same with ActiveRecord and Mysql, so you should be handling your exceptions correctly
But as #Marek as said you should be relying on Active record and be doing things like
Model.create()
OR
model_instance.save()
If you want to find (and perhaps handle) the entries in your db that are not valid, try the following in the rails console:
ModelName.find_each do |item|
unless item.valid?
puts "Item ##{item.id} is invalid"
# code to fix the problem...
end
end
valid? runs the Validations again, but does not alter the data.
I am pretty new to Sphinx.
Trying to find user with name "bob" and company_id "14".
Controller:
#users = User.search 'bob', :conditions => { :company_id => '14'}
Model:
define_index do
indexes :name
indexes :company_id
end
Error:
index user_core: query error: no field 'company_id' found in schema
I have the 'company_id' in table & I re-indexed everything several times.
When I am just searching for the 'name' everything works properly.
Just as another helpful hint: turns out I had to change the way I called Model.search(), since my field was listed as an attribute (i.e. using has), I needed to call the search method with :with instead of :conditions (for fields).
Attributes should be declared as:
has company_id
So, in you case:
Model:
define_index do
indexes :name
has :company_id
end
And one more helpful hint, if you happen to be an idiot like me:
If you are getting this error and you are correctly using attributes and fields, it may be that you forgot to restart your dev server after adding a new field to the index.
Is there any easier way of writing sql to replace all columns names with "schedule_" to make it easier to work with in PHP.
SELECT * FROM schedules
Array
(
[schedule_id] => 9
[schedule_datetime_from] => 2011-12-22 18:28:00
[schedule_datetime_until] => 2011-12-22 22:28:00
[schedule_capacity] => 89
[schedule_amount] => 9.99
[content_id] => 77
)
At the moment I end up doing:
$stmnt1 = "SELECT s.schedule_id as id, s.schedule_datetime_from as datetime_from, s.schedule_datetime_until as datetime_until, etc FROM schedules s";
There is no other way to do this through SQL -- and really, why would you want to? It's not like you are typing in the query by hand each time.
What you could do is write PHP code that changes the array keys after each row has been read, but that's orders of magnitude worse as a solution. Just go with what you already have.
I agree with Jon, but if you REALLY have to get this done I would recommend using the MySQL command line interface. However, you must also consider indices, UNIQUE constraints, and Foreign Keys. And, if you have any code which is expecting the non-prefixed versions of the columns you will end up breaking it, so be sure your code is updated as well.
Read up on ALTER TABLE CHANGE via MySQL docs, the line you are looking for is: "You can rename a column using a CHANGE old_col_name new_col_name column_definition clause"