MongoDB&C++开发(四)bsoncxx::builder::stream::document的增删改查操作

2. mongocxx

续上一篇,接着看一下mongocxx中的文件有些什么。
这里写图片描述
先看一下基本的增删改查操作:

2.1 connect.cpp 数据库的链接

参见之前的博客。

2.2 create.cpp 构造文档并插入

构造一个文档,插入数据库中的一个collection。关于builder::stream::document的使用见同系列博客之(三)。

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

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

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

int main(int, char**) {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{}};

    auto db = conn["test"];

    // TODO: fix dates

    // @begin: cpp-insert-a-document
    bsoncxx::document::value restaurant_doc =
        document{} << "address" << open_document << "street"
                   << "2 Avenue"
                   << "zipcode"
                   << "10075"
                   << "building"
                   << "1480"
                   << "coord" << open_array << -73.9557413 << 40.7720266 << close_array
                   << close_document << "borough"
                   << "Manhattan"
                   << "cuisine"
                   << "Italian"
                   << "grades" << open_array << open_document << "date"
                   << bsoncxx::types::b_date{std::chrono::milliseconds{12323}} << "grade"
                   << "A"
                   << "score" << 11 << close_document << open_document << "date"
                   << bsoncxx::types::b_date{std::chrono::milliseconds{121212}} << "grade"
                   << "B"
                   << "score" << 17 << close_document << close_array << "name"
                   << "Vella"
                   << "restaurant_id"
                   << "41704620" << finalize;

    // We choose to move in our document here, which transfers ownership to insert_one()
    auto res = db["restaurants"].insert_one(std::move(restaurant_doc));
    // @end: cpp-insert-a-document
}

在数据库test中的restaurant”表”(collection)中插入一个文件restaurant_doc:

 {
     "address" : {
                     "street"   :"2 Avenue",
                     "zipcode"  :"10075",
                     "building" :"1480", 
                     "coord"    :[-73.9557413,40.7720266],
                 },
    "borough" : "Manhattan",
    "cuisine" : "Italian",
    "grades"  : [ 
                   {
                       "date"  : ***时间,
                       “grade" : "A",
                       "score" : 11
                   }
                   {
                       "date"  : ***时间,
                       ”grade" : "B",
                       "score" : 17
                   }
               ]
    "name"          : "Vella",
    "restaruant_id" : "41706420"
}

2.3 update.cpp

  • 找到一个符合条件的文档,修改/新建一个键值对
  • 嵌套修改/新建一个键值对
  • 修改多个文件中的键值对
  • 找到一个符合条件的文档,替换文档中的一部分内容
int main(int, char**) {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{}};

    auto db = conn["test"];

    // Update top-level fields in a single document.
    {
        // @begin: cpp-update-top-level-fields
        //找到有"name":"Juni"键值对的文档,使用\$set指定一个  
        //"cuisine"(如果文档中没有将新建),将这个键值对改
        //"cuisine":"American(New)",然后使用\$currentDate指定
        //叫做"lastModified"的键,bool值true表示这个键对应的值使用
        //Date的形式(见此系列(2)中的常用数据类型
        //使用Unix的时间格式记录下当前的时间。
        bsoncxx::builder::stream::document filter_builder, update_builder;
        filter_builder << "name"
                       << "Juni";
        update_builder << "$set" << open_document << "cuisine"
                       << "American (New)" << close_document << "$currentDate" << open_document
                       << "lastModified" << true << close_document;

        db["restaurants"].update_one(filter_builder.view(), update_builder.view());
        // @end: cpp-update-top-level-fields
    }

    // Update an embedded document in a single document.
    //找到restaurant_id是41156888的这家餐馆的信息,把地址信息(文档)里面的street改成East 31st Street
    {
        // @begin: cpp-update-embedded-field
        bsoncxx::builder::stream::document filter_builder, update_builder;
        filter_builder << "restaurant_id"
                       << "41156888";
        update_builder << "$set" << open_document << "address.street"
                       << "East 31st Street" << close_document;

        db["restaurants"].update_one(filter_builder.view(), update_builder.view());
        // @end: cpp-update-embedded-field
    }

    // Update multiple documents.
    {
        // @begin: cpp-update-multiple-documents
        bsoncxx::builder::stream::document filter_builder, update_builder;
        filter_builder << "address.zipcode"
                       << "10016"
                       << "cuisine"
                       << "Other";
        update_builder << "$set" << open_document << "cuisine"
                       << "Category To Be Determined" << close_document << "$currentDate"
                       << open_document << "lastModified" << true << close_document;

        db["restaurants"].update_many(filter_builder.view(), update_builder.view());
        // @end: cpp-update-multiple-documents
    }

    // Replace the contents of a single document.
    {
        // @begin: cpp-replace-document
        //找到含有filter_builder信息的文档,将其中的对应信息替换成
        //replace_builder的信息
        bsoncxx::builder::stream::document filter_builder, replace_builder;
        filter_builder << "restaurant_id"
                       << "41704620";
        replace_builder << "name"
                        << "Vella 2"
                        << "address" << open_document << "coord" << open_array << -73.9557413
                        << 40.7720266 << close_array << "building"
                        << "1480"
                        << "street"
                        << "2 Avenue"
                        << "zipcode"
                        << "10075" << close_document;

        db["restaurants"].replace_one(filter_builder.view(), replace_builder.view());
        // @end: cpp-replace-document
    }
}

