2012-09-07 2 views
3

문고리에서 객체의 단일 모음을 반환해야하지만 두 개의 검색어를 사용하여 결과를 가져와야하는 상황이 있습니다. 이러한 결과의 순서는 페이지 매김을하기 때문에 중요합니다.연합 2 문법 결과

여기서 제 쿼리 (카테고리와 가격대에 기초하여 목록)

my_listings = MoListing.where(criteria_a) 

번째 쿼리 필터로서 제 쿼리의 결과를 사용할 필요가있다. 그래서 뭔가 같은 :

everything_else = MoListing.where(criteria_b) 

그리고 노동 조합 결과 :

my_listings << everything_else 

그리고 마지막으로, 페이지가 매겨진 결과를 반환은 :

my_listings.page(1).per(25) 

내 문제의 일부가 몽고 쿼리가 아닌 것 같다 필요할 때까지 실행됩니다. 특정 시점에 쿼리 실행을 트리거 할 수있는 방법이 있습니까? 아니면이 결과 집합을 작성하는 데 또 다른 방법을 사용해야합니까? 더 많은 정보

제가 보는 동작과

업데이트는 어떤 반환됩니다 것은 listings 단지 결과 것입니다. 또한 everything_else에는 예상 레코드 (my_listings에 48 레코드, 예상대로 everything_else에 52 레코드)가 포함되어 있음을 확인했습니다.

의견에 언급 된대로 .all을 (를) 쿼리에 적용하면 아무런 영향이 없습니다.

10:57:00 web.1 | #<Mongoid::Criteria 
10:57:00 web.1 |   selector: {"price"=>{"$gte"=>25, "$lte"=>75}}, 
10:57:00 web.1 |   options: {}, 
10:57:00 web.1 |   class: MoListing, 
10:57:00 web.1 |   embedded: false> 

에서 puts listings.inspect 결과는하지만, listings.count48 결과 않습니다. 이 결과를 병합하는 어리석은 간단한 방법을 놓치고 있습니까? 그리고 하나의 콜렉션에서 결과를 얻으면, 다음에 오는 페이지 매김 함수에 어떻게 영향을 미칩니 까? 페이징에 kaminari을 사용하고 있습니다.

아래 답변을 내 자신의 시행 착오 당 2

업데이트는, 나는 해결책 있지만 이상적인 하나가 될 to_a 발견했습니다. 대신 표준 배열을

#merge the results together as an Array 
results = (listings.to_a | everything_else.to_a) 

이것은 우리가 더 이상 몽고 기준으로 작업에 따라 변경되지해야 할 미나리를 통해 매김을 야기하지만,이 기능은 않습니다. 여기에 새로운 페이지 매김 방법이다 : - 나는 상당히 느린 시간 때를보고 있어요 큰 데이터 세트를 사용하여, 그러나 54ms

"debug":{"success":true,"pre_render_duration":54.808775999999995,"overall_duration":86.36554100000001,"count":25},"pagination":{"total_pages":4,"current_page":1}} 

Kaminari.paginate_array(results).page(page).per(per_page) 

(100 개) 기록의 작은 데이터 세트로 작업이 벌금과 멋쟁이 .to_a 메서드를 사용하여 이들을 결합합니다.이 예제는 사과에 대한 사과가 아니지만이 큰 차이점은 모든 것을 반환하는 to_a 문제와 관련이 있습니다. 카미나리는 더 많은 실제 데이터로 작업해야합니다 :

to_a가없는 나의 결과는 모든 레코드를 적용 기준 - 15ms의 두 결과 집합을 병합 to_a와

"debug":{"success":true,"pre_render_duration":15.107164,"overall_duration":18.267599,"count":25},"pagination":{"total_pages":81,"current_page":1}} 

내 결과, - 415ms

"debug":{"success":true,"pre_render_duration":415.258199,"overall_duration":450.66537800000003,"count":25},"pagination":{"total_pages":81,"current_page":1}} 

가 요약하면, 이것은 유효한 옵션이 아닙니다. 개별 데이터 집합을 개별적으로 반환하면큰 데이터 집합도 15ms 걸립니다. 그래서 성취해야 할 것은 조건을 함께 병합하여 단일 쿼리가 Mongo에 대해 실행되어 DB에서 페이지 매김이 발생할 수 있도록하는 것입니다. 있다.

는 SQL에서 나는 약

같은
select 
    * 
from 
    listings 
