2012-04-21 32 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 }) } 

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