2.4 remove.cpp:

  • 删除一个或多个collection中符合条件的document
  • 删除collection中所有的document
  • 删除collection
int main(int, char**) {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{}};

    auto db = conn["test"];

    // Remove all documents that match a condition.
    {
        // @begin: cpp-remove-matching-documents
        //删除有"borough":"Manhattan"键值对的document
        bsoncxx::builder::stream::document filter_builder;
        filter_builder << "borough"
                       << "Manhattan";

        db["restaurants"].delete_many(filter_builder.view());
        // @end: cpp-remove-matching-documents
    }

    // Remove one document that matches a condition.
    {
        // @begin: cpp-remove-justone
        bsoncxx::builder::stream::document filter_builder;
        filter_builder << "borough"
                       << "Queens";

        db["restaurants"].delete_one(filter_builder.view());
        // @end: cpp-remove-justone
    }

    // Remove all documents in a collection.
    {
        // @begin: cpp-remove-all-documents
        db["restaurants"].delete_many({});
        // @end: cpp-remove-all-documents
    }

    // Drop a collection.
    {
        // @begin: cpp-drop-collection
        db["restaurants"].drop();
        // @end: cpp-drop-collection
    }
}

2.5 query.cpp:

  • 查询一个collection中所有的文件
  • 条件查询含有某个键值对的document
  • 条件查询含有某个键值对(值为document,在document中继续嵌套查询)
  • 条件查询含有某个键值对(值为array,在array中继续嵌套查询)
  • 使用$gt(greater than),$lt(less than)进行条件查询
  • 多个条件查询 相当于sql里的and
  • 满足多个条件中至少一个条件查询,相当于sql中的or]
  • 对查询结果进行排序
