2013-06-28 33 views
27

User.find(:all, :order => "RANDOM()", :limit => 10)是我做到了,在Rails的方式3找到一些隨機記錄的'Rails 4 Way'是什麼?

User.all(:order => "RANDOM()", :limit => 10)是我怎麼想的Rails 4將做到這一點,但是這仍然給了我一個棄用警告:

DEPRECATION WARNING: Relation#all is deprecated. If you want to eager-load a relation, you can call #load (e.g. `Post.where(published: true).load`). If you want to get an array of records from a relation, you can call #to_a (e.g. `Post.where(published: true).to_a`). 

回答

67

你會想改爲使用orderlimit方法。您可以擺脫all

對於PostgreSQL和SQLite:

User.order("RANDOM()").limit(10) 

或者對MySQL:

User.order("RAND()").limit(10) 
+0

輝煌,謝謝! – justindao

+12

只是簡單的說明,我不得不使用:'User.order(「RAND()」)。limit(10)',因爲我使用的是MySQL數據庫。 – backwardm

+3

不起作用。它給了我相同的記錄集。 – Major

22

由於隨機函數可以爲不同的數據庫改變,我會建議使用下面的代碼:

User.offset(rand(User.count)).first 

當然,這隻有在您只查找一條​​記錄時纔有用。

如果你想獲得更多的那一個,你可以這樣做:

User.offset(rand(User.count) - 10).limit(10) 

- 10是向你保證的情況下,蘭德獲得10條記錄返回一個數字比計數時 - 10

請記住,您將始終獲得10個連續記錄。

+3

+1不僅「接近」方法比接受的答案更通用,而且當有大量記錄時它也更快。這是因爲'ORDER BY RANDOM()LIMIT $ 1'會**排序整個表格**,然後選擇第一個_n_項目。排序操作可能是'O(n * log n)',並且對一個大表進行排序不僅會讀取該表,還會涉及讀寫臨時文件。 – Dennis

+0

這對我有效,而'User.order(「RANDOM()」)。limit(10)'沒有;它總是返回相同的記錄。我正在使用** Postgresql **數據庫並運行** Rails 5 **。 – sambecker

+0

這應該是公認的答案 – Tallboy

12

我認爲最好的解決方案是真正在數據庫中隨機排序。 但是如果你需要避免從數據庫中獲得特定的隨機函數,你可以使用pluckshuffle的方法。

對於一個記錄:

User.find(User.pluck(:id).shuffle.first) 

對於多個記錄:

User.where(id: User.pluck(:id).sample(10)) 
+0

不錯。更短:'User.find(User.ids.shuffle.first)' – Arta

1

對於MySQL這個工作對我來說:

User.order("RAND()").limit(10) 
-4

這裏有一個快速的解決方案。目前使用它擁有超過150萬條記錄並獲得不俗的表現。最好的解決方案是緩存一個或多個隨機記錄集,然後以期望的時間間隔與後臺工作人員一起刷新它們。

創建random_records_helper.rb文件:

module RandomRecordsHelper 

def random_user_ids(n) 
    user_ids = [] 
    user_count = User.count 
    n.times{user_ids << rand(1..user_count)} 
    return user_ids 
end 
在控制器

@users = User.where(id: random_user_ids(10)) 

這比.order("RANDOM()").limit(10)方法快得多 - I從一個13秒的加載時間下降到500毫秒。

+0

當然,這只是如果你的ID是自動遞增的整數工作,從1開始,並有序列中的漏洞。 –

+1

因爲和@SergioTulentsev一樣的感覺,所以得到了很低的評價。如果你曾經銷燬任何記錄,那麼這種方法是不可靠的,因爲你可以要求10條記錄,並且可能實際上不會獲得10條記錄。速度很快,但沒有正確結果的速度沒有價值,而正確的結果(即使它們比你想要的慢)仍然有價值。 – jeffdill2

4

我建議做這個範圍,你可以那麼IT連鎖:

class User < ActiveRecord::Base 
    scope :random, -> { order(Arel::Nodes::NamedFunction.new('RANDOM', [])) } 
end 

User.random.limit(10) 
User.active.random.limit(10) 
4

雖然不是最快的解決辦法,我喜歡的簡潔:

User.ids.sample(10)

.ids方法產生一組用戶ID和.sample(10)從該陣列中選取10個隨機值。

+0

或者如果你只是想要模型本身,'User.all.sample(10)'會得到它們。 – Okomikeruko