2013-10-11 199 views
1

我有一個文件代表嵌入許多房間的房子。結構是這樣的。複雜的MongoDB查詢聚合

{ 
    description: 'House' 
    total_price: 1000, 
    rooms: [{ 
    description: 'Small Single Room', 
    type: single, 
    available: true, 
    price: 300 
    }, { 
    description: 'Big Single Room', 
    type: single, 
    price: 400, 
    available: true 
    }, { 
    description: 'Another Room', 
    type: single, 
    price: 300, 
    available: true 
    }] 
} 

我有難的時間來解決這個問題:我怎樣才能得到具有的700

總價要做到這一點,我需要接下來可用單間房屋全部。

  • 設置條件上的一些嵌入文檔屬性
  • 設置條件上的可用的嵌入式客房總和
  • 設置條件的總和

目前我正在努力瞭解如何做到這一點。我一直在尋找aggregate和其他方法,但我找不到工作解決方案。

非常感謝。

+0

這是一個數組。我糾正了它。臥室是一系列嵌入式文件。 –

+0

關鍵'房間'應該是數組。類似於:'{description:'House',價格:1000,rooms:[{},{}]}' –

+0

「可用單間,總價格爲700」 - > *精確* 700,*至少* 700或*超過* 700? – Philipp

回答

0

以下是您可以使用的一種方法。將剩餘房間和剩餘價格保存在根級別(以總價格和總房間初始化)。無論何時您將某個房間的可用空間設置爲false,都會從remaining_price和remaining_rooms中減去價格並計數。

{ 
    description: 'House' 
    total_price: 1000, 
    remaining_price: 700, 
    remaining_rooms: 2, 
    rooms: [{ 
    description: 'Small Single Room', 
    type: single, 
    available: false, 
    price: 300 
    }, { 
    description: 'Big Single Room', 
    type: single, 
    price: 400, 
    available: true 
    }, { 
    description: 'Another Room', 
    type: single, 
    price: 300, 
    available: true 
    }] 
} 

現在,你可以簡單地查詢你想使用的房間(我用mongoid,你可以不管你使用的是轉換爲書面查詢):

House.where(:remaining_price.lte => 700, :remaining_rooms.gte => 2).to_a

0

下面是一個聚合框架回答。 請注意,第一個$匹配篩選集合級別爲 的文檔,並使用$ elemMatch來匹配數組元素的類型和可用性。 爲了完成房屋可用房間價格的總和, 不可用的房間必然被過濾掉並丟失。 $ group階段的添加字段保留用於查看的數據, 但您的應用可能更適合通過_id獲取完整文檔。

希望這回答您的問題原來的意圖 並演示聚合框架的力量。

測試/單元/ house_test.rb

require 'test_helper' 
require 'pp' 

class HouseTest < ActiveSupport::TestCase 
    def setup 
    House.delete_all 
    end 

    test "complex aggregate query" do 
    puts "\nMongoid::VERSION:#{Mongoid::VERSION}\nMoped::VERSION:#{Moped::VERSION}" 
    total_price_limit = 700 
    pipeline = [ 
     {'$match' => {'rooms' => {'$elemMatch' => {'type' => 'single', 'available' => true}}}}, 
     {'$unwind' => "$rooms"}, 
     {'$match' => {'rooms.available' => true}}, 
     {'$group' => { 
      '_id' => '$_id', 
      'description' => {'$last' => '$description'}, 
      'total_price_available' => {'$sum' => '$rooms.price'}, 
      'rooms' => {'$push' => '$rooms'}, 
     } 
     }, 
     {'$match' => {'total_price_available' => {'$lte' => total_price_limit}}}, 
     {'$sort' => {'total_price_available' => 1}}, 
    ] 
    docs = [ 
     { 
      description: 'House 1', 
      total_price: 1000, 
      rooms: [{ 
         description: 'Small Single Room', 
         type: 'single', 
         available: true, 
         price: 300 
        }, { 
         description: 'Big Single Room', 
         type: 'single', 
         price: 400, 
         available: true 
        }, { 
         description: 'Another Room', 
         type: 'single', 
         price: 300, 
         available: true 
        }] 
     }, 
     { 
      description: 'House 2', 
      total_price: 600, 
      rooms: [{ 
         description: 'Small Single Room', 
         type: 'single', 
         available: true, 
         price: 300 
        }, { 
         description: 'Big Single Room', 
         type: 'single', 
         price: 400, 
         available: false 
        }, { 
         description: 'Another Room', 
         type: 'single', 
         price: 300, 
         available: true 
        }] 
     } 
    ] 
    docs.each { |house| House.create(house) } 
    pp House.collection.aggregate(pipeline) 
    end 
end 

$耙測試

Run options: 

# Running tests: 

[1/1] HouseTest#test_complex_aggregate_query 
Mongoid::VERSION:3.1.5 
Moped::VERSION:1.5.1 
[{"_id"=>"5272dbe2e4d30b7e0a000002", 
    "description"=>"House 2", 
    "total_price_available"=>600, 
    "rooms"=> 
    [{"description"=>"Small Single Room", 
    "type"=>"single", 
    "available"=>true, 
    "price"=>300}, 
    {"description"=>"Another Room", 
    "type"=>"single", 
    "price"=>300, 
    "available"=>true}]}] 
Finished tests in 0.046359s, 21.5708 tests/s, 0.0000 assertions/s. 
1 tests, 0 assertions, 0 failures, 0 errors, 0 skips