2013-02-07 18 views
0

我要找到匹配的商品多達可選標記儘可能它被所有條件標籤標記,通過匹配可選標記量責令其條件標籤數可選標記。Rails的:當在一個查詢

我想出了這個計數的可選標籤

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的優化查詢,並結合所有其中部分...

我怎麼能添加條件標籤我的構建?謝謝你的幫助!

例子:

類型產品中是非常重要的,但人們不關心細節。

conditional_tags = [ ]

optional_tags = [ 紅色梅賽德斯快速]

紅色汽車將是確定的,但通過奔馳紅快摩托車不應該在結果列表中,即使有更多的匹配標籤。

+0

產品上可選標籤和條件標籤的含義是什麼?是否有可能用較少的技術術語解釋你想要做什麼? –

+0

**條件標記**是_必須擁有_(必須連接到產品才能列出的標記)。 **可選標籤**是_nice-to-have_。最後,所有有條件的標籤和儘可能多的可選標籤都是完美的匹配......我希望它更清晰......:/ – Railsana

+0

我最近的答案的最新版本可能就是它。如果不是,我放棄,對不起。 :) –

回答

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()到「主」查詢。

如果有人有一個想法如何在一個查詢內解決這個問題,請讓我知道!謝謝!

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') 

我猜測可能是不正確的,因爲我不完全理解你想要做什麼。不過,也許這會讓你更進一步。

+0

非常感謝,我添加了一個例子。 – Railsana

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 

所以,如果你有這些標籤:

conditional_tags = [賽車]

optional_tags = [2紅, 3輛奔馳,4速]

你可以這樣做:

Product.having_tags([1]).ordered_by_tag_count([2, 3, 4]) 
+0

實際上,這是行不通的,因爲'.joins'總是一個'LEFT JOIN'而不是'JOIN'。不過,至少可以讓你更接近解決方案。 –

+0

基本上,我認爲你需要編寫一個範圍FILTERS的標籤,另一個範圍的ORDERS標籤計數,然後鏈接這兩個範圍,就像我上面做的那樣。唯一的竅門是每個範圍都必須實際工作。 –

+0

謝謝你的努力。 Rails還將範圍組合到一個查詢中,所以它仍然失敗。另一件事:有產品標記[1,2,3],但他們不顯示: '... WHERE(tags.id IN(1))AND(tags.id IN(2,3) )GROUP BY products.id ORDER BY count_all DESC' – Railsana