MongoDB

MongoDB


第一章 MongoDB相关概念

1.1 节 业务应用场景

  • 传统的关系型数据库(如MySQL),在数据操作的“三高”需求以及应对Web2.0的网站需求面前,显得力不从心。 解释:“三高”需求:

    • High performance - 对数据库高并发读写的需求。

    • Huge Storage - 对海量数据的高效率存储和访问的需求。

    • High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求。

  • 而MongoDB可应对“三高”需求;具体的应用场景如:

    1. 社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。
    2. 游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、高效率存储和访问。
    3. 物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
    4. 物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析。
    5. 视频直播,使用 MongoDB 存储用户信息、点赞互动信息等。
  • 这些应用场景中,数据操作方面的共同特点是:

    1. 数据量大
    2. 写入操作频繁(读写都很频繁)
    3. 价值较低的数据,对事务性要求不高

    对于这样的数据,我们更适合使用MongoDB来实现数据的存储。

  • 什么时候选择MongoDB ?

    • 在架构选型上,除了上述的三个特点外,如果你还犹豫是否要选择它?可以考虑以下的一些问题:

      • 应用不需要事务及复杂 join 支持

      • 新应用,需求会变,数据模型无法确定,想快速迭代开发

      • 应用需要2000-3000以上的读写QPS(更高也可以)

      • 应用需要TB甚至 PB 级别数据存储

      • 应用发展迅速,需要能快速水平扩展

      • 应用要求存储的数据不丢失

      • 应用需要99.999%高可用

      • 应用需要大量的地理位置查询、文本查询

    • 如果上述有1个符合,可以考虑 MongoDB,2个及以上的符合,选择 MongoDB 绝不会后悔。

1.2 节 MongoDB简介

  • MongoDB是一个开源、高性能、无模式的文档型数据库,当初的设计就是用于简化开发和方便扩展,是NoSQL数据库产品中的一种。是最像关系型数据库(MySQL)的非关系型数据库。

  • 它支持的数据结构非常松散,是一种类似于 JSON 的 格式叫BSON,所以它既可以存储比较复杂的数据类型,又相当的灵活。

  • MongoDB中的记录是一个文档,它是一个由字段和值对(field:value)组成的数据结构。MongoDB文档类似于JSON对象,即一个文档认为就是一个对象。字段的数据类型是字符型,它的值除了使用基本的一些类型外,还可以包括其他文档、普通数组和文档数组。

1.3 节 体系结构

  • MySQL和MongoDB对比
SQL术语/概念MongoDB数据/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据记录行/文档
columnfield数据字段/域
indexindex索引
table joins表连接/MongoDB不支持
primary keyprimary key主键/MongoDB自动将_id字段设置为主键

1.4 节 数据模型

  • MongoDB的最小存储单位就是文档(document)对象。文档(document)对象对应于关系型数据库的行。数据在MongoDB中以BSON(Binary-JSON)文档的格式存储在磁盘上。

  • BSON(Binary Serialized Document Format)是一种类json的一种二进制形式的存储格式,简称Binary JSON。BSON和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有JSON没有的一些数据类型,如Date和BinData类型。

  • BSON采用了类似于 C 语言结构体的名称、对表示方法,支持内嵌的文档对象和数组对象,具有轻量性、可遍历性、高效性的三个特点,可 以有效描述非结构化数据和结构化数据。这种格式的优点是灵活性高,但它的缺点是空间利用率不是很理想。

  • Bson中,除了基本的JSON类型:string,integer,boolean,double,null,array和object,mongo还使用了特殊的数据类型。这些类型包括 date,object id,binary data,regular expression 和code。每一个驱动都以特定语言的方式实现了这些类型,查看你的驱动的文档来获取详细信息。

BSON数据类型参考列表:

