MongoDB

课程目标:

  • 理解MongoDB的业务场景,熟悉MongoDB的简介、特点和体系结构、数据类型等。
  • 能够在windows和Linux下安装和启动MongoDB、图形化界面Compass的安装使用。
  • 掌握MongoDB基本常用命令实现数据的CRUD。
  • 掌握MongoDB的索引类型、索引管理、执行计划。
  • 使用Spring Data MongoDB完成文章评论业务的开发。

1.MongoDB相关概念

1.1业务应用场景

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

解释:“三高”需求:

  • High performance 对数据库高并发读写的需求
  • Huge Storage 对海量数据的高效率存储和访问的需求
  • High Scalability && High Availlability 对数据库的高可扩展性和高可用性的需求

而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%高可用
  • 应用需要大量的地理位置查询、文本查询
  • 如果上述有一个符合,可以考虑MongoDB,2个以上的符合,选择MongoDB绝不会后悔

1.2MongoDB简介

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

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

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

1.3Windows系统中安装启动

第一步下载:下载地址:MongoDB Community Download | MongoDB

MongoDB_第1张图片

 第二步:解压安装启动

将压缩包解压到一个目录中,在解压目录中,手动创建一个目录用于存放数据文件,如data/db

方式一:命令行参数方式启动服务

在bin目录中打开命令行提示符,输入以下命令:

mongod --dbpath=..\data\db

方式二:配置文件方式启动服务

在解压文件中新建config文件夹,该文件夹中新建配置文件mongod.conf,内容参考如下:

MongoDB_第2张图片

 1.4Shell连接(mongo命令)

在命令提示符输入以下shell命令即可完成登录

mongo
或
mongo --host=127.0.0.1 --port=27017

查看已经有的数据库

show databases

退出mongodb

exit

更多参数可以通过帮助查看:

mongo --help

提示:MongoDB javascript shell是一个基于javascript的解释器,故是支持js程序的。

1.5Compass-图形化界面客户端

到MongoDB官网下载MongoDB Compass

地址:https://www.mongodb.com/download.center/v2/compass?initial=true

如果是下载安装版,则按照步骤安装;如果是下载压缩版,直接解压,执行里面的MongoDBCompassCommunity.exe文件即可。

在打开的界面中,输入主机地址、端口等相关信息,点击连接:

MongoDB_第3张图片

 提示:连接之前,使用1.3中命令mongod --dbpath=..\data\db开启的服务不要关闭

2.基本常用命令

2.1数据库操作

2.1.1选择和创建数据库

选择和创建数据库的语法格式:

use 数据库名称

如果数据库不存在则自动创建,例如,以下语句创建spitdb数据库:

use spitdb

查看有权限查看的所有的数据库命令

show dbs
或
show databases

注意:在MOngoDB中,集合只有在内容插入后才会创建!就是说,创建集合(数据表)后要再插入一个文档记录,集合才会真正创建。

#查看当前正在使用的数据库命令

db

MongoDB中默认的数据库为test,如果你没有选择数据库,集合将存放在test数据库中。


数据库名可以是满足以下条件的任意UTF-8字符串。

  • 不能是空字符串("").
  • 不得含有' '(空格)、.、$、/、\和\()(空字符)。
  • 应全部小写
  • 最多64字节

有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。

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

2.1.2数据库的删除

MongoDB删除数据库的语法格式如下:

db.dropDatabase()

提示:主要用来删除已经持久化的数据库

2.2集合操作

集合,类似关系型数据库中的表。可以显示的创建,也可以隐式的创建

2.2.1集合的显示创建(了解)

基本语法格式:

db.createCollection(name)

参数说明:

  • name:要创建的集合名称

例如:创建一个名为mycollection的普通集合

db.createCollection("mycollection")

查看当前库中的表:show tables命令

show collections
或
show tables

集合的命名规范:

  • 集合名不能是空字符串""
  • 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾
  • 集合名不能以“system."开头,这是为系统集合保留的前缀

