我有一个bsoncxx::document::view bsonObjViewstd::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。因此,最终解决方案应返回路径指向的值。它应适用于任意深度,也适用于指向TO数组元素的路径(第二个示例路径)和THROUGH数组元素的路径(最后两个示例路径)。我们假定索引为i的数组元素的键为"i"

更新:当前,@ acm建议的方法无法用于具有数组索引的路径(没有数组索引的路径可以正常工作)。这是重现此问题的所有代码:
#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

08-16 10:02