数据类型描述举例
字符串UTF-8字符串都可表示为字符串类型的数据{“x” : “foobar”}
对象id对象id是文档的12字节的唯一 ID{“X” :ObjectId() }
布尔值真或者假:true或者false{“x”:true}+
数组值的集合或者列表可以表示成数组{“x” : [“a”, “b”, “c”]}
32位整数类型不可用。JavaScript仅支持64位浮点数,所以32位整数会被 自动转换。shell是不支持该类型的,shell中默认会转换成64
64位整数不支持这个类型。shell会使用一个特殊的内嵌文档来显示64位整数shell是不支持该类型的,shell中默认会转换成64 位浮点数
64位浮点数shell中的数字就是这一种类型{“x”:3.14159,“y”:3}
null表示空值或者未定义的对象{“x”:null}
undefined文档中也可以使用未定义类型{“x”:undefined}
符号shell不支持,shell会将数据库中的符号类型的数据自动转换成字符串
正则表达式文档中可以包含正则表达式,采用JavaScript的正则表达式语法{“x” : /foobar/i}
代码文档中还可以包含JavaScript代码{“x” : function() { /* …… */ }}
二进制数据二进制数据可以由任意字节的串组成,不过shell中无法使用
最大值/最BSON包括一个特殊类型,表示可能的最大值。shell中没有这个类型。

1.5 MongoDB的特点

MongoDB主要有如下特点:

(1)高性能:

MongoDB提供高性能的数据持久性。特别是,对嵌入式数据模型的支持减少了数据库系统上的I/O活动。 索引支持更快的查询,并且可以包含来自嵌入式文档和数组的键。(文本索引解决搜索的需求、TTL索引解决历史数据自动过期的需求、地 理位置索引可用于构建各种 O2O 应用) mmapv1、wiredtiger、mongorocks(rocksdb)、in-memory 等多引擎支持满足各种场景需求。 Gridfs解决文件存储的需求。

(2)高可用性:

MongoDB的复制工具称为副本集(replica set),它可提供自动故障转移和数据冗余。

(3)高扩展性:

MongoDB提供了水平可扩展性作为其核心功能的一部分。 分片将数据分布在一组集群的机器上。(海量数据存储,服务能力水平扩展) 从3.4开始,MongoDB支持基于片键创建数据区域。在一个平衡的集群中,MongoDB将一个区域所覆盖的读写只定向到该区域内的那些片。

(4)丰富的查询支持:

MongoDB支持丰富的查询语言,支持读和写操作(CRUD),比如数据聚合、文本搜索和地理空间查询等。

(5)其他特点:如无模式(动态模式)、灵活的文档模型

第二章 MongoDB安装

2.1 Windows系统中的安装启动

1)点击安装

在这里插入图片描述

2)点击完整版

在这里插入图片描述

3)选择第一个网络服务

在这里插入图片描述

  • Run Service as Network Service user:以网络服务用户身份运行服务(默认)这是Windows内置的Windows用户账户
  • Run Services as a local or domain user:以本地或域用户身份运行服务对于现有本地用户账户
    • Domain填"."(小数点)即可
    • Account Name为当前Windows用户名
    • Account Password为Windows用户密码(注意不是PIN密码)
  • Service Name:指定服务名称,默认名称是MongoDB。如果您已拥有具有指定名称的服务,则必须选择另一个名称
  • Data Directory:指定数据目录,对应于–dbpath。如果该目录不存在,安装程序将创建该目录并设置对服务用户的目录访问权限
  • Log Directory:指定日志目录,该目录对应于–logpath。如果该目录不存在,安装程序将创建该目录并设置对服务用户的目录访问权限

4)不勾选ui界面下载

在这里插入图片描述

5)配置环境变量

在这里插入图片描述

6)开启服务自启

在这里插入图片描述

2.2 连接客户端

在这里插入图片描述

第三章 MongoDB CRUD操作

3.1 数据库操作命令

1)选择和创建数据库语法,如果数据库不存在创建数据库并使用,如果存在直接使用

use 数据库名

示例:

use demo_db;

注意:如果数据库是空的,它会在创建集合的时候一起创建;但不影响后续操作

2)查看所有数据库

show dbs
或 
show databases

3)查看当前正在使用的数据

db

4)删除数据库

use 库名   #切换到要删除的数据库
db.dropDatabase()

3.2 节 集合命令操作

1)创建集合

db.createCollection('name') # 集合名一定要加引号

2)显示当前库的所有集合

show collections
或
show tables

3)删除某个集合

db.集合名.drop()

4)集合重命名

db.集合名.renameCollection('newName')

3.3 节 文档操作命令

3.3.1 文档插入

1)插入文档

db.集合名.insert({要添加的数据})

