【问题标题】:Randomize order for DataMapper records随机化 DataMapper 记录的顺序
【发布时间】:2012-07-09 09:41:59
【问题描述】:

我只是希望以随机顺序返回 DataMapper 记录

这是我的模型(使用带有 sqlite3 数据库的 DataMapper):

class Movie
  include DataMapper::Resource
  DataMapper::Property::String.length(255)

  property :id, Serial
  property :title, String
  property :img, String
  property :description, String
  property :year, String
  property :created_at, DateTime

  has n, :votes 
  belongs_to :user
end

这就是我返回记录的方式(Sinatra)

get '/' do
  @movies = Movie.all # <-- What should this look like?
  haml :home
end

【问题讨论】:

    标签: ruby sqlite sinatra datamapper


    【解决方案1】:

    您也可以在 SQL 中执行此操作,例如:

    class Movie
      # tons of other stuff here...
    
      def self.random
        repository(:default).adapter.select <<-SQL
          SELECT * FROM movies ORDER BY RANDOM()
        SQL
      end
    end
    

    那你就可以了

    get '/' do
      @movies = Movie.random
      haml :home
    end
    

    如果您使用 MySQL,则需要将 RANDOM() 替换为 RAND()。请注意,Movie#random 返回的对象不是Movie 对象并且是只读的,但是您可以像使用Movie 对象一样读取属性,例如Movie.random.first.title 获取第一部随机电影的标题。

    最大的优势是,如果您的数据库中有很多记录并且只想要少数随机的Movies,您不必获取所有电影并在之后对其进行排序,但是您可以使用 SQL 查询,例如这个:

    SELECT * FROM movies ORDER BY RANDOM() LIMIT 10
    

    或者你可以将你的方法扩展成这样:

    class Movie
      # tons of other stuff here...
    
      def self.random(opts={})
        query = "SELECT * FROM movies ORDER BY RANDOM()"
        query << " LIMIT #{opts[:limit]}" unless opts[:limit].nil?
        repository(:default).adapter.select(query)
      end
    end
    

    允许编写这样的查询:

    Movie.random              # get all movies sorted randomly
    Movie.random(:limit => 5) # get five random movies
    

    【讨论】:

    • 你能解释一下repository(:default).adapter.select在sql语句之前做了什么吗?谢谢。
    • repository(:default) 只选择:default 存储库。您可以在 DataMapper 中使用多个数据存储(请参阅datamapper.org/docs/misc.html),但这与大多数应用程序无关。 adapter 根据您使用的数据库动态获取相应的适配器(例如您的情况下的 sqlite 适配器)。最后,select 对数据库进行查询。
    • 感谢这看起来不错...而且您认为它比 Movie.all.shuffle 更高效?
    • @pruett:不一定性能更高。它的亮点是从数据库中的一个大表中提取一些随机条目,因为数据库查询通常是瓶颈。如果您只有几个条目或者总是想获得所有条目,那么@ScottJShea 的shuffle 解决方案会更简洁,我会坚持下去。
    • 太棒了,谢谢。是的,我检查了他的解决方案,因为它更容易并且正是我所需要的,因为我需要随机化并返回所有结果。感谢您提供反馈并回答我的问题
    【解决方案2】:

    我相信你可以做到这一点(基于on this):

    @movies = Movie.all.sort_by{rand}
    

    另外,同样的帖子 suggests Array#shuffle! 会获取数组并将其随机排列,所以可能是这样的:

    @movies = Movie.all.shuffle #no ! since you are not replacing the Array; not sure if DM supports it
    

    --或--

    @movies = Movie.all
    @movies.shuffle!
    

    【讨论】:

    • @movies = Movie.all.shuffle!@movies = Movie.all; @movies.shuffle! 有何不同?
    • @padde 很微妙,但它是@movies = Movie.all.shuffle... 没有感叹号。 ! 表示您获取原始 var 中的内容并覆盖它。由于在@movies = Movie.all.shuffle 段中的@movies 中没有可覆盖的内容,因此我省略了!。我只是不确定 DM 是否继承了该方法,因此如果它不起作用,则提供替代方法。
    • 我的意思是在你的最后一个例子中,你实际上只是在两行中写了Movie.all.shuffle!。您仍然在 Movie.all 的返回值上调用 mutator。所以说一个人不应该打电话给Movie.all.shuffle!是没有意义的。但是由于Movie.all 只是返回一个副本,所以无论如何都可以,所以没关系。
    • 另请注意shuffle 直接在 C 中实现 Fisher-Yates 算法,因此这是在 Ruby 中打乱数组的最有效方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2019-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多