mongocxx c++ 14标准,进行多表联合查询

 

#include <iostream>
#include <vector>
#include <map>

#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>

#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/types.hpp>

using bsoncxx::builder::stream::document;
using bsoncxx::builder::stream::finalize;
using bsoncxx::builder::stream::open_array;
using bsoncxx::builder::stream::close_array;
using bsoncxx::builder::stream::open_document;
using bsoncxx::builder::stream::close_document;
using bsoncxx::builder::stream::concatenate;
using bsoncxx::builder::basic::make_document;
using bsoncxx::builder::basic::kvp;


void get_data() {
    mongocxx::instance inst{}; // 实例化 Mongocxx 库
    mongocxx::uri uri("mongodb://localhost:27017"); // 连接 MongoDB URI
    mongocxx::client conn(uri); // 创建连接实例

    mongocxx::database db = conn["test_sh"];

    mongocxx::collection teacher_1 = db["teacher_20230417_0_60"];
    mongocxx::collection teacher_2 = db["teacher_20230417_120_180"];
    // mongocxx::collection teacher_3 = db["teacher_20230417_180_240"];

    auto pipeline = mongocxx::pipeline{};
    pipeline.lookup({
        make_document(
            kvp("from", "teacher_20230417_120_180"), // b表的表名
            kvp("localField", "teacher_1.index_join_id"), // a表的关联外键
            kvp("foreignField", "teacher_2.index_join_id"), // b表的关联外键
            kvp("as", "teacher_2") // 别名
        )
        });


    pipeline.unwind("$teacher_2");
    // 如果有多个,这里需要写多个
    /*pipeline.unwind("$array_field1");
    pipeline.unwind("$array_field2");
    pipeline.unwind("$array_field3");*/


    // 这里是做展示代码
    pipeline.project({
        make_document(
            kvp("_id", 0),
            kvp("index", 1),
            kvp("time", 1),
            kvp("TPE02", "$teacher_2.TPE02")
        )
        });

    // 排序
    // pipeline.sort(make_document(kvp("time", 1)));

    pipeline.limit(10); // 使用.limit()操作符限制结果数量


    auto cursor = teacher_1.aggregate(pipeline);

    for (auto&& doc : cursor) {
        std::cout << bsoncxx::to_json(doc) << std::endl;
    }

 

 

 

增加复杂情况下,动态获取表和字段,进行多表联合查询代码

#ifndef GET_DATA_HPP
#define GET_DATA_HPP

#include <iostream>
#include <vector>
#include <map>

#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>

#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/types.hpp>

using bsoncxx::builder::stream::document;
using bsoncxx::builder::stream::finalize;
using bsoncxx::builder::stream::open_array;
using bsoncxx::builder::stream::close_array;
using bsoncxx::builder::stream::open_document;
using bsoncxx::builder::stream::close_document;
using bsoncxx::builder::stream::concatenate;
using bsoncxx::builder::basic::make_document;
using bsoncxx::builder::basic::kvp;

int get_data() {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{"mongodb://localhost:27017"}};

    auto db = conn["test_sh"];

    std::map<std::string, std::vector<std::string>> return_dict;
    return_dict["teacher_20230417_0_60"] = { "index","time" };
    return_dict["teacher_20230417_120_180"] = { "TPE02" };
    return_dict["teacher_20230417_180_240"] = { "TBFTCT08" };

    // 获取return_dict的第二个值,for循环中使用
    std::string previous_key; //所以previous_key存储的都是上一个key值

    auto pipeline = mongocxx::pipeline{};
    for (const auto& item : return_dict) {
        // teacher_20230417_0_60 可以用begin来获取
        if (item.first != "teacher_20230417_0_60") {
            /*
            * 示例
            pipeline.lookup({
              make_document(
                  kvp("from", item.first), // b表的表名
                  kvp("localField", "index_join_id"), // a表的关联外键
                  kvp("foreignField", "index_join_id"), // b表的关联外键
                  kvp("as", "from_" + item.first) // 别名
              )
            });*/


            // 这里需要增加一个判断,因为有可能a 和b的关联外键是a.aid,b.bid,和c的情况不是a和c,可能是b的bbid和c的ccid了
            // 如果second_element.first == 第二个表,localfield就是第一个表的外键
            
            std::string foreign_key_a = previous_key + ".index_join_id";
            std::string foreign_key_b = item.first + ".index_join_id";
            std::string as_name = "from_" + item.first;

            pipeline.lookup({
              make_document(
                  kvp("from", item.first), // b表的表名
                  kvp("localField", "index_join_id"), // a表的关联外键
                  kvp("foreignField", foreign_key_b), // b表的关联外键
                  kvp("as", as_name) // 别名
              )
                });

        }
        // 在这里,element.first 是当前循环的键
            // previous_key 是上一个循环的键(如果有的话)
            // 在第一次循环时,previous_key 是空的

            // 在这里处理当前循环的逻辑

            // 更新 previous_key
        previous_key = item.first;
    }

    bsoncxx::builder::stream::document projection_doc;
    for (const auto& item : return_dict) {
        for (const auto& field : item.second) {
            projection_doc << field << 1;
        }
    }

    pipeline.limit(10); // 使用.limit()操作符限制结果数量

    pipeline.project(projection_doc.view());

    auto cursor = db["teacher_20230417_0_60"].aggregate(pipeline);
    for (auto&& doc : cursor) {
        std::cout << bsoncxx::to_json(doc) << std::endl;
    }

    return 0;
}


