执行子查询

perform subquery

本文关键字:查询 执行      更新时间:2023-10-16

文档:

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

我想查找({"_id":1},{"id":1,"list.lv":1}),但用附加条件限制{"list.lve":1{:"list.id=id"。这意味着我只想检索列表中第一个元素的"id"answers"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");

如果我有问题,请尝试这个本地聚合框架查询来完成您需要的内容:

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

让我更详细地解释一下。一开始过滤掉尽可能多的文档是很重要的。我们可以用第一个$匹配。请注意,如果我们在管道的末尾进行{"_id":1}筛选,mongo将无法为其使用索引。$unvent将把每个列表数组元素变成一个单独的文档。然后我们需要比较两个字段。除了$where之外,我不知道有什么简单的方法可以做到这一点,但我们不能将其与聚合框架一起使用。幸运的是,idlist.id都是数字,所以我们可以$从另一个中减去,看看它们是否相等,"equalsFlag":{"$减法":["$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");

希望它能有所帮助!