You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Python调用C++程序(mongocxx驱动查询MongoDB)并返回结果集

在C++中用mongocxx查询MongoDB并将结果返回给Python的实现方案

我来帮你搞定这个需求——从Python调用C++程序,用mongocxx驱动查询MongoDB再把结果返回给Python。这里有两种实用的实现方案,你可以根据场景选择:

方案一:通过标准输出(stdout)传递结果(最简单)

这种方式不需要处理复杂的跨语言接口,C++程序把查询结果转成JSON输出到stdout,Python读取stdout内容再解析即可。

1. 完善C++查询代码

先把你没写完的C++代码补全,实现查询并输出JSON格式的结果:

#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>
#include <iostream>
#include <vector>
#include <string>

int main() {
    try {
        // 初始化mongocxx实例,必须放在最前面
        mongocxx::instance inst{};
        // 替换成你的MongoDB连接URI
        mongocxx::uri uri("mongodb://localhost:27017");
        mongocxx::client conn(uri);

        // 替换成你的数据库和集合名称
        auto db = conn["your_database"];
        auto coll = db["your_collection"];

        // 构建查询条件,这里示例查询所有文档,你可以按需修改
        bsoncxx::builder::stream::document filter_builder;
        auto filter = filter_builder << bsoncxx::builder::stream::finalize;

        // 执行查询获取游标
        auto cursor = coll.find(filter);

        // 将每个BSON文档转成JSON字符串,逐行输出到stdout
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
    } catch (const std::exception& e) {
        // 把错误信息输出到stderr,方便Python捕获
        std::cerr << "C++程序执行错误: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

2. 编译C++程序

用g++编译时需要链接mongocxx和bsoncxx库,命令示例:

g++ -o mongo_query mongo_query.cpp -lmongocxx -lbsoncxx

如果你的库安装在非标准路径,需要加上-L/usr/local/lib(替换成你的库路径)和-I/usr/local/include/mongocxx/v_noabi -I/usr/local/include/bsoncxx/v_noabi(替换成你的头文件路径)。

3. Python调用并解析结果

用Python的subprocess模块调用编译后的可执行文件,读取输出并解析JSON:

import subprocess
import json

def fetch_mongo_data():
    try:
        # 调用C++可执行文件,捕获标准输出和错误
        proc = subprocess.run(
            ["./mongo_query"],
            capture_output=True,
            text=True,
            check=True
        )
        # 按行分割输出,每一行是一个JSON文档
        json_lines = proc.stdout.strip().split('\n')
        # 解析每个JSON字符串为Python字典
        return [json.loads(line) for line in json_lines if line]
    except subprocess.CalledProcessError as e:
        print(f"C++程序执行失败: {e.stderr}")
        return []
    except json.JSONDecodeError as e:
        print(f"JSON解析错误: {e}")
        return []

if __name__ == "__main__":
    data = fetch_mongo_data()
    print("查询到的MongoDB数据:")
    for doc in data:
        print(doc)

方案二:编译成动态链接库,用ctypes直接调用(更高效)

如果追求更高的性能,不想通过stdout传递数据,可以把C代码编译成动态库,用Python的ctypes模块直接调用C函数。

1. 编写C++动态库代码

注意要提供C兼容的接口(用extern "C"包裹),还要处理内存释放避免泄漏:

#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>
#include <vector>
#include <string>
#include <cstring>

// 定义C兼容的结构体,用于传递结果
typedef struct {
    const char** json_docs;
    size_t count;
} MongoQueryResult;

extern "C" {
    // 查询MongoDB的函数
    MongoQueryResult query_mongodb() {
        static std::vector<std::string> result_docs;
        result_docs.clear();

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

            auto db = conn["your_database"];
            auto coll = db["your_collection"];

            auto filter = bsoncxx::builder::stream::document{} << bsoncxx::builder::stream::finalize;
            auto cursor = coll.find(filter);

            for (auto&& doc : cursor) {
                result_docs.push_back(bsoncxx::to_json(doc));
            }
        } catch (const std::exception& e) {
            // 把错误信息加入结果
            result_docs.push_back(std::string("Error: ") + e.what());
        }

        // 分配C风格的字符串数组
        const char** c_docs = new const char*[result_docs.size()];
        for (size_t i = 0; i < result_docs.size(); ++i) {
            c_docs[i] = strdup(result_docs[i].c_str());
        }

        MongoQueryResult result;
        result.json_docs = c_docs;
        result.count = result_docs.size();
        return result;
    }

    // 释放结果内存的函数,必须调用避免泄漏
    void free_mongo_result(MongoQueryResult* result) {
        if (result->json_docs) {
            for (size_t i = 0; i < result->count; ++i) {
                free((void*)result->json_docs[i]);
            }
            delete[] result->json_docs;
            result->json_docs = nullptr;
            result->count = 0;
        }
    }
}

2. 编译动态库

g++ -shared -fPIC -o libmongoquery.so mongo_query_lib.cpp -lmongocxx -lbsoncxx

3. Python用ctypes调用动态库

import ctypes
import json

# 加载动态库
mongo_lib = ctypes.CDLL("./libmongoquery.so")

# 定义结果结构体类型
class MongoQueryResult(ctypes.Structure):
    _fields_ = [("json_docs", ctypes.POINTER(ctypes.c_char_p)),
                ("count", ctypes.c_size_t)]

# 声明函数的返回值和参数类型
mongo_lib.query_mongodb.restype = MongoQueryResult
mongo_lib.free_mongo_result.argtypes = [ctypes.POINTER(MongoQueryResult)]

def get_mongo_data():
    result = mongo_lib.query_mongodb()
    data = []
    try:
        for i in range(result.count):
            json_str = result.json_docs[i].decode('utf-8')
            try:
                data.append(json.loads(json_str))
            except json.JSONDecodeError:
                # 如果是错误信息,直接添加
                data.append({"error": json_str})
    finally:
        # 必须调用释放函数,避免内存泄漏
        mongo_lib.free_mongo_result(ctypes.byref(result))
    return data

if __name__ == "__main__":
    mongo_data = get_mongo_data()
    print("查询到的数据:")
    for doc in mongo_data:
        print(doc)

内容的提问来源于stack exchange,提问作者anubhav231989

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:54:43