示例:

db.c_demo.insert({user_id:NumberInt(1),user_name:'张三',user_age:NumberInt(18),create_time:new Date()})

提示:

  • c_demo集合如果不存在,则会隐式创建
  • mongo中的数字,默认情况下是double类型,如果要存整型,必须使用函数NumberInt(整型数字),否则取出来就有问题了。
  • 插入当前日期使用 new Date()
  • 插入的数据没有指定 _id ,会自动生成主键值
  • 如果某字段没值,可以赋值为null,或不写该字段。

2)批量插入

db.集合名.insertMany([{数据1},{数据2}...])

示例:

db.c_demo.insert([
	{user_id:NumberInt(1),user_name:'张三',user_age:NumberInt(18),create_time:new Date()},
	{user_id:NumberInt(1),user_name:'张三',user_age:NumberInt(18),create_time:new Date()},
	{user_id:NumberInt(2),user_name:'李四',user_age:NumberInt(18),create_time:new Date()}
])
3.3.2 文档更新

1)覆盖修改

db.集合名.update(查询条件,新的数据)

示例:

# 将查询到user_id:1的第一条数据覆盖
db.c_demo.update({user_id:NumberInt(1)},{user_name:'张三丰'}) 

2)局部修改

db.集合名.update({查询条件},{$set:{修改数据}})

示例:

# 将查询到user_id:1的第一条数据的user_name改为张三丰
db.c_demo.update({user_id:NumberInt(1)},{$set:{user_name:'张三丰'}}) 

3)批量修改

# 修改所有符合条件的数据
db.集合名.update({查询条件},{$set:{修改数据}},{multi:true}) 

示例:

# 将查询到user_id:1的所有数据的user_name都改为张三丰
db.c_demo.update({user_id:NumberInt(1)},{$set:{user_name:'张三丰'}},{multi:true})
3.3.3 文档删除

1)删除数据

# 删除所有符合条件的数据
db.集合名.remove({查询条件})

示例:

db.c_demo.remove({user_id:NumberInt(1)})

2)删除全部数据**【慎用】**

db.集合名.remove({})
3.3.4 文档查询

1)查询基本查询

db.集合名.find({}) #  查询所有  
或  
db.集合名.find()  # 查询所有
db.集合名.find({查询条件})

示例:

db.c_demo.find();
db.c_demo.find({user_id:NumberInt(2)})

2)投影查询

# 这里1表示显示的意思 0表示不显示的意思
db.集合名.find({查询条件},{显示字段}) 显示字段格式 {字段:1,字段:1,字段:0} 

示例:

# 查询的数据显只示 _id / user_id / user_name
db.c_demo.find({},{user_id:1,user_name:1})

3)条件查询

语法:

db.集合名称.find({$and:[{<key1>:<value1>}, {<key2>:<value2>}], ...}) # 和
db.集合名称.find({$or:[{<key1>: <value1>}, {<key2>:<value2>}]}) # 或
db.集合名称.find({ "field" : { $gt: value }}) # 大于: field > value 
db.集合名称.find({ "field" : { $lt: value }}) # 小于: field < value 
db.集合名称.find({ "field" : { $gte: value }}) # 大于等于: field >= value 
db.集合名称.find({ "field" : { $lte: value }}) # 小于等于: field <= value 
db.集合名称.find({ "field" : { $ne: value }}) # 不等于: field != value
db.集合名称.find({"field":{$in:[value1,value2]}}) # 包含
db.集合名称.find({"field":{$nin:[value1,value2]}}) # 不包含
db.集合名称.find({字段:/正则表达式/}) # 支持正则

示例1:

# 查询 user_id:1 和 user_name:"李四" 数据
db.c_demo.find({$and:[{user_id:NumberInt(2)},{user_name:'李四'}]})
# 查询 user_id:1 或 user_name:"王五" 数据
db.c_demo.find({$or:[{user_id:NumberInt(2)},{user_name:'王五'}]})

示例2:

# 查询user_id 为 1 或 2 的数据
db.c_demo.find({user_id:{$in:[NumberInt(1),NumberInt(2)]}})
# 查询user_id 不为 1 或 2 的数据
db.c_demo.find({user_id:{$nin:[NumberInt(1),NumberInt(2)]}})

