课程目标:
传统的关系型数据库(如MYSQL),在数据操作的“三高”需求以及应对web2.0的网站需求面前,显得力不从心。
解释:“三高”需求:
而MongoDB可应对“三高”需求。
具体的应用场景如:
1)社交场景,使用MongoDB存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。
2)游戏场景,实现MongoDB存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、高效率存储和访问。
3)物流场景:使用MongoDB存储订单信息,订单状态在运送过程中会不断更新。以MongoDB内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
4)物联网场景,使用MongoDB存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度分析。
5)视频直播,使用MOngoDB存储用户信息、点赞互动信息等。
这些应用场景中,数据操作方面的共同特点是:
对于这样的数据,我们更适合使用MongoDB来实现数据的存储。
什么时候选择MongoDB?
在架构选型上,除了上述的三个特点外,如果你还犹豫是否要选择它?可以考虑以下的一些问题:
MongoDB是一个开源、高性能、无模式的文档型数据库,当初的设计就是用于简化开发和方便扩展,是NoSQL数据库产品中的一种,是最像关系型数据库(MYSQL)的非关系型数据库。
它支持的数据结构非常松散,是一种类似于JSON的格式叫BSON,所以它既可以存储比较复杂的数据类型,又相当的灵活。
MongoDB中的记录是一个文档,它是一个由字段和值对组成的数据结构。MongoDB文档类似于JSON格式,即一个文档认为就是一个对象。字段的类型就是字符型。它的值除了使用基本的一些类型外,还可以包括其它文档、普通数组和文档数组。
第一步下载:下载地址:MongoDB Community Download | MongoDB
第二步:解压安装启动
将压缩包解压到一个目录中,在解压目录中,手动创建一个目录用于存放数据文件,如data/db
方式一:命令行参数方式启动服务
在bin目录中打开命令行提示符,输入以下命令:
mongod --dbpath=..\data\db
方式二:配置文件方式启动服务
在解压文件中新建config文件夹,该文件夹中新建配置文件mongod.conf,内容参考如下:
在命令提示符输入以下shell命令即可完成登录
mongo
或
mongo --host=127.0.0.1 --port=27017
查看已经有的数据库
show databases
退出mongodb
exit
更多参数可以通过帮助查看:
mongo --help
提示:MongoDB javascript shell是一个基于javascript的解释器,故是支持js程序的。
到MongoDB官网下载MongoDB Compass
地址:https://www.mongodb.com/download.center/v2/compass?initial=true
如果是下载安装版,则按照步骤安装;如果是下载压缩版,直接解压,执行里面的MongoDBCompassCommunity.exe文件即可。
在打开的界面中,输入主机地址、端口等相关信息,点击连接:
提示:连接之前,使用1.3中命令mongod --dbpath=..\data\db开启的服务不要关闭
选择和创建数据库的语法格式:
use 数据库名称
如果数据库不存在则自动创建,例如,以下语句创建spitdb数据库:
use spitdb
查看有权限查看的所有的数据库命令
show dbs
或
show databases
注意:在MOngoDB中,集合只有在内容插入后才会创建!就是说,创建集合(数据表)后要再插入一个文档记录,集合才会真正创建。
#查看当前正在使用的数据库命令
db
MongoDB中默认的数据库为test,如果你没有选择数据库,集合将存放在test数据库中。
数据库名可以是满足以下条件的任意UTF-8字符串。
有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。
MongoDB删除数据库的语法格式如下:
db.dropDatabase()
提示:主要用来删除已经持久化的数据库
集合,类似关系型数据库中的表。可以显示的创建,也可以隐式的创建
基本语法格式:
db.createCollection(name)
参数说明:
例如:创建一个名为mycollection的普通集合
db.createCollection("mycollection")
查看当前库中的表:show tables命令
show collections
或
show tables
集合的命名规范:
集合删除语法格式如下:
db.collection.drop()
或
db.集合.drop()
返回值
如果成功删除选定集合,则drop()方法返回true,否则返回false.
例如:要删除mycollection集合
db.mycollection.drop()
文档(document)的数据结构和JSON基本一样。
所有存储在集合中的数据都是BSON格式。
(1)单个文档插入
使用insert()或save()方法向集合中插入文档,语法如下:
bd.collection.insert(
,
{
writeConcern:,
ordered:
}
)
【实例】要向comment的集合表中插入一条测试数据:
提示:
1)comment集合如果不存在,则会隐式创建
2)mongo中的数字,默认情况下是double类型,如果要存整型,必须使用函数NumberInt(整型数字),否则取出来就有问题了
3)插入当前日期使用new Date()
4)插入的数据没有指定_id,会自动生成主键值
5)如果某字段没值,可以赋值为null,或不写该字段
执行后,如下,说明插入一个数据成功了。
writeResult({"nInserted":1})
注意:
文档键命名规则:
(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})
(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)}})
删除文档的语法结果:
db.集合名称.remove(条件)
以下语句可以将数据全部删除,请慎重
db.comment.remove({})
如果删除_id=1的记录,输入以下语句
db.comment.remove({_id:"1"})
统计查询使用count()方法,语法如下:
db.collection.count(query,options)
【示例】
(1)统计所有记录数:
统计comment集合的所有记录数:
db.comment.count()
(2)按条件统计记录数
例如:统计userId为1003的记录条数
db.comment.count({userId:"1003"})
提示:默认情况下count()方法返回符合条件的全部记录条数
可以使用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)
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(),和命令编写顺序无关。
MonoDB的模糊查询是通过正则表达式的方式实现的。格式为:
db.collection.find({field:/正则表达式/})
或
db.集合.find({字段:/正则表达式/})
提示:正则表达式是js的语法,直接量的写法。
例如:我要查询评论内容包含”开水“的所有文档,代码如下:
db.comment.find({content:/开水/})
如果要查询评论的内容中以”专家“开头的,代码如下:
db.comment.find({content:/^专家/})
<,<=,>,>=这个操作符也是很简单的,格式如下:
示例:查询评论点赞数量大于700的记录
db.comment.find({likenum:{$gt:NumberInt(700)}})
包含使用$in操作符
示例:查询评论的集合中userid字段包含1003或1004文档
db.comment.find({userid:{$in:["1003","1004"]}})
不包含使用$nin操作符
示例:查询评论集合中userid字段不包含1003和1004的文档
db.comment.find({userid:{$nin:["1003","1004"]}})
我们如果需要查询同时满足两个以上条件,需要使用$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}}]})
选择切换数据库: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}]})
索引支持在MongoDB中高效的执行查询。如果没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档,这种扫描全集合的查询效率是非常底的,特别在处理大量的数据时,查询可能要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
如果查询存在适当的索引,MongoDB可以使用该索引限定必须检查的文档数。
索引是特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分。索引存储特定字段或一组字段的值,按字段值排序。索引项的排序支持有效的相等匹配和基于范围的查询操作。此外,MongoDB还可以使用索引中的排序返回排序结果。
官方文档:Indexes — MongoDB Manualhttps://docs.mongodb.com/manual/indexes/
MongoDB索引使用B树数据结构(确切的说是B-Tree,MYSQL是B+Tree)
MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引,对于单个字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为MOngoDB可以在任何方向上遍历索引。
MongoDB还支持多个字段的用户定义索引,即复合索引,复合索引中列出的字段顺序具有重要意义,例如,如果复合索引由{userid:1,score:-1}组成,则索引首先按userid正常排序,然后在每个userid的值内,再按score倒序排序。
地理空间索引、文本索引、哈希索引
说明:返回一个集合中的所有索引的数组
语法:
db.collection.getIndexes()
提示:该语法命令运行要求MongoDB3.0+
【示例】查看comment集合中所有的索引情况
说明:可以移除指定的索引,或移除所有的索引
一、指定索引的移除
语法:
db.collection.dropIndex(index)
【示例】删除comment集合中userid字段上的升序索引:
db.comment.dropIndex({userid:1})
二、所有索引的移除
语法:
db.collection.dropIndexes()
【示例】删除spit集合中所有索引
分析查询性能,通常使用执行计划来查看查询的情况,如查询耗费的时间,是否基于索引查询等。
语法:
db.collection.find(query,options).explain(options)
当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存,这些覆盖的查询非常有效。
1、文章评论实体类的编写:
2、文章评论基本增删改查:
dao层:
service层:
测试类:
(1)CommentRepository新增方法定义
//根据父id查询子评论的分页列表
Page findByParentId(String parentId,Pageable pageable)
(2)CommentService新增方法
(3)测试类:
(1)service层注入mongoTemplate
(2)service层编写更新方法
(3)测试类:
课程目标:
Mongodb中副本集(Replica Set)是一组维护相同数据集的mongod服务。副本集可提供冗余和高可用性,是所有生产部署的基础。
也可以说,副本集类似于有自动故障恢复功能的主从集群。通俗的将就是用多台机器进行同一数据的异步同步,从而使多台机器拥有统一数据的多个副本,并且当主库当掉时不需要用户干预的情况下自动切换其它备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。
(1)冗余和数据可用性
复制提供冗余并提高数据可用性,通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别的容错功能,以防止丢失单个数据库服务器。
(2)MongoDB中的复制
副本集是一组维护相同数据集的mongod示例。副本集包含多个数据承载节点和可选的一个仲裁节点。在承载数据的节点中,一个且仅一个成员被视为主节点,而其它节点被视为次要(从)节点。
主节点接收所有写操作。副本集只能有一个主要能够确认具有{w:"most"}写入关注的写入;虽然在某些情况下,另一个mongod实例可能展示认为自己也是主要的。主要记录其操作日志中的数据集的所有更改,即oplog。辅助(副本)节点复制主节点的oplog并将操作应用于其数据集,以使辅助接点的数据集反映主节点的数据集。如果主要人员不在,则符合条件的中学将举行选举以选出新的主要人员。
(3)主从复制和副本集区别
主从集群和副本集最大的区别就是副本集没有固定的“主节点”;整个集群会选出一个“主节点”,当其挂掉后,又在剩下的从节点中选中其它节点为“主节点”,副本集总有一个活跃点(主、primary)和一个或多个备份节点(从\secondary).
副本集有两种类型三种角色
两种类型:
三种角色:
主要成员(Primary):主要接收所有写操作,就是主节点。
副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型。
仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。
一主一副本一仲栽