【问题标题】:optimizing select query on has_many :through attributes association优化 has_many 上的选择查询:通过属性关联
【发布时间】:2012-04-04 00:14:26
【问题描述】:

我想查找所有带有在 params 数组中传递的标签的帖子。 post通过关联有很多标签。

目前我的代码如下所示:

if params.has_key?(:tags)
  params[:tags].each do |tag|
    @tags = Array.new if @tags.nil?
    @tag = Tag.find_by_content(tag)
    @tags << @tag if @tag
  end
  @allposts = Post.followed_by(@user).select { |p| p.tags.size != 0 && (p.tags & @tags).size == p.tags.size }
else
  @allposts = Post.followed_by(@user)
end

我基本上在做的是根据 params 数组找到实际的标签模型并将它们放入一个数组中,然后我对所有帖子运行选择查询,搜索具有相同标签数组的帖子。

有没有更好更干净的方法来做到这一点?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 activerecord


    【解决方案1】:

    您可以将Tag.find 查询滚动到对数据库的单个请求中,并添加适当的 where 子句来限制返回的帖子:

    finder = Post.followed_by(@user)
    if params.has_key?(:tags)
      @tags = Tag.where(:content => params[:tags])
      finder = finder.with_tags(@tags)
    end
    
    @allposts = finder.all
    

    在 app/models/post.rb 中

    scope :with_tags, lambda { |tags| joins(:tags).group('posts.id').where(:tags => { :id => tags.map { |t| t.id } } ).having("COUNT(*) = ?", tags.length) }
    

    更新

    with_tags 作用域的作用如下:

    1. joins(:tags) 首先我们将标签表加入到帖子表中。当您使用符号语法时,Rails 将使用内部连接 ​​
    2. where(:tags =&gt; { :id =&gt; tags.map { |t| t.id } } ) 我们想要过滤标签,只找到提供的标签。由于我们提供了一个标签对象列表,我们使用 map 来生成一个 ID 数组。然后在 where 子句中使用该数组来创建 WHERE field IN (list) 查询 - 哈希语法中的哈希用于表示表,然后是表中的列。
    3. group('posts.id') 所以现在我们有了一个带有必要标签的帖子列表,但是,如果有多个标签,我们将列出多次的帖子(每个匹配的标签一次),所以我们按 posts.id 分组,以便我们每个帖子只返回 1 行(还需要我们可以在第 4 步中进行计数)
    4. having("count(*) = ?", tags.length) 这是拼图的最后一块。现在我们已经按帖子分组了,我们可以计算与该帖子关联的匹配标签的数量。只要不允许重复标签,那么如果匹配标签的数量(count(*))与我们搜索的标签数量(tags.length)相同,那么我们可以确定该帖子具有我们所有的标签正在搜索。

    您可以通过阅读Active Record Query Interface Guide找到更多关于模型可用的不同查询方法的信息

    【讨论】:

    • 谢谢!这真的很有帮助。您能否解释一下范围声明,因为我也想了解发生了什么?如何在 RSPEC 中测试该语句?
    • 嗨,Gal,将扩展我的答案以解释范围声明
    • 感谢您非常详细的回答!如何获取 Post.followed_by(@user) 的所有标签? post通过标签有很多标签
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多