简体   繁体   English

Rails-如何从对象获取随机记录?

[英]Rails - how to fetch random records from an object?

I am doing something like this: 我正在做这样的事情:

data = Model.where('something="something"')
random_data = data.rand(100..200)

returns: 返回:

NoMethodError (private method `rand' called for #<User::ActiveRecord_Relation:0x007fbab27d7ea8>):

Once I get this random data, I need to iterate through that data, like this: 一旦获得此随机数据,就需要遍历该数据,如下所示:

random_data.each do |rd|
  ...

I know there's a way to fetch random data in MySQL, but I need to pick the random data like 400 times, so I think to load data once from database and 400 times to pick random number is more efficient than to run the query 400 times on MySQL. 我知道有一种方法可以在MySQL中获取随机数据,但是我需要选择400次随机数据,因此我认为从数据库中加载一次数据和选择400次随机数据要比运行查询400次更为有效在MySQL上。

But - how to get rid of that error? 但是-如何摆脱这个错误?

NoMethodError (private method `rand' called for #<User::ActiveRecord_Relation:0x007fbab27d7ea8>):

Thank you in advance 先感谢您

I would add the following scope to the model (depends on the database you are using): 我将以下范围添加到模型中(取决于您使用的数据库):

# to model/model.rb
# 'RANDOM' works with postgresql and sqlite, whereas mysql uses 'RAND'
scope :random, -> { order('RAND()') } 

Then the following query would load a random number (in the range of 200-400) of objects in one query : 然后下面的查询将加载一个随机数(在200-400的范围内)在一个查询中的对象:

Model.random.limit(rand(200...400))

If you really want to do that in Rails and not in the database, then load all records and use sample : 如果您真的想在Rails中而不是在数据库中执行此操作,请加载所有记录并使用sample

Model.all.sample(rand(200..400))

But that to be slower (depending on the number of entries in the database), because Rails would load all records from the database and instantiate them what might take loads of memory. 但这会变慢(取决于数据库中的条目数),因为Rails将从数据库中加载所有记录并实例化它们,这可能会占用大量内存。

使用data.sample(rand(100..200))了解为什么rand无法正常工作的更多信息,请在此处阅读https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4555

Another way, which is not DB specific is : 与数据库无关的另一种方法是:

def self.random_record
  self.where('something = ? and id = ?', "something", rand(self.count))
end

The only things here is - 2 queries are being performed. 这里唯一的事情是-正在执行2个查询 self.count is doing one query - SELECT COUNT(*) FROM models and the other is your actual query to get a random record. self.count在做一个查询- SELECT COUNT(*) FROM models ,另一个是您要获取随机记录的实际查询。

Well, now suppose you want n random records. 好吧,现在假设您想要n随机记录。 Then write it like : 然后像这样写:

def self.random_records n
  records = self.count
  rand_ids = Array.new(n) { rand(records) }
  self.where('something = ? and id IN (?)', 
             "something", rand_ids )
end

It really depends how much effort you want to put into optimizing this, because there's more than one solution. 这实际上取决于您要为此优化付出多少努力,因为有不止一种解决方案。 Here's 2 options.. 这是2个选项。

Something simple is to use ORDER BY RAND() LIMIT 400 to randomly select 400 items. 简单的方法是使用ORDER BY RAND() LIMIT 400随机选择400个项目。

Alternatively, just select everything under the moon and then use Ruby to randomly pick 400 out of the total result set, ex: 或者,只需选择月球下的所有内容,然后使用Ruby从总结果集中随机选择400个,例如:

data = Model.where(something: 'something').all # all is necessary to exec query
400.times do
  data.sample # returns a random model
end

I wouldn't recommend the second method, but it should work. 我不推荐第二种方法,但是它应该可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM