Model.first does not retrieve first record from table - ruby-on-rails

Model.first doesnot retrive first record from table. Instead it retrives any random record from table.
eg:
Merchant.first
Query
SELECT "merchants".* FROM "merchants" LIMIT 1
=> <Merchant id: 6, merchant_name: "Bestylish", description: "", description_html: "" >
Instead the query should be
SELECT "merchants".* FROM "merchants" ORDER BY "merchants"."id" ASC LIMIT 1;
Why it doesnot retrive the first record

Model.first will use the default sorting of your database.
For example. In Postgresql default sorting is not necessarily an id.

This seems to be default behaviour with Postgres, as some active-record versions do not add a default ordering to the query for first, while adding one for last.
https://github.com/rails/rails/issues/9885
PostgreSQL does not by default apply a sort, which is generally a good thing for performance.
So in this context "first" means "the first row returned", not "the first row when ordered by some meaningless key value".
Curiously "last" does seem to order by id.

It is defined here, in Rails 4, to order by primary key if no other order conditions are specified.
In Rails 3.2.11, it is as such:
def find_first
if loaded?
#records.first
else
#first ||= limit(1).to_a[0]
end
end
Without the order method, which will just apply the limit and then leave the ordering up to your database.

You need to apply the ordering yourself. Try calling Merchant.order('id ASC').first
It may be possible to automate this using default scopes in your model but I'm not sure about that.

Related

Ruby on Rails - Limit Database Query to One Result only

I want to query the database but only find out if there is at least one result or not. I am trying to minimize the cost for this transaction. What would the structure be in Rails to have the query be SELECT TOP or SELECT FIRST in SQL?
You could try exists?
Person.exists?(5) # by primary key
Person.exists?(name: 'David')
Person.exists? # is there at least one row in the table?
Person.where(name: 'Spartacus', rating: 4).exists?
Person.active.exists? # if you have an "active" scope
Note that this limits the result set to 1 in the SQL query and the select clause is something like SELECT 1 AS one

How to get the latest created object in ruby on rails [duplicate]

