简体   繁体   English

rails:获取标记为x AND y AND z的所有项目

[英]rails: Get all items tagged x AND y AND z

I've got two models: Item and Tag . 我有两个型号: ItemTag Both have a name attribute. 两者都有name属性。 I want to find items tagged with several tags. 我想找到标有多个标签的商品。

class Item < ActiveRecord::Base
  has_many :tags
  validates_presence_of :name
end

class Tag < ActiveRecord::Base
  belongs_to :item
  validates_presence_of :name
end

Given a list of tag ids, I can easily enough get the list of items tagged with one tag or the other: 给定一个标签ID列表,我可以很容易地获得用一个标签另一个标签标记的项目列表:

# Find the items tagged with one or more of the tags on tag_ids
Item.all(:conditions => ['tags.id in (?)', tag_ids], :joins => :tags)

If tag_ids is {1,4} , then I get all pictures tagged with 1, or 4, or both. 如果tag_ids{1,4} ,那么我tag_ids所有图片标记为1或4或两者。

I want to know now how to get the pictures that are tagged with both - 1 AND 4. 我现在想知道如何获得用-1 4标记的图片。

I can't even imagine the SQL that is needed here. 我甚至无法想象这里需要的SQL。

You can solve this by grouping the results and checking the count: 您可以通过对结果进行分组并检查计数来解决此问题:

Item.all(
  :conditions => ['tags.id IN (?)', tag_ids], 
  :joins      => :tags, 
  :group      => 'items.id', 
  :having     => ['COUNT(*) >= ?', tag_ids.length]
)

Little update : Today, we can use (inspired by elektronaut) : 小更新:今天,我们可以使用(灵感来自elektronaut):

Item.joins(:tags).where("tags.label in (?)", tags).group('items.id').having("COUNT(*) >= ?", tags.size)

It is not very different, by it works well here. 它并没有太大的不同,它在这里运作良好。

I've got one thing to add to elektronaut's otherwise wonderful answer: it will not work on PostgreSQL. 我有一件事要添加到elektronaut的其他很好的答案:它不适用于PostgreSQL。

On my real example the Item.all call includes other tables; 在我的实例中,Item.all调用包括其他表; so the select looks like this: 所以select看起来像这样:

SELECT items.id AS t0_f0, items.name as t0_f1 ..., table2.field1 as t1_f0 .. etc

PostgreSQL's GROUP BY requires that all fields used on a select to be included there. PostgreSQL的GROUP BY要求将select上使用的所有字段都包含在那里。 So I had to include all the fields used on the previous select on the GROUP BY clause. 所以我必须在GROUP BY子句中包含上一个select中使用的所有字段。

And still it didn't work; 它仍然没有用; I'm not sure why. 我不知道为什么。

I ended up doing a simpler, uglier thing. 我最终做了一个更简单,更丑陋的事情。 It requires two db requests. 它需要两个db请求。 One of them is used to return ids, which are used as a condition. 其中一个用于返回id,它们用作条件。

class Item < ActiveRecord::Base

  # returns the ids of the items tagged with all tags
  # usage: Item.tagged_all(1,2,3)
  named_scope :tagged_all, lambda { |*args|
    { :select => "items.id",
      :joins => :tags,
      :group => "items.id",
      :having => ['COUNT(items.id) >= ?', args.length],
      :conditions => ["tags.id IN (?)", args]
    }
  }

Then I can do this: 然后我可以这样做:

  Item.all(
    :conditions => [
      'items.id IN (?) AND ... (other conditions) ...',
      Items.tagged_all(*tag_ids).collect(&:id),
      ... (other values for conditions) ...
    ],
    :includes => [:model2, :model3] #tags isn't needed here any more
  )

Hacky, but it works, and the hackyness is localized. Hacky,但它有效,而hackyness是本地化的。

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

相关问题 X和Y之间的Teradata Z与Z&gt; = Y和Z &lt;X - teradata Z between X and Y vs Z >= Y and Z < X SQL查询:如果x = 1则y选择所有位置 - SQL query: select all where if x=1 then y<z else if x=2 then y<w “ a IN(&#39;x&#39;,&#39;y&#39;)或a =&#39;z&#39;”是否等于:“ a IN(&#39;x&#39;,&#39;y&#39;,&#39;z&#39;)”? - Does “a IN ('x','y') OR a = 'z' ” equal: “a IN ('x', 'y', 'z')”? 在Oracle中将此路径反转为z / y / x到x / y / z - Reverse in Oracle this path z/y/x to x/y/z SQL 计算 X + Y = Z - SQL calculation X + Y = Z SQL查询(显示所有&#39;x&#39;其中&#39;x&#39;不在表&#39;2&#39;中用于字段&#39;y&#39;并且具有&#39;z&#39;标志) - SQL Query (Display All 'x' Where 'x' Is Not In Table '2' for field 'y' and has 'z' flag) 如何获取标记为 Tag1 AND Tag2 AND ... 的所有项目以获取 3 表标记解决方案 - How to get all items that are tagged Tag1 AND Tag2 AND … for a 3-table tag solution sql其中x = y和x = z以及 - sql where x = y and x = z and 选择最近“ z”天内从“ y”类别中购买“ x”次商品的所有客户 - Select all customer who have bought 'x' times something from the category 'y' within the last 'z' days 用于获取列匹配(x AND y AND z)的所有行的查询或代码解决方案 - A query or code solution for getting all rows where a column matches (x AND y AND z)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM