2012-04-21 66 views
8

我在我的模型中定義了以下範圍:如何聯合兩個不同的Mongoid標準

scope :upcoming, -> { where(:start_time.gt => Time.now).asc(:start_time) } 
scope :in_progress, -> { 
    now = Time.now 
    where(:start_time.lte => now).where(:end_time.gte => now).asc(:start_time) 
} 

我想創造一種結合了那些所謂的電流範圍的結果另一個範圍。我試過這樣的事情:

scope :current, -> { self.in_progress | self.upcoming } 

但是,這只是最終將它們視爲數組並將它們連接起來。這樣做的問題是,當我嘗試打電話給我的Model.current範圍內,我收到以下錯誤信息:

NoMethodError: undefined method `as_conditions' for #<Array:0xaceb008> 

這是因爲轉換的Mongoid Criteria對象到一個數組,但我不想要那個。我希望對象保持爲一個Mongoid Criteria對象。

我真正想要的是in_progress集合和即將到來的集合的結合。

任何想法?謝謝。

+1

如果你想要兩個結果集的聯合,那麼你最好使用':$或'查詢從頭開始編寫第三個作用域。 – 2012-04-21 05:26:26

回答

6

你可以嘗試使用Mongoid的查詢方法和取消引用到條件的選擇器來編寫你的條件,但我不一定會推薦這個 - 見下面的例子。我第二個建議,以制定你的第三個範圍。請記住,這些範圍對應於您希望高效的db查詢,因此您可能有必要花時間來檢查和理解生成的生成的和潛在的MongoDB查詢。

型號

class Episode 
    include Mongoid::Document 
    field :name, type: String 
    field :start_time, type: Time 
    field :end_time, type: Time 

    scope :upcoming, -> { where(:start_time.gt => Time.now).asc(:start_time) } 
    scope :in_progress, -> { 
    now = Time.now 
    where(:start_time.lte => now).where(:end_time.gte => now).asc(:start_time) 
    } 
    scope :current, -> { any_of([upcoming.selector, in_progress.selector]) } 
    scope :current_simpler, -> { where(:end_time.gte => Time.now) } 
end 

測試

require 'test_helper' 

class EpisodeTest < ActiveSupport::TestCase 
    def setup 
    Episode.delete_all 
    end 

    test "scope composition" do 
    #p Episode.in_progress 
    #p Episode.upcoming 
    #p Episode.current 
    #p Episode.current_simpler 

    in_progress_name = 'In Progress' 
    upcoming_name = 'Upcoming' 
    Episode.create(:name => in_progress_name, :start_time => Time.now, :end_time => 1.hour.from_now) 
    Episode.create(:name => upcoming_name, :start_time => 1.hour.from_now, :end_time => 2.hours.from_now) 

    assert_equal([in_progress_name], Episode.in_progress.to_a.map(&:name)) 
    assert_equal([upcoming_name], Episode.upcoming.to_a.map(&:name)) 
    assert_equal([in_progress_name, upcoming_name], Episode.current.to_a.map(&:name)) 
    assert_equal([in_progress_name, upcoming_name], Episode.current_simpler.to_a.map(&:name)) 
    end 
end 
+0

使用'any_of'爲我工作,謝謝! – josal 2014-10-10 14:47:01

2

你有你的陣圖回Mongoid ::標準。 您的任何陣列可以被轉換成一個標準與any_in:

scope :has_data, -> { any_in(:_id => all.select{ |record| record.data.size > 0 }.map{ |r| r.id }) } 

所以,這樣的事情應該做的伎倆:(未經測試)

scope :current, -> { any_in(:_id => (self.in_progress + self.upcoming).map{ |r| r.id }) } 

我希望存在更好的解決方案,但是這至少解決方程式。