2.2.2集合的隐式创建

2.2.3集合的删除

集合删除语法格式如下:

db.collection.drop()
或
db.集合.drop()

返回值

如果成功删除选定集合,则drop()方法返回true,否则返回false.

例如:要删除mycollection集合

db.mycollection.drop()

2.3文档基本CRUD

文档(document)的数据结构和JSON基本一样。

所有存储在集合中的数据都是BSON格式。

2.3.1文档的插入

(1)单个文档插入

使用insert()或save()方法向集合中插入文档,语法如下:

bd.collection.insert(
   ,
   {
      writeConcern:,
      ordered:
    }
)

MongoDB_第4张图片

 【实例】要向comment的集合表中插入一条测试数据:

 提示:

1)comment集合如果不存在,则会隐式创建

2)mongo中的数字,默认情况下是double类型,如果要存整型,必须使用函数NumberInt(整型数字),否则取出来就有问题了

3)插入当前日期使用new Date()

4)插入的数据没有指定_id,会自动生成主键值

5)如果某字段没值,可以赋值为null,或不写该字段

执行后,如下,说明插入一个数据成功了。

writeResult({"nInserted":1})

注意:

  1. 文档中的键值对是有序的
  2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其它几种数据类型(甚至可以是整个嵌入的文档)。
  3. MongoDB区分类型和大小写
  4. MongoDB的文档不能有重复的键
  5. 文档的键是字符串,除了少数例外情况,键可以使用任意UTF-8字符

文档键命名规则:

  • 键不能含有\0(空字符)这个字符用来表示键的结尾
  • .和$有特别的意义,只有在特定情况下才能使用
  • 以下划线“_”开头的键是保留的(不是严格要求的)

(2)批量插入

语法:

MongoDB_第5张图片

【示例】批量插入多条文章评论:

MongoDB_第6张图片

 提示:

  • 插入时指定了_id,则主键就是该值
  • 如果某条数据插入失败,将会终止插入,但已经插入成功的数据不会回滚掉
  • 因为批量插入由于数据较多容易出现失败,因此,可以使用try catch进行异常扑获处理,测试的时候可以不处理。如(了解):

MongoDB_第7张图片

2.3.2文档的基本查询

(1)查询所有

如果我们要查询splt集合的所有文档,我们输入以下命令

db.comment.find()
或
db.comment.find({})

这里你会发现每条文档会有一个叫_id的字段,这个相当于我们原来关系数据库中表的主键,当你在插入文档记录时没有指定该字段,MongoDB会自动创建,其类型是ObjectID类型。

如果我们在插入文档记录时指定该字段也可以,其类型可以是ObjectID类型,也可以是MongoDB支持的任意类型。

如果我想按一定条件来查找,比如我想查找userId为1003的记录,怎么办,很简单!只要在find中添加参数即可,参数也是json格式,如下

db.comment.find({userId:"1003"})

如果你只需要返回符合条件的第一条数据,我们可以使用findOne命令来实现,语法和find一样。

如:查询用户编号是1003的记录,但之最多返回符合条件的第一条记录:

db.comment.findOne({userId:'1003'})

(2)投影查询(Projection Query)

如果要查询结果返回部分字段,则需要使用投影查询(不显示所有字段,只显示指定的字段)。

如:查询结果只显示_id、userId、nickname:

db.comment.find({userId:"1003"},{userId:1,nickname:1})

默认_id会显示。

如:查询结果只显示userId、nickname,不显示_id:

 

再例如:查询所有数据,但是只显示_id、userId、nickname:

db.comment.find({},{userId:1,nickname:1})

2.3.3文档的更新

(1)覆盖的修改

如果我们想修改_id为1的记录,点赞量为1001,输入以下语句:

db.comment.update({_id:"1"},{likenum:NumberInt(1001)})

执行后,我们会发现,这条文档除了likenum字段其它字段都不见了。

(2)局部修改

为了解决这个问题,我们需要使用修改器$set来实现,命令如下:

