MongoDB设计方法

发布时间 2024-01-04 17:22:16作者: 飞说晓事

一、 数据如何存储在MongoDB中

与传统的RDBMS关系型数据库不同,MongoDB并没有表Table,行row和列column的概念。它将数据存储在集合collections,文档documents和字段fields中。下图说明了与RDBMS类比的结构之间的关系:

 

二、操作

1、连接

创建一个全局的 mongocxx::instance 对象。然后使用 mongocxx::uri 创建一个 mongocxx::client 对象,这个对象代表一个 MongoDB 连接

    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{"mongodb://localhost/27017"}};
    if (!conn.operator bool()) {
        printf("连接失败!");
    }
    printf("连接成功!");

2、断开连接时自动重新连接

使用了 mongocxx::options::client 对象 opts 来设置一些连接选项。通过设置 max_pool_size 为 1,将连接池的大小限制为 1,这样可以确保当连接断开时,马上进行重连。heartbeat_freq 指定了心跳间隔,以便在连接断开后能够及时检测并重连。 

值得注意的是,尽管设置了自动重连,在对数据库进行操作时还是需要处理可能的连接错误。对于读操作,需要在错误发生时重新执行操作,而对于写操作,可能需要确保操作等,以防止数据重复插入。

mongocxx::instance inst{};
mongocxx::options::client opts;
opts.max_pool_size(1);
opts.heartbeat_freq(std::chrono::seconds(10));
mongocxx::client conn{mongocxx::uri{}, opts};

3、访问数据库

 

有了一个连接到 MongoDB 服务的 mongocxx::client实例。就可以使用 database() 方法或者 [] 操作获得一个 mongocxx::database 实例。

如果访问的数据库不存在,MongoDB 会在第一次存储数据时创建这个数据库。

mongocxx::database db = client["mydb"];

4、访问集合

有了一个 mongocxx::database 实例,你就可以使用 collection() 方法或者 [] 操作获得一个 mongocxx::collection 实例。

如果访问的集合不存在,MongoDB 会在第一次存储数据时创建这个集合。

mongocxx::collection coll = db["test"];

5、创建一个文档

两个可用的生成器接口(builder interfaces)中选择一个使用:

流生成器(Stream builder):bsoncxx::builder::stream 一个使用流操作的文档生成器,在构建文字文档时表现较好。

基本生成器(Basic builder):bsoncxx::builder::basic 生成器实例中更加方便的文档生成器,包含了一些调用方法。

 

使用 bsoncxx::builder::stream::finalize 获得一个 bsoncxx::document::value 的实例。

bsoncxx::document::value 类型是一个拥有独立存储的只读对象。为了使用它,必须使用其 view() 方法获得一个 bsoncxx::document::view 对象:


使用 []操作 访问文档中的字段,这将会返回一个 bsoncxx::document::element 实例。
 
如果 name 中的值不是字符串且你没有在上面代码中包含类型检查,这个代码将会抛出 bsoncxx::exception 实例
/*
{
   "name" : "MongoDB",
   "type" : "database",
   "count" : 1,
   "versions": [ "v3.2", "v3.0", "v2.6" ],
   "info" : {
               "x" : 203,
               "y" : 102
            }
}
*/
#include <cstdint>
#include <iostream>
#include <vector>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/stdx.hpp>
#include <mongocxx/uri.hpp>
// 官方文档中缺少以下语句
#include <bsoncxx\builder\stream\document.hpp>       
#include <mongocxx\instance.hpp>

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

