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对象的堆用一种允许动态配置的方式连接起来。