我们想修改_id为2的记录,浏览量为889,输入以下语句:

db.comment.update({_id:"2"},{$set:{likenum:NumberInt(889)}})

这样就ok啦

(3)批量的修改

更新所有用户为1003的用户的昵称为凯撒大帝

//默认只修改第一条数据
db.comment.update({userId:"1003"},{$set:{nickname:"凯撒2"}})
//修改所有符合条件的数据
db.comment.update({userId:"1003"},{$set:{nickname:"凯撒大帝"}},{multi:true})

提示:如果不加后面的参数,则只更新符合条件的第一条记录

(4)列值增长的修改

如果我们想实现对某列值在原有值的基础上进行增加或减少,可以使用$inc运算符来实现。

需求:对3号数据的点赞数,每次递增1

db.comment.update({_id:"3"},{$inc:(likenum:NumberInt(1)}})

2.3.4删除文档

删除文档的语法结果:

db.集合名称.remove(条件)

以下语句可以将数据全部删除,请慎重

db.comment.remove({})

如果删除_id=1的记录,输入以下语句

db.comment.remove({_id:"1"})

2.4文档的分页查询

2.4.1统计查询

统计查询使用count()方法,语法如下:

db.collection.count(query,options)

MongoDB_第8张图片

 【示例】

(1)统计所有记录数:

统计comment集合的所有记录数:

db.comment.count()

(2)按条件统计记录数

例如:统计userId为1003的记录条数

db.comment.count({userId:"1003"})

提示:默认情况下count()方法返回符合条件的全部记录条数

2.4.2分页列表查询

可以使用limit()方法来读取指定数量的数据,使用skip()方法来跳过指定数量的数据。

基本语法如下所示:

db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)

如果你想返回指定条数的记录,可以在find方法后面调用limit来返回结果(TopN),默认值20,例如:

db.comment.find().limit(3)

skip方法同样接受一个数字参数作为跳过的记录条数.(前N个不要),默认值是0

db.comment.find().skip(3)

2.4.3排序查询

sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用1和-1来指定排序的·方式。其中1为升序排列,而-1是用于降序排列。

语法如下所示:

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

例如:

对userId降序排列,并对访问量进行升序排列

db.comment.find().sort({userid:-1,likenum:1})

提示:skip(),limit(),sort()三个放在一起执行的时候,执行的顺序是先sort(),然后是skip(),最后显示的是limit(),和命令编写顺序无关。

MongoDB_第9张图片

2.5文档的更多查询

2.5.1正则的复杂条件查询

MonoDB的模糊查询是通过正则表达式的方式实现的。格式为:

db.collection.find({field:/正则表达式/})
或
db.集合.find({字段:/正则表达式/})

提示:正则表达式是js的语法,直接量的写法。

例如:我要查询评论内容包含”开水“的所有文档,代码如下:

db.comment.find({content:/开水/})

如果要查询评论的内容中以”专家“开头的,代码如下:

db.comment.find({content:/^专家/})

2.5.2比较查询

<,<=,>,>=这个操作符也是很简单的,格式如下:

  • db.集合名称.find({"field":{$gt:value}})//大于:field>value
  • db.集合名称.find({"field":{$lt:value}})//小于:field
  • db.集合名称.find({"field":{$gte:value}})//大于等于:field>=value
  • db.集合名称.find({"field":{$lte:value}})//小于等于:field<=value
  • db.集合名称.find({"field":{$ne:value}})//不等于:field!=value

示例:查询评论点赞数量大于700的记录

db.comment.find({likenum:{$gt:NumberInt(700)}})

2.5.3包含查询

包含使用$in操作符

示例:查询评论的集合中userid字段包含1003或1004文档

db.comment.find({userid:{$in:["1003","1004"]}})

不包含使用$nin操作符

示例:查询评论集合中userid字段不包含1003和1004的文档

db.comment.find({userid:{$nin:["1003","1004"]}})

2.5.4条件连接查询

