2015-06-19 70 views
0

我想用ruby让所有孩子的名字,在MongoDB的集合中是过滤器元件与红宝石

集合中的元素是这样的:

[ 
{ "name" => "John", 
    "children" => [{"genre" => "male", "name" => "Rick"}, 
        {"genre" => "female", "name" => "Mary"} 
       ] 
}, 
{ "name" => "Richard", 
    "children" => [{"genre" => "female", "name" => "Vicky"}, 
        {"genre" => "female", "name" => "Mary"} 
       ] 
}] 

当我执行:

collection.find({"children" => {"genre" => "female"}}) 

我得到一个Mongo::OperationTimeout: Timed out waiting on socket read.

此外,我不希望所有父母的名单,但只有不同的女性儿童名单。

如果我使用纯Ruby,我可以做到这一点:

collection.find({}).map { |d| 
    d["doc"]["children"].select { |rh| 
     rh["genre"] == "female" 
    }.map { |r| 
     r["name"] 
    } 
}.flatten.uniq 

但我有几百万的条目并采取了很多的时间。 Mongodb肯定有办法在本地返回这个结果。

+0

你应该实际工作中尝试定义[命名范围(http://mongoid.org/en/mongoid/docs/querying。 HTML#范围)在您的模型。 –

+0

我不使用mongoid。我正在使用'mongo' gem来直接连接到mongodb –

回答

-1

如果查询需要很长时间,您可以尝试更改mongo驱动程序和https://github.com/mongodb/mongo-ruby-driver/blob/master/lib/mongo/socket上的套接字超时连接/tcp.rb和mongo查询超时选项http://docs.mongodb.org/manual/reference/method/cursor.addOption/,或尝试使用查询的skip()和limit选项。

0

我不能说你得到了套接字超时任何东西,但此查询:

collection.find({"children" => {"genre" => "female"}}) 

不给你所期望的。它会检查子字段和给定散列之间的确切平等。执行此查询的正确方法是:

collection.find("children.genre" => "female") 

但它仍然找到至少有一个女孩的所有父母。这些父母的男性孩子也包含在这个视图中,你必须在得到结果后对它们进行过滤。

或者,你可以用骨料的整体选择():

collection.aggregate([ 
    {:$unwind => '$children'}, 
    {:$match => {'children.genre' => 'female'}}, 
    {:$group => {_id: '$children'}} 
]).map { |c| c[:_id] }