【问题标题】:Rails - how to fetch random records from an object?Rails - 如何从对象中获取随机记录?
【发布时间】:2015-05-05 09:53:09
【问题描述】:

我正在做这样的事情:

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

返回:

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

一旦我得到这个随机数据,我需要遍历这些数据,如下所示:

random_data.each do |rd|
  ...

我知道有一种方法可以在 MySQL 中获取随机数据,但是我需要选择 400 次这样的随机数据,所以我认为从数据库加载一次数据和 400 次选择随机数比运行在 MySQL 上查询 400 次。

但是 - 如何摆脱这个错误?

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

提前谢谢你

【问题讨论】:

  • 该表总共有多少行?该表中的主 ID 是否完整或是否存在间隙(您是否删除了记录)?

标签: mysql ruby-on-rails ruby arrays random


【解决方案1】:

使用data.sample(rand(100..200)) 有关 rand 为什么不起作用的更多信息,请在此处阅读 https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4555

【讨论】:

  • 嗯.. 我正在尝试这种方法,但收到此错误:TypeError (no implicit conversion of Range into Integer):
  • 你可以试试 data.sample(rand(10..100))
【解决方案2】:

我会在模型中添加以下范围(取决于您使用的数据库):

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

那么下面的查询会在一个查询中加载一个随机数(范围为200-400)的对象:

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

如果你真的想在 Rails 中而不是在数据库中这样做,那么加载所有记录并使用sample

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

但这会更慢(取决于数据库中的条目数),因为 Rails 会从数据库中加载所有记录并实例化它们,这可能会占用大量内存。

【讨论】:

  • 但这意味着我总是得到 400 条记录,对吧?我需要随机计数结果(假设在 200 到 400 之间)。而且,数据库有 400 次查询,但在另一种方法中,只有一条记录,并且运行了 400 次抓取随机记录的方法。只是想知道什么更有效。
  • ORDER BY 会对大型数据库表的查询性能产生负面影响。我不会在生产代码中使用它。
  • @user984621:我更新了我的答案。它只会查询数据库一次。
  • @mcfinnigan:在数据库中排序肯定比首先将所有记录加载到内存中更快(就像问题中建议的那样)。特别是对于更大的数据库。但你是对的,对于有数百万行的表格来说,这可能不是一个好主意。
【解决方案3】:

另一种并非特定于数据库的方式是:

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

这里唯一的事情是 - 正在执行 2 个查询self.count 正在执行一个查询 - SELECT COUNT(*) FROM models,另一个是您的实际查询以获取 随机 记录。

好吧,现在假设您想要n 随机记录。然后像这样写:

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

【讨论】:

    【解决方案4】:

    这实际上取决于您要投入多少精力来优化它,因为解决方案不止一种。这里有 2 个选项..

    一个简单的方法是使用ORDER BY RAND() LIMIT 400随机选择400个项目。

    或者,只需选择月球下的所有内容,然后使用 Ruby 从总结果集中随机挑选 400 个,例如:

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

    我不推荐第二种方法,但应该可以。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-17
      • 1970-01-01
      • 2016-10-29
      • 2014-11-21
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多