2013-09-16 33 views
2

我想弄清楚某些類型的文章的數量。我有一個非常低效的查詢:ActiveRecord查詢數組交集?

Article.where(status: 'Finished').select{|x| x.tags & Article::EXPERT_TAGS}.size

在我的追求成爲一個更好的程序員,我不知道如何使這個更快的查詢。 tags是一個字符串在Article陣列,並且Article::EXPERT_TAGS是字符串的另一個陣列。我想找到數組的交集,並得到結果記錄數。編輯:Article::EXPERT_TAGSarticle.tags定義爲Mongo數組。這些數組包含字符串,我相信它們是序列化的字符串。例如:Article.first.tags = ["Guest Writer", "News Article", "Press Release"]。不幸的是,這不是作爲一個單獨的標籤表正確設置的。

第二次編輯:我使用的是MongoDB,所以實際上它使用MongoMapper或mongoid等MongoWrapper,而不是ActiveRecord。這是我的錯誤,對不起!由於這個錯誤,它把這個問題的分析搞砸了。感謝PinnyM指出錯誤!

+0

如何被存儲在數據庫中的這個陣列串 - 作爲一個單獨的表(表模式,請)或Array場?你在用什麼DBMS? – PinnyM

+1

我看起來約翰通過序列化數組來存儲'tags'列表(@John,請保持誠實) –

+0

這是作爲一個數組存儲在MongoDB中的一個列中,而不是一個單獨的表(這將使回顧過程中的生活變得更容易)。 – John

回答

0

假設整個tags列表存儲在一個單一的數據庫字段,要保持這種方式,我沒有看到很大的改進範圍,因爲你需要的所有數據進入紅寶石進行處理。

然而,有一個問題,您的數據庫查詢

Article.where(status: 'Finished') 

# This translates into the following query 
SELECT * FROM articles WHERE status = 'Finished' 

從本質上講,你獲取的所有列,而您只需要爲您的工藝tags列。所以,你可以使用pluck這樣的:

Article.where(status: 'Finished').pluck(:tags) 

# This translates into the following query 
SELECT tags FROM articles WHERE status = 'Finished' 
+0

ActiveRecord內置支持將'Array'和'Hash'序列化爲一個列。如果爲'tags'定義了一個'text'列,並且分配了'tags = @ your_array',它將被序列化並保存到數據庫中,當您查詢記錄時,它將被反序列化爲一個'Array'對象。例如,看到這個SO線程,http://stackoverflow.com/questions/6694432/using-rails-serialize-to-save-hash-to-database –

0

我回答了有關像ActiveRecord的here查詢一般路口的問題。

下面提取:


以下是我使用用於構造之類的查詢相交在ActiveRecord的一般方法:

class Service < ActiveRecord::Base 
    belongs_to :person 

    def self.with_types(*types) 
    where(service_type: types) 
    end 
end 

class City < ActiveRecord::Base 
    has_and_belongs_to_many :services 
    has_many :people, inverse_of: :city 
end 

class Person < ActiveRecord::Base 
    belongs_to :city, inverse_of: :people 

    def self.with_cities(cities) 
    where(city_id: cities) 
    end 

    # intersection like query 
    def self.with_all_service_types(*types) 
    types.map { |t| 
     joins(:services).merge(Service.with_types t).select(:id) 
    }.reduce(scoped) { |scope, subquery| 
     scope.where(id: subquery) 
    } 
    end 
end 

Person.with_all_service_types(1, 2) 
Person.with_all_service_types(1, 2).with_cities(City.where(name: 'Gold Coast')) 

它將產生以下形式的SQL:

SELECT "people".* 
    FROM "people" 
WHERE "people"."id" in (SELECT "people"."id" FROM ...) 
    AND "people"."id" in (SELECT ...) 
    AND ... 

您可以根據需要使用上述方法創建任意數量的子查詢條件/連接等,只要每個子查詢返回其結果集中匹配人員的ID。

每個子查詢結果集都將AND'在一起,從而將匹配集限制爲所有子查詢的交集。