[英]Query nested BSON documents with mongo c++ driver
我有一个bsoncxx::document::view bsonObjView
和一个std::vector<std::string> path
,表示我们在 BSON 文档中搜索的值的键(第一个键是顶级,第二个键是深度 1 、第三键深度 2 等)。
我正在尝试编写一个给定路径的函数,它将搜索 bson 文档:
bsoncxx::document::element deepFieldAccess(bsoncxx::document::view bsonObj, const std::vector<std::string>& path) {
assert (!path.empty());
// for each key, find the corresponding value at the current depth, next keys will search the value (document) we found at the current depth
for (auto const& currKey: path) {
// get value for currKey
bsonObj = bsonObj.find(currKey);
}
// for every key in the path we found a value at the appropriate level, we return the final value we found with the final key
return bsonObj;
}
如何让功能发挥作用? bsonObj
应该是什么类型以允许在循环中进行此类搜索? 另外,如何检查是否找到了currKey
的值?
另外,是否有一些内置的bsoncxx方法来做到这一点?
这是一个示例 json 文档,后跟一些指向其中的值的路径。 当给定路径时,最终的解决方案应该返回相应的值:
{
"shopper": {
"Id": "4973860941232342",
"Context": {
"CollapseOrderItems": false,
"IsTest": false
}
},
"SelfIdentifiersData": {
"SelfIdentifierData": [
{
"SelfIdentifierType": {
"SelfIdentifierType": "111"
}
},
{
"SelfIdentifierType": {
"SelfIdentifierType": "2222"
}
}
]
}
}
示例路径:
路径[ shopper -> Id -> targetValue ]
指向字符串"4973860941232342"
。
路径[ SelfIdentifiersData -> SelfIdentifierData -> array_idx: 0 -> targetValue ]
指向对象{ "SelfIdentifierType": { "SelfIdentifierType": "111" } }
。
路径[ SelfIdentifiersData -> SelfIdentifierData -> array_idx: 0 -> SelfIdentifierType -> targetValue ]
指向对象{ "SelfIdentifierType": "111" }
。
路径[ SelfIdentifiersData -> SelfIdentifierData -> array_idx: 0 -> SelfIdentifierType -> SelfIdentifierType -> targetValue ]
指向字符串"111"
。
请注意,路径的类型为std::vector<std::string> path
。 所以最终的解决方案应该返回路径指向的值。 它应该适用于任意深度,也适用于指向数组元素(第二个示例路径)和 THROUGH 数组元素(最后两个示例路径)的路径。 我们假设索引i
处的数组元素的键是"i"
。
#include <iostream>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
std::string turnQueryResultIntoString3(bsoncxx::document::element queryResult) {
// check if no result for this query was found
if (!queryResult) {
return "[NO QUERY RESULT]";
}
// hax
bsoncxx::builder::basic::document basic_builder{};
basic_builder.append(bsoncxx::builder::basic::kvp("Your Query Result is the following value ", queryResult.get_value()));
std::string rawResult = bsoncxx::to_json(basic_builder.view());
std::string frontPartRemoved = rawResult.substr(rawResult.find(":") + 2);
std::string backPartRemoved = frontPartRemoved.substr(0, frontPartRemoved.size() - 2);
return backPartRemoved;
}
// TODO this currently fails for paths with array indices
bsoncxx::document::element deepFieldAccess3(bsoncxx::document::view bsonObj, const std::vector<std::string>& path) {
if (path.empty())
return {};
auto keysIter = path.begin();
const auto keysEnd = path.end();
std::string currKey = *keysIter; // for debug purposes
std::cout << "Current key: " << currKey;
auto currElement = bsonObj[*(keysIter++)];
std::string currElementAsString = turnQueryResultIntoString3(currElement); // for debug purposes
std::cout << " Query result for this key: " << currElementAsString << std::endl;
while (currElement && (keysIter != keysEnd)) {
currKey = *keysIter;
std::cout << "Current key: " << currKey;
currElement = currElement[*(keysIter++)];
currElementAsString = turnQueryResultIntoString3(currElement);
std::cout << " Query result for this key: " << currElementAsString << std::endl;
}
return currElement;
}
// execute this function to see that queries with array indices fail
void reproduceIssue() {
std::string testJson = "{\n"
" \"shopper\": {\n"
" \"Id\": \"4973860941232342\",\n"
" \"Context\": {\n"
" \"CollapseOrderItems\": false,\n"
" \"IsTest\": false\n"
" }\n"
" },\n"
" \"SelfIdentifiersData\": {\n"
" \"SelfIdentifierData\": [\n"
" {\n"
" \"SelfIdentifierType\": {\n"
" \"SelfIdentifierType\": \"111\"\n"
" }\n"
" },\n"
" {\n"
" \"SelfIdentifierType\": {\n"
" \"SelfIdentifierType\": \"2222\"\n"
" }\n"
" }\n"
" ]\n"
" }\n"
"}";
// create bson object
bsoncxx::document::value bsonObj = bsoncxx::from_json(testJson);
bsoncxx::document::view bsonObjView = bsonObj.view();
// example query which contains an array index, this fails. Expected query result is "111"
std::vector<std::string> currQuery = {"SelfIdentifiersData", "SelfIdentifierData", "0", "SelfIdentifierType", "SelfIdentifierType"};
// an example query without array indices, this works. Expected query result is "false"
//std::vector<std::string> currQuery = {"shopper", "Context", "CollapseOrderItems"};
bsoncxx::document::element queryResult = deepFieldAccess3(bsonObjView, currQuery);
std::cout << "\n\nGiven query and its result: [ ";
for (auto i: currQuery)
std::cout << i << ' ';
std::cout << "] -> " << turnQueryResultIntoString3(queryResult) << std::endl;
}
没有内置的方法可以做到这一点,因此您需要编写一个类似于上面概述的辅助函数。
我相信您遇到的问题是函数的参数是bsoncxx::document::view
,但view::find
的返回值是bsoncxx::document::element
。 因此,您需要考虑循环中某处的类型更改。
我想我会这样写函数:
bsoncxx::document::element deepFieldAccess(bsoncxx::document::view bsonObj, const std::vector<std::string>& path) {
if (path.empty())
return {};
auto keysIter = path.begin();
const auto keysEnd = path.end();
auto currElement = bsonObj[*(keysIter++)];
while (currElement && (keysIter != keysEnd))
currElement = currElement[*(keysIter++)];
return currElement;
}
请注意,如果找不到路径的任何部分,或者如果路径尝试遍历实际上不是 BSON 文档或 BSON 数组的对象,这将返回无效的bsoncxx::document::element
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.