Skip to content

mongocxx — MongoDB C++ 驱动

mongocxx 是 MongoDB 官方 C++ 驱动,提供现代 C++ API,支持 BSON 文档操作、聚合管道、事务、GridFS 等完整功能。

安装

bash
# Ubuntu(先安装 mongoc)
sudo apt install libmongoc-dev libbson-dev
# 然后编译 mongocxx:https://mongocxx.org/mongocxx-driver/current/installation/

# vcpkg
vcpkg install mongo-cxx-driver

# CMake
find_package(mongocxx REQUIRED)
find_package(bsoncxx REQUIRED)
target_link_libraries(myapp PRIVATE mongo::mongocxx_shared mongo::bsoncxx_shared)

连接与基本操作

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

using bsoncxx::builder::stream::document;
using bsoncxx::builder::stream::finalize;
using bsoncxx::builder::stream::open_array;
using bsoncxx::builder::stream::close_array;

int main() {
    // 必须先创建 instance(全局唯一)
    mongocxx::instance inst{};

    // 连接
    mongocxx::client client{mongocxx::uri{"mongodb://localhost:27017"}};

    // 获取数据库和集合
    auto db = client["mydb"];
    auto coll = db["users"];

    // 插入单个文档
    auto doc = document{}
        << "name" << "Alice"
        << "age" << 30
        << "email" << "alice@example.com"
        << "tags" << open_array << "cpp" << "programming" << close_array
        << finalize;

    auto result = coll.insert_one(doc.view());
    if (result) {
        auto id = result->inserted_id().get_oid().value.to_string();
        std::cout << "插入 ID: " << id << "\n";
    }

    // 批量插入
    std::vector<bsoncxx::document::value> docs;
    for (int i = 0; i < 100; ++i) {
        docs.push_back(document{}
            << "name" << ("User" + std::to_string(i))
            << "age" << (20 + i % 50)
            << finalize);
    }
    coll.insert_many(docs);
}

查询

cpp
// 查询所有
auto cursor = coll.find({});
for (const auto& doc : cursor) {
    std::cout << bsoncxx::to_json(doc) << "\n";
}

// 条件查询
auto filter = document{} << "age" << bsoncxx::builder::stream::open_document
                          << "$gt" << 25
                          << bsoncxx::builder::stream::close_document
                          << finalize;
auto cursor2 = coll.find(filter.view());

// 查询选项(排序、分页、投影)
mongocxx::options::find opts;
opts.sort(document{} << "age" << 1 << finalize);  // 按 age 升序
opts.limit(10);
opts.skip(20);
opts.projection(document{} << "name" << 1 << "age" << 1 << "_id" << 0 << finalize);

auto cursor3 = coll.find(filter.view(), opts);

// 查询单个
auto one = coll.find_one(document{} << "name" << "Alice" << finalize);
if (one) {
    auto name = (*one)["name"].get_string().value;
    std::cout << name << "\n";
}

// 统计
auto count = coll.count_documents(document{} << "age" << bsoncxx::builder::stream::open_document
                                              << "$gt" << 18
                                              << bsoncxx::builder::stream::close_document
                                              << finalize);
std::cout << "成年用户: " << count << "\n";

更新与删除

cpp
// 更新单个
auto update_filter = document{} << "name" << "Alice" << finalize;
auto update = document{} << "$set" << bsoncxx::builder::stream::open_document
                          << "age" << 31
                          << "updated" << true
                          << bsoncxx::builder::stream::close_document
                          << finalize;
coll.update_one(update_filter.view(), update.view());

// 更新多个
auto update_many_filter = document{} << "age" << bsoncxx::builder::stream::open_document
                                      << "$lt" << 18
                                      << bsoncxx::builder::stream::close_document
                                      << finalize;
auto inc_update = document{} << "$inc" << bsoncxx::builder::stream::open_document
                               << "age" << 1
                               << bsoncxx::builder::stream::close_document
                               << finalize;
coll.update_many(update_many_filter.view(), inc_update.view());

// upsert(不存在则插入)
mongocxx::options::update upsert_opts;
upsert_opts.upsert(true);
coll.update_one(update_filter.view(), update.view(), upsert_opts);

// 删除
coll.delete_one(document{} << "name" << "Alice" << finalize);
coll.delete_many(document{} << "age" << bsoncxx::builder::stream::open_document
                              << "$lt" << 18
                              << bsoncxx::builder::stream::close_document
                              << finalize);

聚合管道

cpp
// 聚合:按部门统计平均薪资
mongocxx::pipeline pipeline;
pipeline.match(document{} << "active" << true << finalize);
pipeline.group(document{}
    << "_id" << "$department"
    << "avg_salary" << bsoncxx::builder::stream::open_document
        << "$avg" << "$salary"
        << bsoncxx::builder::stream::close_document
    << "count" << bsoncxx::builder::stream::open_document
        << "$sum" << 1
        << bsoncxx::builder::stream::close_document
    << finalize);
pipeline.sort(document{} << "avg_salary" << -1 << finalize);

auto cursor = coll.aggregate(pipeline);
for (const auto& doc : cursor) {
    std::cout << bsoncxx::to_json(doc) << "\n";
}

索引

cpp
// 创建索引
auto index_spec = document{} << "email" << 1 << finalize;
mongocxx::options::index index_opts;
index_opts.unique(true);
coll.create_index(index_spec.view(), index_opts);

// 复合索引
coll.create_index(document{} << "age" << 1 << "name" << 1 << finalize);

// 文本索引(全文搜索)
coll.create_index(document{} << "description" << "text" << finalize);
auto text_query = document{} << "$text" << bsoncxx::builder::stream::open_document
                               << "$search" << "cpp programming"
                               << bsoncxx::builder::stream::close_document
                               << finalize;
auto text_cursor = coll.find(text_query.view());

关键认知

mongocxx 的 BSON builder 语法初看繁琐,但类型安全。bsoncxx::to_json()bsoncxx::from_json() 可以与 JSON 字符串互转,方便调试。聚合管道是 MongoDB 最强大的查询工具,复杂统计优先用聚合而非多次查询。

系统学习 C++ 生态,深入底层架构