int main(int, char**) {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{}};

    auto db = conn["test"];

    // Query for all the documents in a collection.
    //查询test数据库的restaurants集合中的所有文档
    {
        // @begin: cpp-query-all
        auto cursor = db["restaurants"].find({});
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        // @end: cpp-query-all
    }

    // Query for equality on a top level field.
    //查询restaurants集合中所有含"borough":"Manhattan"键值对的文档
    {
        // @begin: cpp-query-top-level-field
        auto cursor = db["restaurants"].find(document{} << "borough"
                                                        << "Manhattan" << finalize);

        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        // @end: cpp-query-top-level-field
    }

    // Query by a field in an embedded document.
    //嵌套查询,查询邮编为10075的餐馆的文档,address是文档中嵌套的一个文档,zipcode是address中的一个key,10075是zipcode对应的value.
    {
        // @begin: cpp-query-embedded-document
        bsoncxx::builder::stream::document filter_builder;
        filter_builder << "address.zipcode"
                       << "10075";

        auto cursor = db["restaurants"].find(filter_builder.view());
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        // @end: cpp-query-embedded-document
    }

    // Query by a field in an array.
    //grades键对应的值是一个array,里面有两个文档,在这个数组中查找grade键的值是B的文档
    {
        // @begin: cpp-query-field-in-array
        bsoncxx::builder::stream::document filter_builder;
        filter_builder << "grades.grade"
                       << "B";

        auto cursor = db["restaurants"].find(filter_builder.view());
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        // @end: cpp-query-field-in-array
    }

    // Query with the greater-than operator ($gt).
    //在grades对应的array中寻找score大于30的文档
    {
        // @begin: cpp-query-greater-than
        bsoncxx::builder::stream::document filter_builder;
        filter_builder << "grades.score" << open_document << "$gt" << 30 << close_document;

        auto cursor = db["restaurants"].find(filter_builder.view());
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        // @end: cpp-query-greater-than
    }

    // Query with the less-than operator ($lt).
    //$gt和$lt,分别是大于和小于
    {
        // @begin: cpp-query-less-than
        bsoncxx::builder::stream::document filter_builder;
        filter_builder << "grades.score" << open_document << "$lt" << 10 << close_document;

        auto cursor = db["restaurants"].find(filter_builder.view());
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        // @end: cpp-query-less-than
    }

    // Query with a logical conjunction (AND) of query conditions.
    //filter_builder中有多个键值对,默认是and的关系,相当于SQL语句中的and,表示查询cuisine是Italian并且zipcode是10075的餐馆的文档
    {
        // @begin: cpp-query-logical-and
        bsoncxx::builder::stream::document filter_builder;
        filter_builder << "cuisine"
                       << "Italian"
                       << "address.zipcode"
                       << "10075";

        auto cursor = db["restaurants"].find(filter_builder.view());
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        // @end: cpp-query-logical-and
    }

    // Query with a logical disjunction (OR) of query conditions.
    //$or表示或的关系注意这个地方open_array/close_array和open_document/close_document的使用
    {
        // @begin: cpp-query-logical-or
        bsoncxx::builder::stream::document filter_builder;
        filter_builder << "$or" << open_array << open_document << "cuisine"
                       << "Italian" << close_document << open_document << "address.zipcode"
                       << "10075" << close_document << close_array;

        auto cursor = db["restaurants"].find(filter_builder.view());
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        // @end: cpp-query-logical-or
    }

    // Sort query results.
    //1和-1表示升序和降序(应该是)
    {
        // @begin: cpp-query-sort
        mongocxx::options::find opts;
        bsoncxx::builder::stream::document order_builder;
        order_builder << "borough" << 1 << "address.zipcode" << -1;
        opts.sort(order_builder.view());

        auto cursor = db["restaurants"].find({}, opts);
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        // @end: cpp-query-sort
    }
}

2.6 get_values_from_documents.cpp

从数据库的文档中取数据,输出到cout

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

// Document model, showing array with nested documents:
//
// {
//     "_id" : ObjectId(...),
//     "messagelist" : [
//       {
//         "uid" : 413098706,
//         "status" : 2,
//         "msg": "..."
//       },
//       ...
//     ]
// }

// Construct a document in the format of 'messagelist'.
bsoncxx::document::value new_message(int64_t uid, int32_t status, std::string msg) {
    document doc;
    return doc << "uid" << uid << "status" << status << "msg" << msg << finalize;
}

// Insert a document into the database.
void insert_test_data(mongocxx::collection& coll) {
    document builder{};
    //这种赋值方法注意一下
    builder << "messagelist" << open_array << new_message(413098706, 3, "Lorem ipsum...")
            << new_message(413098707, 2, "Lorem ipsum...")
            << new_message(413098708, 1, "Lorem ipsum...") << close_array;

    bsoncxx::document::value doc = builder << finalize;

    // Normally, one should check the return value for success.
    coll.insert_one(doc.view());
}

