0

我想找到匹配尽可能多的可选标签的产品,这些标签由所有条件标签标记,按匹配的可选标签数量排序。

我想出了这个来计算可选标签

optional_tags = [1,2,3]
conditional_tags = [4]

products = Product.select('COUNT(*) AS count_all, products.*')
                  .joins(:tags).where('tags.id IN (?)', optional_tags)
                  .group('products.id')
                  .order('count_all DESC')

我成功获得了产品 ID 和匹配的可选标签的数量:

products: {30=>4, 26=>3, 29=>3, 27=>2, 28=>1}

当我尝试添加条件标签时,我只得到一个空哈希。我试过这样:

products = Product.where('tags.id IN (?)', conditional_tags)
                  .select('COUNT(*) AS count_all, products.*')
                  .joins(:tags).where('tags.id IN (?)', optional_tags)
                  .group('products.id')
                  .order('count_all DESC')

Rails 优化了查询并结合了所有where部分......

如何将条件标签添加到我的构造中?谢谢你的帮助!

例子:

产品的类型很重要,但人们并不关心细节。

条件标签 = [ 1 辆车]

optional_tags = [ 2 红色3 奔驰4 快速]

一辆红色的 汽车是可以的,但一辆梅赛德斯红色快速 摩托车不应该出现在结果列表中,即使有更多匹配的标签。

4

3 回答 3

1

我不知道你是否知道,但我认为你的第二个查询相当于:

products = Product.select('COUNT(*) AS count_all, products.*')
                  .joins(:tags)
                  .where('tags.id IN (?) AND tags.id IN (?)', optional_tags, conditional_tags)
                  .group('products.id')
                  .order('count_all DESC')

也许你在追求更接近这个的东西?

products = Product.select('COUNT(*) AS count_all, products.*')
                  .joins(:tags)
                  .where('tags.id IN (?)', optional_tags | conditional_tags)
                  .group('products.id')
                  .order('count_all DESC')

我的猜测可能不正确,因为我不完全理解您要做什么。不过,也许这会让你走得更远。

于 2013-02-07T20:41:40.700 回答
1

好吧,我想我终于想通了:

class Product < ActiveRecord::Base
  scope :having_tags, -> { |tags|
    joins(:tags).where('tags.id IN (?)', tags)
  }

  scope :ordered_by_tag_count, -> { |tags|
    joins(:tags)
    .where('tags.id IN (?)', tags)
    .group('products.id')
    .order('count_all DESC')
  }
end

所以如果你有这些标签:

条件标签 = [1 辆车]

optional_tags = [2 red, 3 mercedes, 4 fast]

你可以这样做:

Product.having_tags([1]).ordered_by_tag_count([2, 3, 4])
于 2013-02-07T21:07:18.317 回答
0

谢谢你的帮助,杰森。我想我想通了...我对可选标签的主查询中的条件标签执行子查询。

我的产品范围:

scope :tagged, lambda { |tag_ids|
  joins(:tags)
  .where('tags.id IN (?)', tag_ids)
  .group('products.id')
}
scope :matched, lambda { |product_ids, tag_ids|
  select('COUNT(*) AS count_all, products.*')
  .joins(:tags)
  .where('products.id IN (?) AND tags.id IN (?)', product_ids, tag_ids)
  .group('products.id')
  .order('count_all DESC')
}

我的查询构造:

result = Product.matched(Product.tagged(branch_ids).map(&:id), tag_ids)

我有点担心性能,因为 Rails 必须执行两个单独的查询。好消息是,我可以将 .limit() 添加到“主”查询中。

如果有人知道如何在一个查询中解决这个问题,请告诉我!谢谢!

于 2013-02-08T02:54:19.503 回答