2012-04-21 28 views
8

Tôi có phạm vi sau đây được định nghĩa trong mô hình của tôi:Làm thế nào để kết hợp hai tiêu chuẩn khác nhau 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) 
} 

Tôi muốn tạo ra một phạm vi kết hợp các kết quả của cả hai trong những phạm vi được gọi là hiện tại. Tôi đã thử một cái gì đó như thế này:

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

Nhưng điều này chỉ kết thúc điều trị cả hai như mảng và ghép chúng. Vấn đề ở đây là khi tôi cố gắng gọi phạm vi của tôi với Model.current, tôi nhận được thông báo lỗi sau:

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

này là bởi vì nó chuyển đổi Tiêu chuẩn Mongoid phản đối một mảng, nhưng tôi không muốn điều đó. Tôi muốn đối tượng ở lại như một đối tượng Mongoid Criteria.

Điều tôi thực sự muốn là liên minh của tập hợp in_progress và bộ sắp tới.

Bất kỳ ý tưởng nào? Cảm ơn.

+1

Nếu bạn muốn kết hợp hai tập hợp kết quả thì bạn có thể viết tốt hơn phạm vi thứ ba từ đầu bằng truy vấn ': $ hoặc'. –

Trả lời

6

Bạn có thể cố gắng soạn tiêu chí của mình bằng cách sử dụng các phương thức truy vấn của Mongoid và dereferencing vào bộ chọn của tiêu chí, nhưng tôi không nhất thiết phải đề xuất điều này - xem bên dưới để biết ví dụ. Tôi thứ hai đề nghị để tạo ra phạm vi thứ ba của bạn. Hãy nhớ rằng các phạm vi này tương ứng với các truy vấn db mà bạn muốn có hiệu quả, vì vậy nó có lẽ đáng để bạn kiểm tra và hiểu các truy vấn MongoDB kết quả và cơ bản được tạo ra.

Mẫu

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 

thử nghiệm

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

Việc sử dụng 'any_of' làm việc cho tôi, cảm ơn! – josal

2

Bạn có để lập bản đồ Mảng của bạn trở lại một Mongoid :: Tiêu chuẩn. Bất kỳ mảng của bạn có thể được dịch sang một tiêu chí với any_in:

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

Vì vậy, một cái gì đó như thế này nên làm như lừa: (chưa được kiểm tra)

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

Tôi hy vọng tồn tại giải pháp tốt hơn, nhưng điều này giải phương trình ít nhất.

Các vấn đề liên quan