我们如果需要查询同时满足两个以上条件,需要使用$and操作符将条件进行关联。(相当于SQL的and)格式为:

$and:[{ },{ ],{ }]

示例:查询评论集合中likenum大于等于700并且小于2000的文档:

db.comment.find({$and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lte:NumberInt(2000)}}]})

如果两个以上条件之间是或者的关系,我们使用$or操作符进行关联,与前面and的使用方式相同。格式为:

$or:[{ },{ },{ }]

示例:查询评论集合中userid为1003,或者点赞数小于1000的文档记录

db.comment.find({$or:[{userid:"1003"},{likenum:{$lt:1000}}]})

2.6常用命令小结

选择切换数据库:use articledb

插入数据:db.comment.insert({bson数据})

查询所有数据:db.comment.find()

条件查询数据:db.comment.find({条件})

查询符合条件的第一条记录:db.comment.findOne({条件})

查询符合条件的前几条记录:db.comment.find({查询条件}).limit(条数)

查询符合条件的跳过的记录:db.comment.find({查询条件}).skip(条数)

修改数据:db.comment.update({条件},{修改后的数据})或db.comment.update({条件},{$set:{要修改部分的字段:数据}})

修改数据并自增某字段值:db.comment.update({条件},{$inc:{自增的字段:步进值}})

删除数据:db.comment.remove({条件})

统计查询:db.comment.count({条件})

模糊查询:db.comment.find({字段名:/正则表达式/})

条件比较运算:db.comment.find({字段名:{$gt:值}})

包含查询:db.comment.find({字段名:{$in:[值1,值2]}})或db.comment.find({字段名:{$nin:[值1,值2]}})

条件连接查询:db.comment.find({$and:[{条件1},{条件2}]})或db.comment.find({$or:[{条件1},{条件2}]})

3.索引-Index

3.1概述

索引支持在MongoDB中高效的执行查询。如果没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档,这种扫描全集合的查询效率是非常底的,特别在处理大量的数据时,查询可能要花费几十秒甚至几分钟,这对网站的性能是非常致命的。

如果查询存在适当的索引,MongoDB可以使用该索引限定必须检查的文档数。

索引是特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分。索引存储特定字段或一组字段的值,按字段值排序。索引项的排序支持有效的相等匹配和基于范围的查询操作。此外,MongoDB还可以使用索引中的排序返回排序结果。

官方文档:Indexes — MongoDB Manualhttps://docs.mongodb.com/manual/indexes/

MongoDB索引使用B树数据结构(确切的说是B-Tree,MYSQL是B+Tree)

3.2索引的类型

3.2.1单字段索引

MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引,对于单个字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为MOngoDB可以在任何方向上遍历索引。

MongoDB_第10张图片

3.2.2复合索引

MongoDB还支持多个字段的用户定义索引,即复合索引,复合索引中列出的字段顺序具有重要意义,例如,如果复合索引由{userid:1,score:-1}组成,则索引首先按userid正常排序,然后在每个userid的值内,再按score倒序排序。

MongoDB_第11张图片

3.2.3其它索引

地理空间索引、文本索引、哈希索引

  • 地理空间索引:为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面几何的二维球面索引。
  • 文本索引:MongoDB提供了一种文本索引类型,支持在集合中搜索字符串的内容。这些文本索引不存储特定于语言的停止词,而将集合中的词作为词干,只存储根词。
  • 哈希索引:为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的值分布更加随机,但只支持相等匹配,不支持基于范围的查询。

3.3索引的管理操作

3.3.1索引的查看

说明:返回一个集合中的所有索引的数组

语法:

db.collection.getIndexes()

提示:该语法命令运行要求MongoDB3.0+

【示例】查看comment集合中所有的索引情况

MongoDB_第12张图片

3.3.2索引的创建

 MongoDB_第13张图片

 MongoDB_第14张图片

 MongoDB_第15张图片

3.3.3索引的移除

说明:可以移除指定的索引,或移除所有的索引

一、指定索引的移除