// Iterate over contents of messagelist.遍历messagelist数组中的所有内容
void iterate_messagelist(const bsoncxx::document::element& ele) {
    // Check validity and type before trying to iterate.
    if (ele.type() == type::k_array) {
        bsoncxx::array::view subarray{ele.get_array().value};
        for (const bsoncxx::array::element& msg : subarray) {
            // Check correct type before trying to access elements.
            // Only print out fields if they exist; don't report missing fields.
            if (msg.type() == type::k_document) {
                bsoncxx::document::view subdoc = msg.get_document().value;
                bsoncxx::document::element uid = subdoc["uid"];//使用[]访问键
                bsoncxx::document::element status = subdoc["status"];
                bsoncxx::document::element msg = subdoc["msg"];
                if (uid && uid.type() == type::k_int64) {
                    std::cout << "uid: " << uid.get_int64().value << std::endl;
                }
                if (status && status.type() == type::k_int32) {
                    std::cout << "status: " << status.get_int32().value << std::endl;
                }
                if (msg && msg.type() == type::k_utf8) {
                    std::cout << "msg: " << msg.get_utf8().value << std::endl;
                }
            } else {
                std::cout << "Message is not a document" << std::endl;
            }
        }
    } else {
        std::cout << "messagelist is not an array" << std::endl;
    }
}

// Print document parts to standard output.
void print_document(const bsoncxx::document::view& doc) {
    // Extract _id element as a string.
    bsoncxx::document::element id_ele = doc["_id"];
    if (id_ele.type() == type::k_oid) {
        std::string oid = id_ele.get_oid().value.to_string();//注意 _id可以通过to_string()转为std::string
        std::cout << "OID: " << oid << std::endl;
    } else {
        std::cout << "Error: _id was not an object ID." << std::endl;
    }

    // Extract "messagelist" element, which could be the 'invalid' (false)
    // element if it doesn't exist.
    bsoncxx::document::element msgs_ele = doc["messagelist"];
    if (msgs_ele) {
        iterate_messagelist(msgs_ele);
    } else {
        std::cout << "Error: messagelist field missing." << std::endl;
    }
}

void iterate_documents(mongocxx::collection& coll) {
    // Execute a query with an empty filter (i.e. get all documents).
    mongocxx::cursor cursor = coll.find({});

    // Iterate the cursor into bsoncxx::document::view objects.
    for (const bsoncxx::document::view& doc : cursor) {
        print_document(doc);
    }
}

int main() {
    mongocxx::instance inst{};
    mongocxx::client client{mongocxx::uri{}};
    mongocxx::collection coll = client["test"]["events"];

    coll.drop();
    insert_test_data(coll);
    iterate_documents(coll);
}

简单分析了增删改查的基本用法,之后再通过看API了解更详细的使用方法。下一篇博客把常用的类和成员函数,相关参数梳理一下。
还有几个感觉比较有用的例子:
aggregate.cpp :用来统计

index.cpp:建索引
bulk_write.cpp:批量操作
instance_management.cpp:对instance进行管理,项目大的时候会需要,保持分配给mongocxx::instance和mongocxx::pool对象的堆用一种允许动态配置的方式连接起来。

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
最近重构并优化了一套后端服务的代码: 1. 设计并开发高效的C++对象池算法,时间复杂度为 O(1) 在整个重构框架,对象池是负责管理内存的底层基本模块 2. 利用命令模式的思想开发 Redis 子模块 抽象出方便高效的接口提供给上层程序员使用 3. 利用组合模式和装饰模式的思想开发 MongoDB 数据查询条件装饰器 将查询条件和数据 MongodbModule 数据模型进行解耦合 4. 抽象出一套 MongoDB Module 结果集接口 通过模板和特化技术实现 string/int 等不同索引类型的结果集 5. 开发 AbstractMongodbModule 类处理通用的 MongoDB 数据表数据操作 数据不同的表都有自己的 AbstractMongodbModule 子类对应 6. 用 Perl 开发自动代码生成器,上层程序员对照数据表结构写 .tmpl 配置文件, 自动生成该数据表的 MongodbModule 子类,减轻程序员新增表时的工作量 7. 结合 Redis 模块和 MongoDB 模块,开发 HierarchicalModule 分层数据模型 构造一个 Redis 缓存层 + MongoDB 持久层的后台 Server 架构 并通过简单方便的接口供上层程序员使用,具体的数据分层处理对上层程序员是黑盒的 8. 设计并开发整套缓存层使用的 KEY 规则,方便缓存更新 结合公司的数据订阅系统进行 Redis缓存层 + MongoDB 持久层数据更新功能 9. 重构后的分层数据架构比原有接口效率提高 5 - 400 倍(返回数据记录条数从 150 - 5 条) 绝大部分时间后端接口需要获取记录个数在 50 以内,所以效率提升在 100 倍左右
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值