#endif // GET_DATA_HPP

 

最终形成的代码逻辑

#ifndef GET_DATA_HPP
#define GET_DATA_HPP

#include <iostream>
#include <vector>
#include <map>

#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>

#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/types.hpp>

using bsoncxx::builder::stream::document;
using bsoncxx::builder::stream::finalize;
using bsoncxx::builder::stream::open_array;
using bsoncxx::builder::stream::close_array;
using bsoncxx::builder::stream::open_document;
using bsoncxx::builder::stream::close_document;
using bsoncxx::builder::stream::concatenate;
using bsoncxx::builder::basic::make_document;
using bsoncxx::builder::basic::kvp;

int get_data() {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{"mongodb://localhost:27017"}};

    auto db = conn["test_sh"];

    std::map<std::string, std::vector<std::string>> return_dict;
    return_dict["teacher_20230417_0_60"] = { "index","time" };
    return_dict["teacher_20230417_120_180"] = { "TPE02" };
    return_dict["teacher_20230417_180_240"] = { "TBFTCT08" };

    // 获取return_dict的第二个值,for循环中使用
    std::string previous_key; //所以previous_key存储的都是上一个key值

    bsoncxx::builder::stream::document projection_doc;
    projection_doc << "_id" << 0;

    auto pipeline = mongocxx::pipeline{};
    for (const auto& item : return_dict) {
        // teacher_20230417_0_60 可以用begin来获取
        if (item.first != "teacher_20230417_0_60") {
            /*
            * 示例
            pipeline.lookup({
              make_document(
                  kvp("from", item.first), // b表的表名
                  kvp("localField", "index_join_id"), // a表的关联外键
                  kvp("foreignField", "index_join_id"), // b表的关联外键
                  kvp("as", "from_" + item.first) // 别名
              )
            });*/


            // 这里需要增加一个判断,因为有可能a 和b的关联外键是a.aid,b.bid,和c的情况不是a和c,可能是b的bbid和c的ccid了
            // 如果second_element.first == 第二个表,localfield就是第一个表的外键

            std::string foreign_key_a = previous_key + ".index_join_id";
            std::cout << foreign_key_a << std::endl;
            std::string foreign_key_b = item.first + ".index_join_id";
            std::string as_name = "from_" + item.first;

            pipeline.lookup({
              make_document(
                  kvp("from", item.first), // b表的表名
                  kvp("localField", foreign_key_a), // a表的关联外键
                  kvp("foreignField", foreign_key_b), // b表的关联外键
                  kvp("as", as_name) // 别名
              )
                });
            pipeline.unwind("$" + as_name); // 这里要是别名才可以

            for (const auto& field : item.second) {
                std::string field_name = "$" + as_name + "." + field;
                projection_doc << field << field_name; // kvp("TPE02", "$teacher_2.TPE02") 类似这种写法
            }

        }
        else {
            for (const auto& field : item.second) {
                projection_doc << field << 1;
            }
        }

        // 在这里,element.first 是当前循环的键
            // previous_key 是上一个循环的键(如果有的话)
            // 在第一次循环时,previous_key 是空的

            // 在这里处理当前循环的逻辑

            // 更新 previous_key
        previous_key = item.first;
    }


    pipeline.limit(10); // 使用.limit()操作符限制结果数量

    pipeline.project(projection_doc.view());

    auto cursor = db["teacher_20230417_0_60"].aggregate(pipeline);
    for (auto&& doc : cursor) {
        std::cout << bsoncxx::to_json(doc) << std::endl;
    }

    return 0;
}


#endif // GET_DATA_HPP
View Code

 

等等,看似对的,但实际上数据是错的。

修改后的代码

#ifndef GET_DATA_HPP
#define GET_DATA_HPP