语法:

db.collection.dropIndex(index)

MongoDB_第16张图片

 【示例】删除comment集合中userid字段上的升序索引:

db.comment.dropIndex({userid:1})

二、所有索引的移除

语法:

db.collection.dropIndexes()

【示例】删除spit集合中所有索引

MongoDB_第17张图片

3.4索引的使用

3.4.1执行计划

分析查询性能,通常使用执行计划来查看查询的情况,如查询耗费的时间,是否基于索引查询等。

语法:

db.collection.find(query,options).explain(options)

MongoDB_第18张图片

 MongoDB_第19张图片

 3.4.2涵盖的查询

当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存,这些覆盖的查询非常有效。

MongoDB_第20张图片

4.文章评论

4.1文章评论的基本增删改查

1、文章评论实体类的编写:

MongoDB_第21张图片

 2、文章评论基本增删改查:

dao层:

MongoDB_第22张图片

 service层:

MongoDB_第23张图片

 测试类:

MongoDB_第24张图片

 4.2根据上级ID查询文章评论的分页列表

(1)CommentRepository新增方法定义

//根据父id查询子评论的分页列表
Page findByParentId(String parentId,Pageable pageable)

(2)CommentService新增方法

MongoDB_第25张图片

 (3)测试类:

MongoDB_第26张图片

 4.3MongoTemplate实现评论点赞

(1)service层注入mongoTemplate

MongoDB_第27张图片

 (2)service层编写更新方法

MongoDB_第28张图片

 (3)测试类:

MongoDB_第29张图片

 5.MongoDB集群和安全

课程目标:

  • MongoDB的副本集:操作、主要概念、故障转移、选举规则
  • MOngoDB的分片集群:概念、优点、操作、分片策略、故障转移
  • MongoDB的安全认证

5.1副本集-Replica Sets

5.1.1简介

Mongodb中副本集(Replica Set)是一组维护相同数据集的mongod服务。副本集可提供冗余和高可用性,是所有生产部署的基础。

也可以说,副本集类似于有自动故障恢复功能的主从集群。通俗的将就是用多台机器进行同一数据的异步同步,从而使多台机器拥有统一数据的多个副本,并且当主库当掉时不需要用户干预的情况下自动切换其它备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。

(1)冗余和数据可用性

复制提供冗余并提高数据可用性,通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别的容错功能,以防止丢失单个数据库服务器。

(2)MongoDB中的复制

副本集是一组维护相同数据集的mongod示例。副本集包含多个数据承载节点和可选的一个仲裁节点。在承载数据的节点中,一个且仅一个成员被视为主节点,而其它节点被视为次要(从)节点。

主节点接收所有写操作。副本集只能有一个主要能够确认具有{w:"most"}写入关注的写入;虽然在某些情况下,另一个mongod实例可能展示认为自己也是主要的。主要记录其操作日志中的数据集的所有更改,即oplog。辅助(副本)节点复制主节点的oplog并将操作应用于其数据集,以使辅助接点的数据集反映主节点的数据集。如果主要人员不在,则符合条件的中学将举行选举以选出新的主要人员。

(3)主从复制和副本集区别

主从集群和副本集最大的区别就是副本集没有固定的“主节点”;整个集群会选出一个“主节点”,当其挂掉后,又在剩下的从节点中选中其它节点为“主节点”,副本集总有一个活跃点(主、primary)和一个或多个备份节点(从\secondary).

5.1.2副本集的三个角色

副本集有两种类型三种角色

两种类型:

  • 主节点(Primary)类型:数据操作的主要连接点,可读写。
  • 次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举。

三种角色:

主要成员(Primary):主要接收所有写操作,就是主节点。

副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型。

仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。

5.1.3副本集架构目标

一主一副本一仲栽

MongoDB_第30张图片

 5.1.4副本集的创建

5.1.5 副本集的数据读写操作

5.1.6主节点的选举原则

5.1.7故障测试

你可能感兴趣的:(mongodb)