2012-09-07 142 views
3

我有一種情況,我需要從mongo返回一個對象集合,但需要使用兩個查詢來獲得結果。這些結果的順序很重要,因爲它們是分頁的。聯盟兩個mongo結果

這是第一個查詢:(基於類別和價格範圍清單)

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條記錄,正如預期的那樣,記錄中有52條記錄在everything_else中)。

.all應用於我在評論中提到的查詢時,不會產生任何影響。一個puts listings.inspect結果

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> 

然而,listings.count不會導致48。我是否錯過了合併這些結果的一些愚蠢的簡單方法?一旦我在一個系列中獲得了結果,這將如何影響後續的分頁功能。我正在使用kaminari進行分頁。

更新2

每下面的答案和我自己的摸索,我發現to_a是一個解決方案,但不是一個理想的一個。這確實功能:

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

這使得通過雷分頁必須改變,因爲我們不再與蒙戈標準的工作,而是一個標準的數組。這裏是新的分頁方法:

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

有100條記錄一個小數據集工作,這是罰款和花花公子 - 54ms

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

然而,使用更大的數據集我看到顯著較慢的時候,使用.to_a方法來組合這些。雖然這些例子並不完全適用於蘋果,但這個大的差異指向的問題是to_a返回所有內容,迫使Kaminari使用更多的實際數據:

我的結果沒有to_a,只是返回所有記錄應用標準 - 15ms的

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

我的結果與to_a,合併兩個結果 - 415ms

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

總之,這不是一個有效的選項。即使對於大數據集,也要分別返回每個數據集15ms,所以我認爲我需要完成的是將標準合併在一起,以便針對Mongo運行單個查詢,從而允許分頁發生在分貝上是。

在SQL我會做一些大致是

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

是否有可能做到這一點蒙戈?

+0

你是什麼意思你的問題的一部分?你會得到不完整的結果嗎? 你只有列表嗎?是這樣嗎? 請詳細說明這裏有什麼問題? –

+0

在Active Record中觸發執行的解決方案是使用.all函數。 只需在查詢後添加'.all',它們將在那裏執行,並且不會有延遲加載。 –

回答

3

也許您可以創建一個類來封裝有關如何爲特定數組檢索數據的詳細信息,並且通過使用Mongo驅動程序,您可以跳過並限制查詢選項以減少傳輸的數據大小。

使用這種方法,你可以使用這樣的事情(namings不是很好,我沒有測試的代碼,但你會走點):

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

這可能是粗暴的方式做到這一點,但:

# 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) 

這是你想要的嗎?我在我的一個mongoid模型上嘗試過它,並且似乎以這種方式工作。

PS:但.to_a的性能受到影響 - 整個結果集被提取併合並。但看看你提到的記錄數量(~50張),應該沒問題。

+0

這與我提出的解決方案非常相似。唯一的區別是我使用了一個Array union vs flatten - results =(listing | 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)