这是一个聚合框架的答案。请注意,第一个 $match 在集合级别过滤文档并使用 $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