示例3:

# 查询 user_name 以 张 开头的数据
db.c_demo.find({user_name:/^张/}) 
# 查询 user_name 包含 张三 的数据
db.c_demo.find({user_name:/张三/}) 
3.3.5 文档分页查询

1)语法

db.集合名.find().limit(NUMBER).skip(NUMBER) # limit(<查询文档条数>) skip(<跳过文档条数>)

2)示例:

# 查询前2条数据,跳过前1条数据
db.c_demo.find().limit(2).skip(1);
 # 查询前3条记录 默认值为20
db.c_demo.find().limit(3)
# 跳过前3条 默认值为0
db.c_demo.find().skip(3)

3)分页查询

# 每页2个,第二页开始:跳过前两条数据,接着值显示3和4条数据
#第一页 
db.c_demo.find().skip(0).limit(2) 
#第二页 
db.c_demo.find().skip(2).limit(2) 
#第三页 
db.c_demo.find().skip(4).limit(2)
3.3.6 统计查询

1)语法

db.集合名.count(<查询条件>);

2)示例:

# 统计所有数据
db.c_demo.count();
# 统计user_id:1的数据
db.c_demo.count({user_id:NumberInt(1)})
3.3.7 排序查询

1)语法:

db.集合名.find().sort(<{KEY:1}>)
或
db.集合名称.find().sort(<排序方式>)

2)升序 and 降序

# 升
db.c_demo.find().sort({user_id:-1})
# 降
db.c_demo.find().sort({_id:1})
3.3.8 skip(), limilt(), sort()连用
  • skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),后是显示的 limit(),和命令编写顺序无关。

第四章 MongoDB索引操作

4.1 节 查看索引

1)语法:

db.集合名.getIndexes()

2)示例:

db.c_demo.getIndexes();

4.2 节 索引创建

1)语法:

db.集合名.createIndex({字段:1/-1})  #1升序索引 -1降序索引

2)示例:

db.c_demo.createIndex({user_id:1})

4.3 节 索引移除

1)语法:

db.集合名.dropIndex(index)

2)示例:

db.c_demo.dropIndex({user_id:1})

学习链接:一篇文章解决MongoDB的所有问题 - Jeff的技术栈 - 博客园 (cnblogs.com)


第五章 SpringBoot整合 MongoDB

1)添加依赖

<!--mongodb-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

2)配置连接

spring:
  data:
    mongodb:
      host: 127.0.0.1
      database: demo
      port: 27017

3)创建po

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

@Data
@Document("c_user")//集合名不一致需要写上
public class User {
    @Id//MongoDB默认id为`_id`
    private String id;
    @Field("user_id")//不一致需写上
    private Integer userId;
    @Field("user_name")
    private String userName;
    @Field("user_age")
    private Integer userAge;
    @Field("create_time")
    private Date createTime;
}

4)创建dao

import com.study.po.User;
import org.springframework.data.mongodb.repository.MongoRepository;
//MongoRepository提供类了简单的方法
public interface UserDao extends MongoRepository<User,String> {
}

5)测试CRUD

import com.study.dao.UserDao;
import com.study.po.User;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.Date;
import java.util.List;

@SpringBootTest
public class MongodbDemoTests {

    @Autowired
    private UserDao userDao;//提供简单crud
    @Autowired
    private MongoTemplate mongoTemplate;//提供条件查询分页等
    @Test
    public void insertTest(){
        User user = new User();
        user.setId(null);
        user.setUserId(2);
        user.setUserName("张三丰");
        user.setUserAge(18);
        user.setCreateTime(new Date());
        userDao.insert(user);
    }
    @Test
    public void findAllTest(){
        List<User> users = userDao.findAll();
        users.forEach(System.out::println);
    }
    @Test
    public void deleteTest(){
        userDao.deleteById("64cb51b9bcd2ea6901e270a9");
    }
    @Test
    public void  selectByParams(){
        //构建查询条件
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId("64cb5368b01e47067fb95df8")));
        User user = mongoTemplate.findOne(query, User.class);
        System.out.println("user = " + user);
    }
    @Test
    public void  selectByParams1(){
        //构建查询条件
        Query query = new Query();
        query.addCriteria(Criteria.where("user_name").regex("张"));
        List<User> users = mongoTemplate.find(query, User.class);
        users.forEach(System.out::println);
    }
    @Test
    public void updateTest(){
        //构建条件
        Query query = new Query();
        query.addCriteria(Criteria.where("user_name").is("张三"));
        Update update = new Update();
        update.set("user_age",20);
        mongoTemplate.upsert(query,update,User.class);
    }
    @Test
    public void pageTest(){
        //构建查询条件
        Query query = new Query();
        //查询条数
        long count = mongoTemplate.count(query, User.class);
        System.out.println("count = " + count);
        //分页查询
        List<User> users = mongoTemplate.find(query.skip(1).limit(1), User.class);
        users.forEach(System.out::println);
    }
}