int main(int,char**)
{
    mongocxx::instance instance{};      // This should be done only once.
    mongocxx::uri uri("mongodb://localhost:27017");
    mongocxx::client client(uri);

    mongocxx::database db = client["mydb"];     // 访问数据库
    mongocxx::collection coll = db["test"];     // 访问集合

    // 构造 JSON 文档
    auto builder = bsoncxx::builder::stream::document{};
    bsoncxx::document::value doc_value = builder
        << "name" << "MongoDB"
        << "type" << "database"
        << "count" << 1
        << "versions" << bsoncxx::builder::stream::open_array
        << "v3.2" << "v3.0" << "v2.6"
        << close_array
        << "info" << bsoncxx::builder::stream::open_document
        << "x" << 203
        << "y" << 102
        << bsoncxx::builder::stream::close_document
        << bsoncxx::builder::stream::finalize;
    // 访问 JSON 文档 string 字段
    bsoncxx::document::view view = doc_value.view();
    bsoncxx::document::element element = view["name"];
    if (element.type() != bsoncxx::type::k_utf8)
    {
        std::cout << "name type error." << std::endl;
    }
    std::string name = element.get_utf8().value.to_string();
    std::cout << "name:" << std::endl;
    std::cout << name << std::endl;
    // 访问 JSON 文档 array 字段
    element = view["versions"];
    if (element.type() != bsoncxx::type::k_array)
    {
        std::cout << "versions type error." << std::endl;
    }
    bsoncxx::array::view version = element.get_array().value;       // 获取到的元素为 array view
    std::cout << "version:" << std::endl;
    for each (bsoncxx::array::element var in version)
    {
        std::string value = var.get_utf8().value.to_string();       // 此处不再进行类型检查,检查是否为 string 的方法和上面相同
        std::cout << value<<" ";
    }
    std::cout << std::endl;
    // 访问 JSON 文档 document 字段
    element = view["info"];
    if (element.type() != bsoncxx::type::k_document)
    {
        std::cout << "info type error." << std::endl;
    }
    bsoncxx::document::view info = element.get_document().value;        // 获取到的元素依然为 document view
    std::cout << "info:" << std::endl;
    bsoncxx::document::element ele1 = info["x"];
    if (ele1.type() != bsoncxx::type::k_int32)
        std::cout << "ele1 type error" << std::endl;
    int x = ele1.get_int32().value;
    std::cout << "x: " << x << std::endl;
    int y = info["y"].get_int32().value;    // 如果不做参数类型检查,可以使用这种简单的方式
    std::cout << "y: " << y << std::endl;

    system("pause");
    return 0;
}

6、插入

创建或插入操作将新文档添加到集合。如果集合当前不存在,则插入操作将创建集合。

在MongoDB中,插入操作以单个集合为目标。MongoDB中的所有写操作都是单个文档级别的原子操作。

 直接插入json字符

    
mongoInit();
auto client = mongoClient();
auto places = (*client)["places"]["places"];
    std::string doc = "{"
        "\"col_protocol_type\": \"PM3\"," 
        "\"channel\" : \"1\","
        "\"time\" : \"2023-08-11 15:39:57.271\"," 
        "\"name\" : \"回路1温度\"," 
        "\"unit\" : \"℃\"," 
        "\"max\" : [" 
        "38.0,"
        "100" 
        "] ,"
        "\"min\" : ["
        "28.0,"
        "8"
        "] }";

bsoncxx::document::value josn = bsoncxx::from_json(string_To_UTF8(doc));
places.insert_one(josn.view());
mongoQuit();

 

三、插入中文方法:

     1、需要转换utf8字符串

#include <Windows.h>
using namespace std;

std::string string_To_UTF8(const std::string& str)
{
    int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

    wchar_t* pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴 
    ZeroMemory(pwBuf, nwLen * 2 + 2);

    ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);

    int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

    char* pBuf = new char[nLen + 1];
    ZeroMemory(pBuf, nLen + 1);

    ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

    std::string retStr(pBuf);

    delete[]pwBuf;
    delete[]pBuf;

    pwBuf = NULL;
    pBuf = NULL;

    return retStr;
}

2、添加数据库配置文件mongod.cfg

engine: wiredTiger
  wiredTiger:
    engineConfig:
      directoryForIndexes: true
      collectionConfig:
        blockCompressor: none
      indexConfig:
        prefixCompression: true
  mmapv1:
    smallFiles: true
  replication:
    replSetName: "rs0"

 

 

参考文献:

            1、https://blog.csdn.net/weixin_44834554/article/details/127057842

            2、https://www.python100.com/html/71390.html

           3、https://codeleading.com/article/29143068957/

           4、https://www.jianshu.com/p/0959d2221f43