#include <iostream>
#include <vector>
#include <map>

#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>

#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/types.hpp>

using bsoncxx::builder::stream::document;
using bsoncxx::builder::stream::finalize;
using bsoncxx::builder::stream::open_array;
using bsoncxx::builder::stream::close_array;
using bsoncxx::builder::stream::open_document;
using bsoncxx::builder::stream::close_document;
using bsoncxx::builder::stream::concatenate;
using bsoncxx::builder::basic::make_document;
using bsoncxx::builder::basic::kvp;

int get_data() {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{"mongodb://localhost:27017"}};

    auto db = conn["test_sh"];

    std::map<std::string, std::vector<std::string>> return_dict;
    return_dict["teacher_20230417_0_60"] = { "index","time" };
    return_dict["teacher_20230417_120_180"] = { "TPE02" };
    return_dict["teacher_20230417_180_240"] = { "TBFTCT08" };

    // 获取return_dict的第二个值,for循环中使用
    std::string previous_key; //所以previous_key存储的都是上一个key值

    bsoncxx::builder::stream::document projection_doc;
    projection_doc << "_id" << 0;
    projection_doc << "index_join_id" << 1;

    auto pipeline = mongocxx::pipeline{};
    for (const auto& item : return_dict) {
        // teacher_20230417_0_60 可以用begin来获取
        if (item.first != "teacher_20230417_0_60") {
            /*
            * 示例
            pipeline.lookup({
              make_document(
                  kvp("from", item.first), // b表的表名
                  kvp("localField", "index_join_id"), // a表的关联外键
                  kvp("foreignField", "index_join_id"), // b表的关联外键
                  kvp("as", "from_" + item.first) // 别名
              )
            });*/


            // 这里需要增加一个判断,因为有可能a 和b的关联外键是a.aid,b.bid,和c的情况不是a和c,可能是b的bbid和c的ccid了
            // 如果second_element.first == 第二个表,localfield就是第一个表的外键

            std::string foreign_key_a = previous_key + ".index_join_id";
            std::cout << foreign_key_a << std::endl;
            std::string foreign_key_b = item.first + ".index_join_id";
            std::string as_name = "from_" + item.first;

            pipeline.lookup({
              make_document(
                  kvp("from", item.first), // b表的表名
                  //kvp("localField", foreign_key_a), // a表的关联外键
                  //kvp("foreignField", foreign_key_b), // b表的关联外键

                  // 如果用类似sql的left join a.id=b.id的形式,数据有问题,所以暂时注释掉了

                  kvp("localField", "index_join_id"), // a表的关联外键
                  kvp("foreignField", "index_join_id"), // b表的关联外键  

                  kvp("as", as_name) // 别名
              )
                });
            pipeline.unwind("$" + as_name); // 这里要是别名才可以

            for (const auto& field : item.second) {
                std::string field_name = "$" + as_name + "." + field;
                projection_doc << field << field_name; // kvp("TPE02", "$teacher_2.TPE02") 类似这种写法
            }

        }
        else {
            for (const auto& field : item.second) {
                projection_doc << field << 1;
            }
        }

        // 在这里,element.first 是当前循环的键
            // previous_key 是上一个循环的键(如果有的话)
            // 在第一次循环时,previous_key 是空的

            // 在这里处理当前循环的逻辑

            // 更新 previous_key
        previous_key = item.first;
    }

    // pipeline.match(make_document(kvp("index", "TAB000002")));


    pipeline.limit(10); // 使用.limit()操作符限制结果数量



    pipeline.project(projection_doc.view());

    auto cursor = db["teacher_20230417_0_60"].aggregate(pipeline);
    for (auto&& doc : cursor) {
        std::cout << bsoncxx::to_json(doc) << std::endl;
    }

    return 0;
}


#endif // GET_DATA_HPP
View Code

 问题在这里

 

增加过滤条件

您好!如果您想在 pipeline.match 中使用大于或小于条件,可以使用 $gt 和 $lt 操作符。例如,如果您想限定 index 的数据大于 1,可以使用以下代码:

pipeline.match(make_document(kvp("index", make_document(kvp("$gt", 1)))));

如果您想限定 index 的数据小于 1,可以使用以下代码:
pipeline.match(make_document(kvp("index", make_document(kvp("$lt", 1)))));
这样,在执行 pipeline.match 时,只有满足条件的文档才会被处理。
等于 pipeline.match(make_document(kvp(
"index", "TAB000002")));

 

posted @ 2023-05-31 23:05  我当道士那儿些年  阅读(119)  评论(0编辑  收藏  举报