第六章 GridFS存储桶

上传文件

@SpringBootTest
public class MongodbDemoTests {
     @Autowired
    private GridFsTemplate gridFsTemplate;
    /**
     * 上传文件
     * @throws FileNotFoundException
     */
    @Test
    public void upLoad() throws FileNotFoundException {
        File file = new File("E:\\TestFile\\1.mp4");
        //获取文件名
        String fileName = file.getName();
        System.out.println("fileName = " + fileName);
        InputStream inputStream = new FileInputStream(file);
        //获取文件类型
        String contentType = file.getName().substring(fileName.lastIndexOf(".")+1,fileName.length());
        //存储文件返回id
        ObjectId objectId = gridFsTemplate.store(inputStream, fileName, contentType);
        System.out.println("objectId = " + objectId);
    }
}
  • 将文件上传到名为fs(默认)的存储桶中

删除文件

  /**
    * 删除文件
    */
    @Test
    public void deleteFile(){
        //构建查询条件,根据id查询
        Query query = new Query(Criteria.where("_id").is(new ObjectId("64cb5c9fb7ffc115846f2c96")));
        gridFsTemplate.delete(query);
    }

下载文件

  • 创建配置类
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MongoDBConfig {
    @Value("${spring.data.mongodb.database}")
    private String db;

    @Bean
    public GridFSBucket gridFSBucket(MongoClient mongoClient){
        MongoDatabase mongoDatabase = mongoClient.getDatabase(db);
        GridFSBucket bucket = GridFSBuckets.create(mongoDatabase);
        return bucket;
    }
}
  • 下载文件
	@Autowired
    private GridFSBucket gridFSBucket;

	@Test
    public void downLoad() throws IOException {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            //文件的id
            String id = "64cb5e15ed0d50684aa08dcc";
            //根据id查询文件
            Query query = new Query(Criteria.where("_id").is(new ObjectId(id)));
            //获得存储桶文件
            GridFSFile file = gridFsTemplate.findOne(query);
            //打开存储桶下载流
            GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(new ObjectId(id));
            //构建存储桶资源
            GridFsResource resource = new GridFsResource(file,gridFSDownloadStream);
            //获取输入流
            inputStream = resource.getInputStream();
            //创建输出流
            outputStream = new FileOutputStream(new File("E:\\TestFile\\3.mp4"));
            //读写
            byte[] bs = new byte[1024];
            int len;
            while ((len = inputStream.read(bs)) != -1) {
                outputStream.write(bs, 0, len);
                outputStream.flush();
            }
        } finally {
            //关流
            if (inputStream != null){
                inputStream.close();
            }
            if (outputStream != null){
                outputStream.close();
            }
        }
    }

自定义存储桶

@Configuration
public class MongoDBConfig {
	//获取配置文件中数据库信息
    @Value("${spring.data.mongodb.database}")
    String db;
    //注入操作桶对象
    @Bean(name = "gridFsMp4Template")
    public GridFsTemplate gridFsTestTemplate(SimpleMongoClientDatabaseFactory dbFactory, MongoConverter converter) {
        return new GridFsTemplate(dbFactory, converter, "mp4");
    }
    //GridFSBucket用于打开下载流
    @Bean(name="gridMp4BucketTemplate")
    public GridFSBucket getGridFSBucket(MongoClient mongoClient){
        MongoDatabase mongoDatabase = mongoClient.getDatabase(db);
        GridFSBucket bucket = GridFSBuckets.create(mongoDatabase,"mp4");
        return bucket;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值