I was wondering if there is a way to find the newest record in a table in rails3?
Given a Post model, you could do #post = Post.order("created_at").last
(The reason I didn't just do a #post = Post.last is because that always defaults to sort by your primary key (usually id). Most of the time this is fine, but I'm sure there's a scenario where that could cause problems (e.g. setting custom IDs on records, database changes which affect the primary key sequencing/autonumbering, etc.). Sorting by the created_at timestamp ensures you are really getting the most recent record).
While dmarkow's answer is technically correct, you'll need to make an index on created_at or risk an increasingly slow query as your database grows.
If you know that your "id" column is an auto-increment primary key (which it likely is), then just use it since it is an index by definition.
Also, unless AREL is optimized to select only one record in a find(:last), you run the risk of making it select ALL records, then return you just the last one by using the "last()" method. More efficient is to limit the results to one:
MyModel.last(:order => "id asc", :limit => 1)
or
MyModel.first(:order => "id desc", :limit => 1)
you may run into ambiguity issues using created_at on a sufficiently high-traffic table.
eg. try:
INSERT INTO table (created_at) VALUES ( NOW() );
INSERT INTO table (created_at) VALUES ( NOW() );
..has the potential to have the same created_at, which only has 1 second of resolution. a sort would return them in no particular order.
you may be better off storing a microtime value and sorting on that.
Yes, you can use the method .last
So if your model is called Post then:
>> Post.last
=> #<Post ...>
Try, for a model named ModelName:
record = ModelName.last

Count, empty? fails for ActiveRecord with outer joins

I have two models, Monkey and Session, where Monkey has_many Session. I have a scope for Monkey:
scope :with_session_counts, -> {
joins("LEFT OUTER JOIN `sessions` ON `sessions`.`monkey_id` = `monkeys`.`id`")
.group(:id)
.select("`monkeys`.*, COUNT(DISTINCT `sessions`.`id`) as session_count")
}
in order to grab the number of associated Sessions (even when 0).
Querying #monkeys = Monkey.with_session_counts works as expected. However, when I test in my view:
<% unless #monkeys.empty?%>
I get this error:
Mysql2::Error: Column 'id' in field list is ambiguous:
SELECT COUNT(*) AS count_all, id AS id FROM `monkeys`
LEFT OUTER JOIN `sessions` ON `sessions`.`monkey_id` = `monkeys`.`id`
GROUP BY `monkeys`.`id`
How would I convince Rails to prefix id with the table name in presence of the JOIN?
Or is there a better alternative for the OUTER JOIN?
This applies equally to calling #monkeys.count(:all). I'm using RoR 4.2.1.
Update:
I have a partial fix for my issue (specify group("monkeys.id") explicitly) I wonder whether this is a bug in the code that generates the SELECT clause for count(:all). Note that in both cases (group("monkeys.id") and group(:id)) the GROUP BY part is generated correctly (i.e. with monkeys.id), but in the latter case the SELECT only contains id AS id. The reason I say 'partial' is because it works in that it does not break a call to empty?, but a call to count(:all) returns a Hash {monkey_id => number_of_sessions} instead of the number of records.
Update 2:
I guess my real question is: How can I get the number of associated sessions for each monkey, so that for all intents and purposes I can work with the query result as with Monkey.all? I know about counter cache but would prefer not to use it.
I believe it is not a bug. Like you added on your update, you have to specify the table that the id column belongs to. In this case group('monkeys.id') would do it.
How would the code responsible for generating the statement know the table to use? Without the count worked fine because it adds points.* to the projection and that is the one used by group by. However, if you actually wanted to group by Sessions id, you would have to specify it anyway.

Faster save method?

I must convert ~ 1.300.000 records on my database.
Do you know a method faster than this?
Article.find_each(&:save)
If you're looking to update a single field in a table, you can use update_all on your ActiveRecord model.
Post.update_all(:published=>true)
# UPDATE "posts" SET "published" = 't'
This works with an ActiveRecord scopes as well.
Post.where(:published=>true).update_all(:published=>false)
# SQL (3.3ms) UPDATE "posts" SET "published" = 'f' WHERE "posts"."published" = 't'
By using this, you can use conditional statements (such as where) to pick out common rows in your table and perform update_all on them. This is assuming you want to do some form of attribute updating before saving the record.
You can increase the number of records in batch (the default is 1000), this number depends on how much memory you have in your server:
Article.find_each(:batch_size => 5000) { |r| r.save }
If you are creating, you need to bulk insert with a gem like activerecord-import. If you are updating, just use update_all.

Find the newest record in Rails 3

I was wondering if there is a way to find the newest record in a table in rails3?
Given a Post model, you could do #post = Post.order("created_at").last
(The reason I didn't just do a #post = Post.last is because that always defaults to sort by your primary key (usually id). Most of the time this is fine, but I'm sure there's a scenario where that could cause problems (e.g. setting custom IDs on records, database changes which affect the primary key sequencing/autonumbering, etc.). Sorting by the created_at timestamp ensures you are really getting the most recent record).
While dmarkow's answer is technically correct, you'll need to make an index on created_at or risk an increasingly slow query as your database grows.
If you know that your "id" column is an auto-increment primary key (which it likely is), then just use it since it is an index by definition.
Also, unless AREL is optimized to select only one record in a find(:last), you run the risk of making it select ALL records, then return you just the last one by using the "last()" method. More efficient is to limit the results to one:
MyModel.last(:order => "id asc", :limit => 1)
or
MyModel.first(:order => "id desc", :limit => 1)
you may run into ambiguity issues using created_at on a sufficiently high-traffic table.
eg. try:
INSERT INTO table (created_at) VALUES ( NOW() );
INSERT INTO table (created_at) VALUES ( NOW() );
..has the potential to have the same created_at, which only has 1 second of resolution. a sort would return them in no particular order.
you may be better off storing a microtime value and sorting on that.
Yes, you can use the method .last
So if your model is called Post then:
>> Post.last
=> #<Post ...>
Try, for a model named ModelName:
record = ModelName.last

Resources