mongodb - 执行子查询

时间:2014-02-09 16:07:14

标签: c++ mongodb

文件:

   { "_id":1, "id":1, "list" : [ { "lv" : 1 , "id":1}, {"lv" : 2 , "id":2} ] }

我想找到({“_ id”:1},{“id”:1,“list.lv”:1})但限制{“list.lv”:1}并附加条件:“list .id = id“。这意味着我只想检索列表中第一个元素的“id”和“list.lv”部分,因为它的“list.id”==“id”== 1

通常是代码中提供的条件值,但在此示例中,值在文档中。 SQL通过子查询或连接表来完成此操作。 mongodb是否在单个查询中支持此功能?以及如何用c ++驱动程序编写它?

根据回答,添加c ++代码:

mongo::BSONObj res;
std::vector<mongo::BSONObj> pipeline;
pipeline.push_back(BSON("$match"<<BSON("_id"<<1)));
pipeline.push_back(BSON("$unwind"<<"$list"));
mongo::BSONArrayBuilder ab;
ab<<"$id"<<"$list.id";
pipeline.push_back(BSON("$project"<<BSON("id"<<1<<"list.lv"<<1<<"equalsFlag"<<BSON("$subtract"<<ab.arr()))));
pipeline.push_back(BSON("$match"<<BSON("equalsFlag"<<0)));
pipeline.push_back(BSON("$project"<<BSON("id"<<1<<"list.lv"<<1)));
conn->runCommand("db_name", BSON( "aggregate" << "collection_name" << "pipeline" << pipeline ), res);
std::cout<<res["result"].Array()[0].Obj().getObjectField("list").getIntField("lv");

1 个答案:

答案 0 :(得分:1)

如果我向您提问,请尝试使用此原生aggregate framework查询来完成您所需的操作:

db.collectionName.aggregate(
{"$match" : {"_id" : 1 }}, 
{"$unwind" : "$list"}, 
{"$project" : {"id":1, "list.lv" : 1, "equalsFlag" : {"$subtract" : ["$id", "$list.id"]}}}, 
{"$match" : {"equalsFlag" : 0}}, 
{"$project" : {"id": 1, "list.lv" : 1}})

让我更详细地解释一下。尽可能多地过滤掉尽可能多的文档非常重要。我们可以使用第一个$match来完成。请注意,如果我们执行{“_ id”:1}在管道末尾过滤mongo将无法使用索引。 $unwind会将每个列表数组元素转换为单独的文档。然后我们需要比较两个字段。除了$where之外,我不知道有什么简单的方法可以做到这一点,但是我们不能将它用于聚合框架。幸运的是, id list.id 都是数字的,所以我们可以 $减去一个来查看它们是否相等,“equalsFlag”:{ “$ subtract”:[“$ id”,“$ list.id”]}。如果是, equalsFlag 将为0.所以我们只需添加一个新的 $ match 来获取 id = list.id 的文档,最后到从结果中省略equalsFlag字段我们还有一个$ project。

我不是C ++人,但我确信C ++驱动程序支持聚合框架作为大多数其他驱动程序。因此,只需谷歌一些示例将此本机查询转换为C ++查询。这应该相当容易,至少C#是真的。

编辑:来自jean的C ++代码来完成答案

mongo::BSONObj res;
std::vector<mongo::BSONObj> pipeline;
pipeline.push_back(BSON("$match"<<BSON("_id"<<1)));
pipeline.push_back(BSON("$unwind"<<"$list"));
mongo::BSONArrayBuilder ab;
ab<<"$id"<<"$list.id";
pipeline.push_back(BSON("$project"<<BSON("id"<<1<<"list.lv"<<1<<"equalsFlag"<<BSON("$subtract"<<ab.arr()))));
pipeline.push_back(BSON("$match"<<BSON("equalsFlag"<<0)));
pipeline.push_back(BSON("$project"<<BSON("id"<<1<<"list.lv"<<1)));
conn->runCommand("db_name", BSON( "aggregate" << "collection_name" << "pipeline" << pipeline ), res);
std::cout<<res["result"].Array()[0].Obj().getObjectField("list").getIntField("lv");

希望它有所帮助!