where 
    field = "blah" 
union all 
select 
    * 
from 
    listings 
where 
    field <> "blah" 

가 몽고에서이 작업을 수행하는 것이 가능 할 것?

# Let us say the listings is obtained using listing_query_params 
listings = MoListing.where(listing_query_params) 

# and everything else is from everything_else_query_params 
everything_else = MoListing.where(everything_else_query_params) 

results = [listings.to_a, everything_else.to_a].flatten 

results.page(1).per(25) 

이 당신이 원하는 무엇인가 :

+0

문제의 일부를 의미합니까? 불완전한 결과가 있습니까? 목록 만 제공합니까 ?? 그래? 여기에서 문제가 무엇인지 자세히 설명해 주시겠습니까? –

+0

액티브 레코드에서 트리거 실행은 .all 함수를 사용합니다. 쿼리 뒤에'.all'을 추가하면 거기에서 실행될 것이고 지연로드는 없을 것입니다. –

답변

3

아마도 특정 배열에 대해 데이터를 검색하는 방법에 대한 세부 정보를 캡슐화하는 클래스를 만들고 Mongo 드라이버를 사용하여 전송 된 데이터 크기를 줄이기 위해 쿼리 옵션을 건너 뛰고 제한 할 수 있습니다. 이 방법을 사용

, 당신은 다음과 같이 사용할 수 있습니다 (인 이름을 잘 못을 그리고 난 코드를 테스트 didnt한다, 그러나 당신은 점 할게요) :

class MoListingDataRetriever 
    def initialize(page_size) 
    @page_size = page_size/2 #since you'll have two queries 
    driver_instance = MoListing.db #just an exemple. You could use any of your classes that are mongo documents to do this 
    @collection_driver = driver_instance.collection("mo_listing") #or whatever you collection name is on mongo 
    end 

    def retrieve_mo_listings(query_param_a, query_param_b, current_page) 
    query_options = { 
     limit: @page_size, 
     page: current_page, 
     skip: (@page_size * (current_page - 1)) #to skip a number of records already retrieved from the query 
    } 
    results_from_query_a = @driver_instance.find(query_param_a, query_options) 
    results_from_query_b = @driver_instance.find(query_param_a, query_options) 
    results_from_query_b.to_a.concat(results_from_query_b.to_a)  
    end 
end 
+0

이것은 결국 궁극적으로 대답이되었습니다.페이징에 Kaminari를 사용하는 대신, 필자는 자신의 롤을 굴려서 결과 세트에서 레코드가 필요한지를 판단해야했습니다. 이상적은 아니지만 작동하며 비교적 빠릅니다. –

2

이 비록 그것을 할 원유 방법이 될 수 있는가? 나는 몽고이드 모델 중 하나에서이 방법을 시도해 보았습니다.

추신 : 그러나 .to_a는 성능에 문제가 있습니다. 전체 결과 집합을 가져 와서 병합합니다. 그러나 레코드 수 (~ 50 개)를 살펴보면 괜찮을 것입니다.

+0

이것은 내가 생각해 낸 해결책과도 매우 비슷합니다. 유일한 차이점은 Array 유니온과 flatten - results = (listings | everything_else)를 사용했다는 것입니다. 이것은 Kaminari가 작동하는 방식에 영향을 미쳤으므로 더 많은 테스트를 거친 후에 자세한 내용을 설명하는 내용으로 게시물을 업데이트 할 것입니다. 또한 실제 사용은 1000 개의 레코드를 사용하므로 성능에 대한 좋은 점을 제기합니다. 나는 더 많은 데이터를 가지고이 대답을 옳은 것으로 표기하고 현상금을 수여하기 전에 여전히 받아 들일 수 있는지 알아보기 위해 테스트 할 것입니다. .to_a보다 나은 해결책이있는 것처럼 보입니다. –

+0

이 질문에 대한 나의 답변이 원래 질문에 추가되었습니다. –

+0

나는 매우 잘 쓰여졌을 것이다. 'results = MoListing.any_of (listing_query_params, everything_else_query_params)' 그러나 결과의 순서가 필요했기 때문에 동일한 쿼리에서도 순서를 지정하는 방법을 알 수 없었다. – Suren

0

을이 시도 :

my_listings = MoListing.where(criteria_a) 
everything_else = MoListing.where(criteria_b) 
all_listings = MoListing.or(my_listings.selector).or(everything_else.selector).page(1).per(25)