2014-09-01 80 views
1

Im堅持在rails中使用高級查詢。我需要一個在mongoid中工作的解決方案,如果可能的話還有活動記錄(可能不可能)。我在下面放了一個簡化的例子。Rails/mongoid:對陣列的高級查詢

考慮以下模型:

class Announcement 
    include Mongoid::Document 

    field :title, type: String 
    field :user_group, type: Array 
    field :year, type: Array 
    field :tags, type: Array 

    has_and_belongs_to_many :subjects 

    before_save :generate_tags 

    private 
    def generate_tags 
    tags = [] 
    if self.subjects.present? 
     self.subjects.each { |x| tags << x.name.downcase.gsub(" ", "_") } 
    end 

    if self.year.present? 
     self.year.each { |x| tags << "year_" + x.to_s } 
    end 

    self.tags = tags 
    end 
end 

鑑於文獻1的標籤陣列:

["hsc_mathematics", "hsc_chemistry", "year_9"] 

和文獻2:

和文獻3:

["hsc_mathematics", "hsc_chemistry", "year_9", "year_10"] 

和文件4:

["year_9", "year_10"] 

現在考慮下面的模式:

class Student < User 
    include Mongoid::Document 

    field :year, type: Integer 
    has_many :subjects 

    def announcements 
     tags = [] 
     if self.subjects.present? 
     self.subjects.each { |x| subjects << x.name.downcase.gsub(" ", "_") } 
     end 

     tags << "year_" + self.year.to_s 

     Announcement.where("user_group" => { "$in" => ["Student", "all_groups"]}).any_of({"tags" => { "$in" => tags }}, {tags: []}) 
    end 
end 

在我們的例子的目的,我們的學生有以下標籤:

[ "hsc_mathematics", "hsc_physics", "year_10" ] 

我的查詢不正確,因爲我想返回文檔2,3和4但不是文檔1.

我需要在返回公告時遵循以下查詢:

i。如果公告的主題標籤與任何主題相匹配

ii。如果公告在任何年份都有年份標籤匹配

iii。如果公告的年份和主題標籤在任何一年和任何主題上都匹配

我該怎麼寫呢?

編輯

我很高興今年打出我的標籤,但即時通訊仍然停留

Announcement.where("user_group" => { "$in" => ["Student", "all_groups"]}).any_of({"tags" => { "$in" => ["hsc_mathematics", "hsc_physics"] }}, {tags: []}).any_of({"year_at_school" => { "$in" => 10 }}, {year_at_school: []}) 
+0

你不會得到一個可以同時適用於AR和Mongoid的解決方案,它們對於所有的查詢都有完全不同的接口。爲什麼當他們有內部結構時,你把所有的標籤混合成一堆?爲什麼不更好地組織數據,以便以某種理智的方式查詢它? – 2014-09-01 05:43:37

+0

看我的編輯,我已經分出了我的年份標籤。查詢的第一個2/3僅適用於年份過濾。 – 2014-09-01 06:27:02

回答

2

因此,解決辦法是調整我的模型,並使用一個更有組織的查詢而不是一個完整標記銀行。

公告模型:

class Announcement 
    include Mongoid::Document 

    field :title, type: String 
    field :user_group, type: Array, default: [""] 
    field :year, type: Array, default: [""] 
    field :tags, type: Array, default: [""] 

    has_and_belongs_to_many :subjects 

    before_save :generate_tags 

    private 
    def generate_tags 
    tags = [] 
    if self.subjects.present? 
     self.subjects.each { |x| tags << x.name.downcase.gsub(" ", "_") } 
    end 

    self.tags = tags 
    end 
end 

用戶模型:

class Student < User 
    include Mongoid::Document 

    field :year, type: Integer 
    has_many :subjects 

    def announcements 
    year = "year_" + self.year.to_s 
     tags = [""] 
     if self.subjects.present? 
     self.subjects.each { |x| tags << x.name.downcase.gsub(" ", "_") } 
     end 

     Announcement.where("user_group" => { "$in" => ["Student", ""] }).and("year" => { "$in" => [year, ""]}).any_in(tags: tags).all.entries 
    end 
end 

編輯:下面有所述查詢的整潔版本所建議

該實施例還具有假設的到期字段無=永不過期

Announcement.where(:user_group.in => ["Student", ""], :year.in => [year, ""], :tags.in => tags).any_of({:expires_at.gte => Time.zone.now}, {:expires_at => nil}).all.entries 
+0

你應該可以用Mongoid來說'where(:user_group.in => [...])',我發現MongoDB想要使用的散列通常很混亂。 – 2014-09-02 01:32:55

+0

真棒,我會玩的。乾杯 – 2014-09-02 02:21:32