2014-02-09 9 views
1

документ:MongoDB - выполнить подзапрос

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

Я хочу, чтобы сделать поиск ({ "_ идентификатор": 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

Если я получил свой вопрос попробовать этот родной 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} фильтр в конце конвейера, манго не сможет использовать для него индекс. $unwind превратит каждый элемент массива списка в отдельный документ. Затем нам нужно сравнить два поля. Я не знаю, какой простой способ сделать это, кроме $where, но мы не можем использовать его с общей структурой. К счастью, оба id и list.id являются числовыми, поэтому мы можем $ вычесть один из другого, чтобы убедиться, что они равны, "equalsFlag": {"$ subtract": ["$ id", "$ list. Я бы"]} . Если они есть, equalsFlag будет 0. Поэтому мы просто добавляем новый $ матч, чтобы получить документы, где id = list.id и, наконец, опустить поле equalsFlag из результатов, у нас есть еще один $ project.

Я не парень C++, но я уверен, что драйвер C++ поддерживает агрегированную инфраструктуру как большинство других драйверов. Так что просто Google некоторые примеры для преобразования этого родного запроса в C++. Это должно быть довольно легко, по крайней мере, это верно для C#.

EDIT: 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"); 

Надеется, что это помогает!

+0

Работает. И я также добавляю код кода C++ в свой вопрос. – jean

+0

Несомненно. Готово! –

Смежные вопросы