# MongoDB

MongoDB

MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。

在高负载的情况下,添加更多的节点,可以保证服务器性能。

MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

img

# 服务安装

  • 进入 官网 ,选择适合自己的安装包,并复制下载链接

    image-20211230171326720

  • 下载并解压安装包

    # 下载
    wget https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-rhel70-5.0.5.tgz
    
    # 解压
    tar -xzvf mongodb-linux-x86_64-enterprise-rhel70-5.0.5.tgz
    
    # 进入解压后的文件夹
    cd mongodb-linux-x86_64-enterprise-rhel70-5.0.5
    
    # 创建data目录和log目录
    mkdir data
    mkdir log
    touch log/mongodb.log
    
    # 启动服务 (默认在27017端口启动)
    bin/mongod --dbpath ./data --logpath ./log/mongodb.log --bind_ip_all --fork
    
    # 客户端连接
    bin/mongo
    
  • 其它

    若服务启动有以下报错, 说明是依赖包未安装,安装以下即可

    # bin/mongod: error while loading shared libraries: libnetsnmpmibs.so.31: cannot open shared object file: No such file or director
    
    yum install net-snmp
    

# 概念解析

MongoDB术语/概念 SQL术语/概念 解释/说明
database database 数据库
collection table 数据库表/集合
document row 数据记录行/文档
field column 数据字段/域
index (普通索引、联合索引、唯一索引) index 索引
/ table joins 表连接
primary key primary key 主键,MongoDB自动将_id字段设置为主键

# 数据库

和关系型数据库一样,一个mongodb中可以创建多个数据库,每个数据库可以有自己的集合和权限,数据存储于

执行“show dbs" 命令可以展示所有数据库列表, 第一列显示数据库名称,第二列显示对应数据库所占用的存储空间

MongoDB Enterprise > show dbs;
admin      0.000GB
config     0.000GB
local      0.000GB
lowan-iot  0.001GB
test       0.000GB

其中 "admin"、"config"、"local" 为 mongodb 默认创建的数据库

  • admin : 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
  • local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
  • config: 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。

执行 "db" 命令可以显示当前数据库对象

MongoDB Enterprise > db
test

执行 "use" 命令可以切换到一个指定的数据库

MongoDB Enterprise > use lowan-iot
switched to db lowan-iot
MongoDB Enterprise >

# 文档

文档是一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。

# 集合

集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。

集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

比如,我们可以将以下不同数据结构的文档插入到集合中:

{"site":"www.baidu.com"}
{"site":"www.google.com","name":"Google"}
{"site":"www.runoob.com","name":"菜鸟教程","num":5}

# MongoDB 数据类型

数据类型 描述
String 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
Integer 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
Boolean 布尔值。用于存储布尔值(真/假)。
Double 双精度浮点值。用于存储浮点值。
Min/Max keys 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
Array 用于将数组或列表或多个值存储为一个键。
Timestamp 时间戳。记录文档修改或添加的具体时间。
Object 用于内嵌文档。
Null 用于创建空值。
Symbol 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
Date 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
Object ID 对象 ID。用于创建文档的 ID。
Binary Data 二进制数据。用于存储二进制数据。
Code 代码类型。用于在文档中存储 JavaScript 代码。
Regular expression 正则表达式类型。用于存储正则表达式。

# SpringBoot 连接 MongoDB

# 环境配置

  • 在项目的pom文件中引入依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    
  • 在配置文件中配置连接信息

    spring:
        data:
            mongodb:
              host: 192.168.20.195:27017
              database: lowan-iot
              auto-index-creation: true
    
  • 在需要与mongodb数据库交互的地方注入 MongoTemplate

    @Resource
    private MongoTemplate mongoTemplate;
    

# 创建集合

  • 在项目启动成功后提前创建所有需要的集合

    // 创建实体,在实体的类上加入注解 Document
    @Data
    @Document("object_model_log")
    @CompoundIndex(def = "{'timestamp':1, 'deviceId':1}")
    public class ObjectModelDataLog {
    
        private String deviceId;
    
        private String messageType;
    
        private Long timestamp;
    }
    
    // 调用方法 MongoTemplate#createCollection(java.lang.Class<T>)
    mongoTemplate.createCollection(ObjectModelDataLog.class);
    // 或者调用重载方法 MongoTemplate#createCollection(java.lang.String)
    mongoTemplate.createCollection("object_model_log");
    
  • 动态创建集合

    MongoDB属于NoSQL的范畴,无schema模式设计,即使未提前创建集合,也可以在插入数据的时候根据Document动态创建集合

# 插入文档

插入文档需要有两个参数,第一个是集合的名称,第二个是需要插入的数据

 public void handle(List<Message> messages) {
     List<JSONObject> dataList = new ArrayList<>();
     for (Message message : messages) {
         if (message.getData().isEmpty()) {
             continue;
         }
         JSONObject data = new JSONObject(message.getData());
         data.put("deviceId", message.getDeviceId());
         data.put("timestamp", message.getTimestamp());
         data.put("messageType", message.getMessageType());
         dataList.add(data);
     }
     mongoTemplate.insert(dataList, ObjectModelDataLog.class);
}

# 查询文档

查询文档需要有三个参数,第一个为集合的名称,第二个为查询条件,第三个为查询结果的接收实体类型

// 第一个参数,集合名称
String collectionName = "object_model_log";

// 第二个参数,查询条件,对字段值进行过滤
Criteria criteria = Criteria.where("deviceId").is(query.getDeviceId());
criteria.and("messageType").is(query.getMessageType());
Query mongoQuery = new Query(criteria);

// 设置分页查询参数--若不需要分页,可忽略以下参数
mongoQuery.skip(((long) query.getOffset()))
    .limit(query.getPageSize())
    .with(Sort.by(Sort.Order.desc(DevLogKeys.TIMESTAMP)));

// 执行查询,并获取结果
List<JSONObject> list = mongoTemplate.find(mongoQuery, JSONObject.class, collectionName);

# 更新文档

更新文档也需要三个参数,第一个为集合的名称,第二个为查询条件,第三个为更新的字段值

// 集合名称
String collectionName = "object_model_log";

// 查询参数
Query query = new Query();
query.addCriteria(Criteria.where("deviceId").is(message.getDeviceId()));

// 需要更新的值
Update update = new Update();
update.set("timestamp", message.getTimestamp());
JSONObject data = message.getData();
for (Map.Entry<String, Object> entry : data.entrySet()) {
    if (entry.getValue() != null) {
        update.set(entry.getKey(), entry.getValue());
    }
}
// 执行更新操作
mongoTemplate.update(query, update, collectionName);

# 删除文档

// 集合名称
String collectionName = "object_model_log";

// 查询参数
Query query = new Query();
query.addCriteria(Criteria.where("deviceId").is(message.getDeviceId()));

// 执行删除
mongoTemplate.remove(query, collectionName);