爬梯:MongoDB入门到高级到SpringBoot-API

学习资料:黑马程序员

使用版本:mongodb 4.0.23

CentOs7

MongoDB

1. 入门

1.1 介绍

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

它支持的数据结构非常松散,是类似Json的Bson格式(二进制的Json),因此可以存储比较复杂的数据类型,且保持相当高的灵活性。

Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

应用场景:

  • 高并发:high performance ,对数据库高并发的读写(秒杀)

  • 大数据量:huge storage,海量数据的效率存储和访问(大数据时代)

  • 可扩展:high scalability,库表结构的扩展(加字段)

  • 高可用:high availability,数据库的集群(宕机)

基础概念:

  • 数据库:仓库,在仓库中存放集合;
  • 集合:类似于数组,集合中存放文档;
  • 文档:文档数据库中的最小单位,存储和操作的对象都是文档;

1.2 与传统关系型数据库的对比

在这里插入图片描述

在这里插入图片描述

1.3 下载

windows:https://www.mongodb.org/dl/win32

linux:https://www.mongodb.org/dl/linux

指引下载:https://www.mongodb.com/try/download/community

MongoDB的版本号偶数为稳定版,奇数为开发版;

MongoDB对32位的系统支持不佳,在3.2版本之后不再对32位系统提供支持。

1.4 安装

1.4.1 安装到linux

使用版本:mongodb 4.0.23

# 1.解压
[root@ct7_1 opt]# tar -zxvf mongodb-linux-x86_64-4.0.23.tgz
mongodb-linux-x86_64-4.0.23/LICENSE-Community.txt
mongodb-linux-x86_64-4.0.23/MPL-2
mongodb-linux-x86_64-4.0.23/README
mongodb-linux-x86_64-4.0.23/THIRD-PARTY-NOTICES
mongodb-linux-x86_64-4.0.23/bin/install_compass
mongodb-linux-x86_64-4.0.23/bin/mongo
mongodb-linux-x86_64-4.0.23/bin/mongod
mongodb-linux-x86_64-4.0.23/bin/mongos
[root@ct7_1 opt]# ls
apache-tomcat-8.5.58         images                              mongodb-linux-x86_64-4.0.23.tgz  pcre-8.44         tomcat8080
apache-tomcat-8.5.58.tar.gz  mongodb-linux-x86_64-3.0.6-rc2.tgz  nginx-1.18.0                           pcre-8.44.tar.gz  tomcat8081
containerd                   mongodb-linux-x86_64-4.0.23   nginx-1.18.0.tar.gz                    rabbitmq

# 2.移动文件夹
[root@ct7_1 opt]# mv ./mongodb-linux-x86_64-4.0.23 /usr/local/mongodb/

# 3.创建数据目录、日志目录
[root@ct7_1 opt]# mkdir /usr/local/mongodb/data /usr/local/mongodb/logs
[root@ct7_1 opt]# cd /usr/local/mongodb/
[root@ct7_1 mongodb]# ls
bin  data  LICENSE-Community.txt  logs  MPL-2  README  THIRD-PARTY-NOTICES
 
# 4.启动
[root@ct7_1 mongodb]# ./bin/mongod --dbpath=/usr/local/mongodb/data --logpath=/usr/local/mongodb/logs/mongdb.log --logappend --port=27017 -fork
about to fork child process, waiting until server is ready for connections.
forked process: 4485
child process started successfully, parent exiting

# 5.登录
[root@ct7_1 mongodb]# ./bin/mongo
MongoDB shell version v4.0.23
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("992c2f09-eed2-40df-803e-ff07e3e151f7") }
MongoDB server version: 4.0.23
---
The server generated these startup warnings when booting: 
        2021-02-22T21:14:51.660-08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
        2021-02-22T21:14:51.660-08:00: You are running this process as the root user, which is not recommended
        2021-02-22T21:14:51.660-08:00: This server is bound to localhost. Remote systems will be unable to connect to this server. Start the server with --bind_ip <address> to specify which IP addresses it should serve responses from, or with --bind_ip_all to bind to all interfaces. If this behavior is desired, start the server with --bind_ip 127.0.0.1 to disable this warning
        2021-02-22T21:14:51.660-08:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
        2021-02-22T21:14:51.660-08:00: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. We suggest setting it to 'never'
        2021-02-22T21:14:51.660-08:00: Soft rlimits too low
        2021-02-22T21:14:51.660-08:00:         currentValue: 1024
        2021-02-22T21:14:51.660-08:00:         recommendedMinimum: 64000
---
---
        Enable MongoDB's free cloud-based monitoring service, which will then receive and display
        metrics about your deployment (disk utilization, CPU, operation statistics, etc).

        The monitoring data will be available on a MongoDB website with a unique URL accessible to you
        and anyone you share the URL with. MongoDB may use this information to make product
        improvements and to suggest MongoDB products and deployment options to you.

        To enable free monitoring, run the following command: db.enableFreeMonitoring()
        To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
配置文件

绿色版是缺省了配置文件的,需要自行创建配置文件。

mongodb的配置文件只支持yaml格式

systemLog:  			# 日志
   destination: file	## MongoDB的所有日志以文件的形式输出
   path: "/usr/local/mongodb/logs/mongodb.log"
   logAppend: true		## mongod或mongos实例重启后日志追加在原日志文件末尾
storage:				# 存储
   journal:				## 启用持久性日志以确保数据文件保持有效和可恢复
      enabled: true
   dbPath: "/usr/local/mongodb/data"	## mongod实例存储数据的目录
processManagement:		# 进程
   fork: true			## mongos或mongod进程启用后台运行,守护进程模式
net:					# 网络
  bindIpAll: true		## 是否监听全部ip(不开启则默认只监听本机)/bindIp:绑定指定IP;
  port: 27017
security:				# 安全
  authorization: enabled # 授权模式

启动命令

# -f/-config
./bin/mongod -f mongodb.conf

然后防火墙开放端口,让远程可以访问

firewall-cmd --zone=public --add-port=27017/tcp --permanent
firewall-cmd --reload

1.4.2 安装到windows

教程视频

2. MongoDB基础

2.1 概念

  • 数据库:仓库,在仓库中存放集合;
  • 集合:类似于数组,集合中存放文档;
  • 文档:文档数据库中的最小单位,存储和操作的对象都是文档;

2.2 数据库的基本操作

查看数据库、选择数据库

# 查看数据库
> show databases
admin   0.000GB
config  0.000GB
local   0.000GB
# 选择数据库
> use admin
switched to db admin
> use admin2
switched to db admin2
> show databases
admin   0.000GB
config  0.000GB
local   0.000GB

ps:当选择一个不存在的数据库时不会报错,当该不存在的数据库中产生数据时,MongoDB会进行隐式创建。

  • admin:权限角度看这是一个“root”数据库。添加用户到admin库则该用户默认拥有整个mongodb的权限。一些特定的服务器端命令也只能从这个数据库运行:列出所有数据库、关闭mongod服务器;
  • local:当mongodb配置分片时,该库的内容不会被复制,既该库是一个本地单机的库;
  • config:当mongodb用户分片配置时,config数据库在内部使用,用于保存分片的相关信息

删除数据库

> show databases
admin       0.000GB
config      0.000GB
local       0.000GB
myDatabase  0.000GB
# 1.选择数据库
> use myDatabase
switched to db myDatabase
# 2.删除数据库
> db.dropDatabase()
{ "dropped" : "myDatabase", "ok" : 1 }
> show databases
admin   0.000GB
config  0.000GB
local   0.000GB

2.3 集合的基本操作

创建集合、查看集合、删除集合

# 创建集合
> db.createCollection('c1')
{ "ok" : 1 }

# 查看集合
> show collections
c1

> db.createCollection('c2')
{ "ok" : 1 }
> show collections
c1
c2
# 删除集合
> db.c1.drop()
true
> show collections
c2

2.4 文档的基本操作

2.4.1 创建文档

基础语法:db.集合名.insert({jason})

> show databases
admin   0.000GB
config  0.000GB
local   0.000GB
> use test1
switched to db test1
# 创建文档
> db.c1.insert({name:'石似心',age:25})
WriteResult({ "nInserted" : 1 })
# 查看文档
> db.c1.find()
{ "_id" : ObjectId("60349565d312509840f9662c"), "name" : "石似心", "age" : 25 }
> db.c1.insert({color:"红色"})
WriteResult({ "nInserted" : 1 })
> db.c1.find()
{ "_id" : ObjectId("60349565d312509840f9662c"), "name" : "石似心", "age" : 25 }
{ "_id" : ObjectId("60349586d312509840f9662d"), "color" : "红色" }

ps:MongoDB的ID自动创建的、全球唯一的ID

在这里插入图片描述

创建数据手动存入ID(不推荐)

# 带上id键:_id
> db.c2.insert({_id:1,address:"广州市"})
WriteResult({ "nInserted" : 1 })
> db.c2.find()
{ "_id" : 1, "address" : "广州市" }

一次性创建多条文档

# 使用数组[]
> db.c2.insert([
	{sex:"男"},
	{hair:"soft"},
	{fat:"no"}
])
BulkWriteResult({
	"writeErrors" : [ ],
	"writeConcernErrors" : [ ],
	"nInserted" : 3,
	"nUpserted" : 0,
	"nMatched" : 0,
	"nModified" : 0,
	"nRemoved" : 0,
	"upserted" : [ ]
})
> db.c2.find()
{ "_id" : 1, "address" : "广州市" }
{ "_id" : ObjectId("60349744d312509840f9662e") }
{ "_id" : ObjectId("603497afd312509840f9662f"), "sex" : "男" }
{ "_id" : ObjectId("603497afd312509840f96630"), "hair" : "soft" }
{ "_id" : ObjectId("603497afd312509840f96631"), "fat" : "no" }

使用循环插入多条文档

ps:MongoDB支持部分js语法

# 使用循环
> for(var i=0;i<10;i++){
	db.c2.insert({province:"广东",number:i})
}
# 由于循环是每次执行一条创建命令,所以打印的结果是最后一条创建命令的结果
WriteResult({ "nInserted" : 1 })
> db.c2.find()
{ "_id" : 1, "address" : "广州市" }
{ "_id" : ObjectId("60349744d312509840f9662e") }
{ "_id" : ObjectId("603497afd312509840f9662f"), "sex" : "男" }
{ "_id" : ObjectId("603497afd312509840f96630"), "hair" : "soft" }
{ "_id" : ObjectId("603497afd312509840f96631"), "fat" : "no" }
{ "_id" : ObjectId("60349996d312509840f96632"), "province" : "广东", "number" : 0 }
{ "_id" : ObjectId("60349996d312509840f96633"), "province" : "广东", "number" : 1 }
{ "_id" : ObjectId("60349996d312509840f96634"), "province" : "广东", "number" : 2 }
{ "_id" : ObjectId("60349996d312509840f96635"), "province" : "广东", "number" : 3 }
{ "_id" : ObjectId("60349996d312509840f96636"), "province" : "广东", "number" : 4 }
{ "_id" : ObjectId("60349996d312509840f96637"), "province" : "广东", "number" : 5 }
{ "_id" : ObjectId("60349996d312509840f96638"), "province" : "广东", "number" : 6 }
{ "_id" : ObjectId("60349996d312509840f96639"), "province" : "广东", "number" : 7 }
{ "_id" : ObjectId("60349996d312509840f9663a"), "province" : "广东", "number" : 8 }
{ "_id" : ObjectId("60349996d312509840f9663b"), "province" : "广东", "number" : 9 }

使用异常捕获

> try {
    db.c2.insert([
        {sex:"男"},
        {hair:"soft"},
        {fat:"no"}
    ])
} catch (e) {
	print (e)
}

当某条数据异常时,会打印出来

2.4.2 查询文档

查询文档

基础语法:db.集合名.find([{条件}[,{列}])

条件查询

# 查询fat=no
> db.c2.find({fat:"no"})
{ "_id" : ObjectId("603497afd312509840f96631"), "fat" : "no" }

# 查询number>3
> db.c2.find({number:{$gt:7}})
{ "_id" : ObjectId("60349996d312509840f9663a"), "province" : "广东", "number" : 8 }
{ "_id" : ObjectId("60349996d312509840f9663b"), "province" : "广东", "number" : 9 }

# 查询number=1,number=3,number=9
> db.c2.find({number:{$in:[1,3,9]}})
{ "_id" : ObjectId("60349996d312509840f96633"), "province" : "广东", "number" : 1 }
{ "_id" : ObjectId("60349996d312509840f96635"), "province" : "广东", "number" : 3 }
{ "_id" : ObjectId("60349996d312509840f9663b"), "province" : "广东", "number" : 9 }


转义符含义
$gt大于
$gte大于等于
$lt小于
$lte小于等于
$ne不等于
$in区间内
$nin不在区间内

列查询

ps:_id是每次都会返回的列,不受列查询影响

# 只显示sex列
> db.c2.find({},{sex:1})
{ "_id" : 1 }
{ "_id" : ObjectId("60349744d312509840f9662e") }
{ "_id" : ObjectId("603497afd312509840f9662f"), "sex" : "男" }
{ "_id" : ObjectId("603497afd312509840f96630") }
{ "_id" : ObjectId("603497afd312509840f96631") }
{ "_id" : ObjectId("60349996d312509840f96632") }
{ "_id" : ObjectId("60349996d312509840f96633") }
{ "_id" : ObjectId("60349996d312509840f96634") }
{ "_id" : ObjectId("60349996d312509840f96635") }
{ "_id" : ObjectId("60349996d312509840f96636") }
{ "_id" : ObjectId("60349996d312509840f96637") }
{ "_id" : ObjectId("60349996d312509840f96638") }
{ "_id" : ObjectId("60349996d312509840f96639") }
{ "_id" : ObjectId("60349996d312509840f9663a") }
{ "_id" : ObjectId("60349996d312509840f9663b") }
# 不显示sex列
> db.c2.find({},{sex:0})
{ "_id" : 1, "address" : "广州市" }
{ "_id" : ObjectId("60349744d312509840f9662e") }
{ "_id" : ObjectId("603497afd312509840f9662f") }
{ "_id" : ObjectId("603497afd312509840f96630"), "hair" : "soft" }
{ "_id" : ObjectId("603497afd312509840f96631"), "fat" : "no" }
{ "_id" : ObjectId("60349996d312509840f96632"), "province" : "广东", "number" : 0 }
{ "_id" : ObjectId("60349996d312509840f96633"), "province" : "广东", "number" : 1 }
{ "_id" : ObjectId("60349996d312509840f96634"), "province" : "广东", "number" : 2 }
{ "_id" : ObjectId("60349996d312509840f96635"), "province" : "广东", "number" : 3 }
{ "_id" : ObjectId("60349996d312509840f96636"), "province" : "广东", "number" : 4 }
{ "_id" : ObjectId("60349996d312509840f96637"), "province" : "广东", "number" : 5 }
{ "_id" : ObjectId("60349996d312509840f96638"), "province" : "广东", "number" : 6 }
{ "_id" : ObjectId("60349996d312509840f96639"), "province" : "广东", "number" : 7 }
{ "_id" : ObjectId("60349996d312509840f9663a"), "province" : "广东", "number" : 8 }
{ "_id" : ObjectId("60349996d312509840f9663b"), "province" : "广东", "number" : 9 }

格式化显示

db.集合名.find().pretty()
# 将文档json格式化显示

2.4.3 修改文档

基础语法:db.集合名.update([条件,新数据[,是否新增,是否修改多条])

# 初始数据
> for(var i=0;i<10;i++){
	db.c3.insert({_id:i,name:"小伦"+i,sex:"男"})
}
WriteResult({ "nInserted" : 1 })
> db.c3.find()
{ "_id" : 0, "name" : "小伦0", "sex" : "男" }
{ "_id" : 1, "name" : "小伦1", "sex" : "男" }
{ "_id" : 2, "name" : "小伦2", "sex" : "男" }
{ "_id" : 3, "name" : "小伦3", "sex" : "男" }
{ "_id" : 4, "name" : "小伦4", "sex" : "男" }
{ "_id" : 5, "name" : "小伦5", "sex" : "男" }
{ "_id" : 6, "name" : "小伦6", "sex" : "男" }
{ "_id" : 7, "name" : "小伦7", "sex" : "男" }
{ "_id" : 8, "name" : "小伦8", "sex" : "男" }
{ "_id" : 9, "name" : "小伦9", "sex" : "男" }

# 修改文档
> db.c3.update({name:"小伦3"},{name:"小杰"})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.c3.find()
{ "_id" : 0, "name" : "小伦0", "sex" : "男" }
{ "_id" : 1, "name" : "小伦1", "sex" : "男" }
{ "_id" : 2, "name" : "小伦2", "sex" : "男" }
{ "_id" : 3, "name" : "小杰" }
{ "_id" : 4, "name" : "小伦4", "sex" : "男" }
{ "_id" : 5, "name" : "小伦5", "sex" : "男" }
{ "_id" : 6, "name" : "小伦6", "sex" : "男" }
{ "_id" : 7, "name" : "小伦7", "sex" : "男" }
{ "_id" : 8, "name" : "小伦8", "sex" : "男" }
{ "_id" : 9, "name" : "小伦9", "sex" : "男" }

# 修改指定列(也可以是新增)
> db.c3.update({name:"小伦5"},{$set:{name:"小周"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.c3.find()
{ "_id" : 0, "name" : "小伦0", "sex" : "男" }
{ "_id" : 1, "name" : "小伦1", "sex" : "男" }
{ "_id" : 2, "name" : "小伦2", "sex" : "男" }
{ "_id" : 3, "name" : "小杰" }
{ "_id" : 4, "name" : "小伦4", "sex" : "男" }
{ "_id" : 5, "name" : "小周", "sex" : "男" }
{ "_id" : 6, "name" : "小伦6", "sex" : "男" }
{ "_id" : 7, "name" : "小伦7", "sex" : "男" }
{ "_id" : 8, "name" : "小伦8", "sex" : "男" }
{ "_id" : 9, "name" : "小伦9", "sex" : "男" }

# 修改文档的列名
> db.c3.update({_id:8},{$rename:{sex:"jj"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.c3.find()
{ "_id" : 0, "name" : "小伦0", "sex" : "男" }
{ "_id" : 1, "name" : "小伦1", "sex" : "男" }
{ "_id" : 2, "name" : "小伦2", "sex" : "男" }
{ "_id" : 3, "name" : "小杰" }
{ "_id" : 4, "name" : "小伦4", "sex" : "男" }
{ "_id" : 5, "name" : "小周", "sex" : "男" }
{ "_id" : 6, "name" : "小伦6", "sex" : "男" }
{ "_id" : 7, "name" : "小伦7", "sex" : "男" }
{ "_id" : 8, "name" : "小伦8", "jj" : "男" }
{ "_id" : 9, "name" : "小伦9", "sex" : "男" }

# 删除文档指定列
> db.c3.update({_id:9},{$set:{work:"singer"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.c3.find()
{ "_id" : 0, "name" : "小伦0", "sex" : "男" }
{ "_id" : 1, "name" : "小伦1", "sex" : "男" }
{ "_id" : 2, "name" : "小伦2", "sex" : "男" }
{ "_id" : 3, "name" : "小杰" }
{ "_id" : 4, "name" : "小伦4", "sex" : "男" }
{ "_id" : 5, "name" : "小周", "sex" : "男" }
{ "_id" : 6, "name" : "小伦6", "sex" : "男" }
{ "_id" : 7, "name" : "小伦7", "sex" : "男" }
{ "_id" : 8, "name" : "小伦8", "jj" : "男" }
{ "_id" : 9, "name" : "小伦9", "sex" : "男", "work" : "singer" }
> db.c3.update({_id:9},{$unset:{work}})
uncaught exception: ReferenceError: work is not defined :
@(shell):1:31
> db.c3.update({_id:9},{$unset:{work:1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.c3.find()
{ "_id" : 0, "name" : "小伦0", "sex" : "男" }
{ "_id" : 1, "name" : "小伦1", "sex" : "男" }
{ "_id" : 2, "name" : "小伦2", "sex" : "男" }
{ "_id" : 3, "name" : "小杰" }
{ "_id" : 4, "name" : "小伦4", "sex" : "男" }
{ "_id" : 5, "name" : "小周", "sex" : "男" }
{ "_id" : 6, "name" : "小伦6", "sex" : "男" }
{ "_id" : 7, "name" : "小伦7", "sex" : "男" }
{ "_id" : 8, "name" : "小伦8", "jj" : "男" }
{ "_id" : 9, "name" : "小伦9", "sex" : "男" }

# 组合修改器:修改指定列的值,修改指定列的名
> db.c3.update({_id:9},{
	$set:{name:"拓海"},
	$rename:{sex:"性别"}
})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.c3.find()
{ "_id" : 0, "name" : "小伦0", "sex" : "男" }
{ "_id" : 1, "name" : "小伦1", "sex" : "男" }
{ "_id" : 2, "name" : "小伦2", "sex" : "男" }
{ "_id" : 3, "name" : "小杰" }
{ "_id" : 4, "name" : "小伦4", "sex" : "男" }
{ "_id" : 5, "name" : "小周", "sex" : "男" }
{ "_id" : 6, "name" : "小伦6", "sex" : "男" }
{ "_id" : 7, "name" : "小伦7", "sex" : "男" }
{ "_id" : 8, "name" : "小伦8", "jj" : "男" }
{ "_id" : 9, "name" : "拓海", "性别" : "男" }
修改器含义
$inc递增
$rename重命名列
$set修改列值
$unset删除列

额外条件(了解)

  • 是否新增:如果条件匹配不到,是否新增:true|false(默认falce)
  • 是否修改多条:如果条件匹配到多条,是否全部修改:true|false
# 是否新增:不存在则插入
> db.c3.update({_id:100},{name:"叶湘伦"},true)
WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : 100 })
> db.c3.find()
{ "_id" : 0, "name" : "小伦0", "sex" : "男" }
{ "_id" : 1, "name" : "小伦1", "sex" : "男" }
{ "_id" : 2, "name" : "小伦2", "sex" : "男" }
{ "_id" : 3, "name" : "小杰" }
{ "_id" : 4, "name" : "小伦4", "sex" : "男" }
{ "_id" : 5, "name" : "小周", "sex" : "男" }
{ "_id" : 6, "name" : "小伦6", "sex" : "男" }
{ "_id" : 7, "name" : "小伦7", "sex" : "男" }
{ "_id" : 8, "name" : "小伦8", "jj" : "男" }
{ "_id" : 9, "name" : "拓海", "性别" : "男" }
{ "_id" : 100, "name" : "叶湘伦" }

# 是否修改多条
> db.c3.update({sex:"男"},{$set:{sex:"女"}},false,true)
WriteResult({ "nMatched" : 7, "nUpserted" : 0, "nModified" : 7 })
> db.c3.find()
{ "_id" : 0, "name" : "小伦0", "sex" : "女" }
{ "_id" : 1, "name" : "小伦1", "sex" : "女" }
{ "_id" : 2, "name" : "小伦2", "sex" : "女" }
{ "_id" : 3, "name" : "小杰" }
{ "_id" : 4, "name" : "小伦4", "sex" : "女" }
{ "_id" : 5, "name" : "小周", "sex" : "女" }
{ "_id" : 6, "name" : "小伦6", "sex" : "女" }
{ "_id" : 7, "name" : "小伦7", "sex" : "女" }
{ "_id" : 8, "name" : "小伦8", "jj" : "男" }
{ "_id" : 9, "name" : "拓海", "性别" : "男" }
{ "_id" : 100, "name" : "叶湘伦" }

2.4.4 删除文档

基础语法:db.集合名.remove([条件[,是否删除一条])

> db.c3.remove({sex:"女"},false)
WriteResult({ "nRemoved" : 7 })
> db.c3.find()
{ "_id" : 3, "name" : "小杰" }
{ "_id" : 8, "name" : "小伦8", "jj" : "男" }
{ "_id" : 9, "name" : "拓海", "性别" : "男" }
{ "_id" : 100, "name" : "叶湘伦" }

3. MongoDB高级

3.1 复杂查询

准备数据

db.c4.insert({_id:2,muscle:"背阔肌",})
db.c4.insert({_id:0,muscle:"斜方肌",})
db.c4.insert({_id:3,muscle:"胸肌",})
db.c4.insert({_id:1,muscle:"肱二头肌",})
db.c4.insert({_id:5,muscle:"股四头肌",})
db.c4.insert({_id:4,muscle:"腹直肌",})

3.1.1 统计 count

语法:db.集合名.count([条件])

> db.c4.count()
6
> db.c4.count({"_id":3})
1

3.1.2 正则 content

语法:db.集合名.find({列名:/正则表达式/})

> db.c4.find({muscle:/二/})
{ "_id" : 1, "muscle" : "肱二头肌" }

3.1.3 排序 sort

语法:db.集合名.find().sort([条件])

# 根据_id倒序:1表正序,-1表倒序
> db.c4.find().sort({_id:-1})
{ "_id" : 5, "muscle" : "股四头肌" }
{ "_id" : 4, "muscle" : "腹直肌" }
{ "_id" : 3, "muscle" : "胸肌" }
{ "_id" : 2, "muscle" : "背阔肌" }
{ "_id" : 1, "muscle" : "肱二头肌" }
{ "_id" : 0, "muscle" : "斜方肌" }

3.1.4 分页 limit

语法:db.集合名.find()[.sort().skip(跳过数)].limit(条数)

skip:跳过指定数量的文档

limit:限制查询的文档数量

skip公式:(当前页-1)*条数

# 查询前两条
> db.c4.find().sort({_id:1}).limit(2)
{ "_id" : 0, "muscle" : "斜方肌" }
{ "_id" : 1, "muscle" : "肱二头肌" }
# 查询第三、第四条
> db.c4.find().sort({_id:1}).skip(2).limit(2)
{ "_id" : 2, "muscle" : "背阔肌" }
{ "_id" : 3, "muscle" : "胸肌" }

3.1.5 管道器查询

$and	db.集合名.find({$and:[{条件1},{条件2}]})
$or		db.集合名.find({$or:[{条件1},{条件2}]})
$in		db.集合名.find({列名:{$in:["",""]})
$nin	db.集合名.find({列名:{$nin:["",""]})
$gt		db.集合名.find({列名:{$gt:""})
$lt

3.2 聚合查询

语法:db.集合名.aggregate([

​ {管道:{表达式}}

​ …

])

常用管道

$group 将集合中的文档分组,用于统计结果
$match 过滤数据,只输出复合条件的文档
$sort  聚合数据进行排序
$skip  跳过指定文档数
$limit 限制文档数
...

常用表达式

$sum 求和	$sum:1 同count表示统计
$avg 
$min
$max
...

分组统计

# 准备数据
db.c5.insert({_id:1,name:"a",sex:1,age:1})
db.c5.insert({_id:5,name:"b",sex:1,age:3})
db.c5.insert({_id:4,name:"t",sex:0,age:4})
db.c5.insert({_id:2,name:"e",sex:0,age:5})
db.c5.insert({_id:3,name:"h",sex:0,age:2})

# 分组统计 列总和
> db.c5.aggregate([
	{
		$group:{
			_id:"$sex",
			sumAge:{$sum:"$age"}
		}
	}
])
{ "_id" : 1, "sumAge" : 4 }
{ "_id" : 0, "sumAge" : 11 }

# 分组统计 文档数
> db.c5.aggregate([{
	$group:{
		_id:"$sex",
		total:{$sum:1}
	}
}])
{ "_id" : 1, "total" : 2 }
{ "_id" : 0, "total" : 3 }

不分组统计

# 求和、平均
> db.c5.aggregate([{
	$group:{
		_id:null,
        total:{$sum:1},
        avgAge:{$avg:"$age"}
    }
}])
{ "_id" : null, "total" : 5, "avgAge" : 3 }

分组统计、排序

> db.c5.aggregate([
	{
        $group:{
            _id:"$sex",
            totalSex:{$sum:1}
        }
	},
	{
		$sort:{
			totalSex:1
		}
	}
])
{ "_id" : 1, "totalSex" : 2 }
{ "_id" : 0, "totalSex" : 3 }

3.3 索引

优点:

  • 提高数据查询的效率,降低IO成本
  • 通过索引对数据进行排序,降低数据排序成本、CPU消耗

缺点:

  • 占有磁盘空间
  • 大量索引会影响数据插入和修改时的效率

3.3.1 创建索引

语法:db.集合名.createIndex(列[,额外选项])

  • 列:{键:1,…} 说明:1表升序
  • 额外选项:设置索引的名称或者唯一索引等
# 准备数据
> for(var i=0;i<100000;i++){
	db.c6.insert({name:"stone"+i,age:i})
}
WriteResult({ "nInserted" : 1 })
> db.c6.count()
100000

# 创建索引
> db.c6.createIndex({name:1})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}

# 创建索引 附带索引名称
> db.c6.createIndex({age:-1},{name:"ageIndex"})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}

# 复合索引
> db.c6.createIndex({name:1,age:1})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}
> db.c6.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_"
	},
	{
		"v" : 2,
		"key" : {
			"name" : 1,
			"age" : 1
		},
		"name" : "name_1_age_1"
	}
]

#唯一索引
> db.c6.createIndex({name:1},{unique:"name"})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}
> db.c6.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_"
	},
	{
		"v" : 2,
		"unique" : true,
		"key" : {
			"name" : 1
		},
		"name" : "name_1"
	}
]

3.3.2 查看索引

语法:db.集合名.getIndexes()

> db.c6.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_"
	},
	{
		"v" : 2,
		"key" : {
			"name" : 1
		},
		"name" : "name_1"
	},	
	{
		"v" : 2,
		"key" : {
			"age" : -1
		},
		"name" : "ageIndex"
	}
]

3.3.3 删除索引

语法:db.集合名.dropIndex(索引名)

db.集合名.dropIndexes()

# 删除指定索引
> db.c6.dropIndex("name_1")
{ "nIndexesWas" : 2, "ok" : 1 }

3.3.4 分析索引

语法:db.集合名.find().explain(“executionStats”)

# 结果解析
> db.c6.find({id:500}).explain("executionStats")
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "test1.c6",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"id" : {
				"$eq" : 500
			}
		},
		"winningPlan" : {
			"stage" : "COLLSCAN",
			"filter" : {
				"id" : {
					"$eq" : 500
				}
			},
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"executionStats" : {				# 执行计划相关统计信息
		"executionSuccess" : true,		# 执行成功的状态
		"nReturned" : 0,				# 返回结果的数量
		"executionTimeMillis" : 111,	# 执行所需时间,毫秒
		"totalKeysExamined" : 0,		# 索引检查的时间
		"totalDocsExamined" : 100001,	# 检查文档总数
		"executionStages" : {
			"stage" : "COLLSCAN",		# 索引扫描方式
			"filter" : {				# 过滤条件
				"id" : {
					"$eq" : 500
				}
			},
			"nReturned" : 0,			# 返回结果的数量
			"executionTimeMillisEstimate" : 8,	# 预估的执行时间,毫秒
			"works" : 100003,			# 工作单元数,查询会被派生为大量小的工作单元
			"advanced" : 0,				# 优先返回的结果数
			"needTime" : 100002,
			"needYield" : 0,
			"saveState" : 100,
			"restoreState" : 100,
			"isEOF" : 1,
			"direction" : "forward",	# 方向
			"docsExamined" : 100001		# 文档检查的数量
		}
	},
	"serverInfo" : {
		"host" : "ct7_1",
		"port" : 27017,
		"version" : "4.0.23",
		"gitVersion" : "8db30a63db1a9d84bdcad0c83369623f708e0397"
	},
	"ok" : 1
}

扫描方式:

  • COLLSCAN 全表扫描
  • IXSCAN 索引扫描
  • FETCH 根据索引去检索指定document

索引查询

# 无索引查询
> db.c6.find({age:1888}).explain("executionStats")
{
	"queryPlanner" : {
		...
	},
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 1,
		"executionTimeMillis" : 52,		# 执行时间
		"totalKeysExamined" : 0,
		"totalDocsExamined" : 100001,
		"executionStages" : {
			"stage" : "COLLSCAN",		# 扫描方式
			"filter" : {
				"age" : {
					"$eq" : 1888
				}
			},
			"nReturned" : 1,
			"executionTimeMillisEstimate" : 1,
			"works" : 100003,
			"advanced" : 1,
			"needTime" : 100001,
			"needYield" : 0,
			"saveState" : 100,
			"restoreState" : 100,
			"isEOF" : 1,
			"direction" : "forward",
			"docsExamined" : 100001
		}
	},
	"serverInfo" : {
		...
	},
	"ok" : 1
}

# 为age添加索引后 再次查询
> db.c6.find({age:1888}).explain("executionStats")
{
	"queryPlanner" : {
		...
	},
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 1,
		"executionTimeMillis" : 1,		# 执行时间
		"totalKeysExamined" : 1,
		"totalDocsExamined" : 1,
		"executionStages" : {
			"stage" : "FETCH",
			"nReturned" : 1,
			"executionTimeMillisEstimate" : 0,
			"works" : 2,
			"advanced" : 1,
			"needTime" : 0,
			"needYield" : 0,
			"saveState" : 0,
			"restoreState" : 0,
			"isEOF" : 1,
			"docsExamined" : 1,
			"alreadyHasObj" : 0,
			"inputStage" : {
				"stage" : "IXSCAN",		# 扫描方式
				"nReturned" : 1,
				"executionTimeMillisEstimate" : 0,
				"works" : 2,
				"advanced" : 1,
				"needTime" : 0,
				"needYield" : 0,
				"saveState" : 0,
				"restoreState" : 0,
				"isEOF" : 1,
				"keyPattern" : {
					"age" : 1
				},
				"indexName" : "age_1",
				"isMultiKey" : false,
				"multiKeyPaths" : {
					"age" : [ ]
				},
				"isUnique" : false,
				"isSparse" : false,
				"isPartial" : false,
				"indexVersion" : 2,
				"direction" : "forward",
				"indexBounds" : {
					"age" : [
						"[1888.0, 1888.0]"
					]
				},
				"keysExamined" : 1,
				"seeks" : 1,
				"dupsTested" : 0,
				"dupsDropped" : 0
			}
		}
	},
	"serverInfo" : {
		...
	},
	"ok" : 1
}

3.4 权限机制

创建账号:

db.createUser({
	user:"username",
	pwd:"password",
	roles:[{
		role:"roles",
		db:"database"
	}]
})

角色:

超级管理员角色:root
数据库用户角色:read、readWrite
数据库管理角色:dbAdmin、userAdmin
集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
备份恢复角色:backup、restore
所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase

3.4.1 开启验证模式

用户需要账号密码才能登陆mongodb

1、添加超级管理员
2、退出服务端
3、重新创建需要输入账号密码的服务(--auth
4、启动客户端服务访问
1、添加管理员
> use admin
switched to db admin
> show collections
system.version
# 创建管理员账号
> db.createUser({
	user:"admin",
	pwd:"admin123",
	roles:[{
		role:"root",
		db:"admin"
	}]
})
Successfully added user: {
	"user" : "admin",
	"roles" : [
		{
			"role" : "root",
			"db" : "admin"
		}
	]
}
> show collections
system.users
system.version

# 创建读写角色
> use test1
switched to db test1
> db.createUser({
	user:"test1",
	pwd:"admin123",
	roles:[{
		role:"readWrite",
		db:"test1"
	}]
})
Successfully added user: {
	"user" : "test1",
	"roles" : [
		{
			"role" : "readWrite",
			"db" : "test1"
		}
	]
}
> db.createUser({
	user:"test2",
	pwd:"admin123",
	roles:[{
		role:"read",
		db:"test1"
	}]
})
Successfully added user: {
	"user" : "test2",
	"roles" : [
		{
			"role" : "read",
			"db" : "test1"
		}
	]
}
2、关闭MongoDB服务端
[root@ct7_1 ~]# ps aux | grep mongodb
root       4485  0.6 12.4 1601212 124488 ?      SLl  Feb22  10:08 ./bin/mongod --dbpath=/usr/local/mongodb/data --logpath=/usr/local/mongodb/logs/mongdb.log --logappend --port=27017 -fork
root      20287  0.0  0.0 112648   952 pts/0    R+   23:11   0:00 grep --color=auto mongodb
...
> use admin
switched to db admin
# 关闭mongodb服务端
> db.shutdownServer()
server should be down...
...
[root@ct7_1 ~]# ps aux | grep mongodb
root      20329  0.0  0.0 112648   952 pts/0    R+   23:15   0:00 grep --color=auto mongodb
3、开启需要验证身份的MongoDB服务端

添加 --auth 命令

[root@ct7_1 ~]# /usr/local/mongodb/bin/mongod --dbpath=/usr/local/mongodb/data --logpath=/usr/local/mongodb/logs/mongdb.log --logappend --port=27017 -fork --auth
about to fork child process, waiting until server is ready for connections.
forked process: 20388
child process started successfully, parent exiting
4、启动mongo客户端

授权:

  • 登录直接认证:mongo ip:port/dbname -u username -p pwd
  • 先登录,选择数据库,然后认证:db.auth(username,pwd)

登录直接认证

[root@ct7_1 ~]# /usr/local/mongodb/bin/mongo 127.0.0.1:27017/admin -u admin -p admin123
MongoDB shell version v4.0.23
connecting to: mongodb://127.0.0.1:27017/admin?compressors=disabled&gssapiServiceName=mongodb
...
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
test1   0.004GB

先登录再认证

[root@ct7_1 ~]# /usr/local/mongodb/bin/mongo
MongoDB shell version v4.0.23
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
...
> use admin
switched to db admin
> db.auth("admin","admin123")
1
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
test1   0.004GB

3.5 备份还原

3.5.1 备份数据库

语法:

mongodump -h -port -u -p -d -o

-h		host 服务器IP(一把不写,默认本机
-port		 端口(一般不写,默认27017
-u		user 账号
-p		pwd  密码
-d		db   数据库(若不写,则全局导出
-o		open 备份到指定目录下

导出数据库

# 使用超级管理员 全局导出
[root@ct7_1 bin]# ./mongodump -u admin -p admin123 -o /usr/local/mongobak
2021-02-24T00:47:22.601-0800	writing admin.system.users to 
2021-02-24T00:47:22.613-0800	done dumping admin.system.users (3 documents)
2021-02-24T00:47:22.613-0800	writing admin.system.version to 
2021-02-24T00:47:22.625-0800	done dumping admin.system.version (2 documents)
2021-02-24T00:47:22.625-0800	writing test1.c1 to 
2021-02-24T00:47:22.637-0800	done dumping test1.c1 (1 document)
[root@ct7_1 bin]# cd /usr/local/mongobak/
[root@ct7_1 mongobak]# ls
admin  test1
[root@ct7_1 mongobak]# cd test1
[root@ct7_1 test1]# ls
c1.bson  c1.metadata.json
[root@ct7_1 test1]# cat c1.bson
(_id`6󿞖򒫦¸namahahaha
# c1集合中只有一个文档:{name:"ahahaha"}

# 导出指定数据库
# 指定数据库时,如果有专用账号则超级管理员无权导出
[root@ct7_1 bin]# ./mongodump -u admin -p admin123 -o /usr/local/mongobak -d test1
2021-02-24T00:51:55.865-0800	Failed: error connecting to db server: server returned error on SASL authentication step: Authentication failed.
# 使用读权限的账号可以导出
[root@ct7_1 bin]# ./mongodump -u test2 -p admin123 -o /usr/local/mongobak -d test1
2021-02-24T00:52:10.756-0800	writing test1.c1 to 
2021-02-24T00:52:10.767-0800	done dumping test1.c1 (1 document)
# 使用读写权限的账号可以导出
[root@ct7_1 bin]# ./mongodump -u test1 -p admin123 -o /usr/local/mongobak -d test1
2021-02-24T00:52:19.314-0800	writing test1.c1 to 
2021-02-24T00:52:19.326-0800	done dumping test1.c1 (1 document)

3.5.2 还原数据库

测试得:mongodb的还原都是增量还原,不会删除现有的而备份文件中没有的数据。

语法:

mongorestore -h -port -u -p -d --drop 文件夹目录

-h		host 服务器IP(一把不写,默认本机
-port		 端口(一般不写,默认27017
-u		user 账号
-p		pwd  密码
-d		db   数据库(若不写,则全局导入
--drop		 先删除数据再导入,否则覆盖

不用–drop

> db.c1.find()
{ "_id" : ObjectId("603610e05e96fb5011ed26b8"), "name" : "ahahaha" }
{ "_id" : ObjectId("60361b09b7059a594ad87034"), "name" : "ddd" }
# 删除ahahaha文档
> db.c1.remove({name:"ahahaha"})
WriteResult({ "nRemoved" : 1 })
> db.c1.find()
{ "_id" : ObjectId("60361b09b7059a594ad87034"), "name" : "ddd" }
> ^C
bye
# 还原有ahahaha的备份文件
[root@ct7_1 bin]# ./mongorestore -u test1 -p admin123 -d test1  /usr/local/mongobak/test1
2021-02-24T01:24:56.835-0800	the --db and --collection args should only be used when restoring from a BSON file. Other uses are deprecated and will not exist in the future; use --nsInclude instead
2021-02-24T01:24:56.835-0800	building a list of collections to restore from /usr/local/mongobak/test1 dir
2021-02-24T01:24:56.847-0800	reading metadata for test1.c1 from /usr/local/mongobak/test1/c1.metadata.json
2021-02-24T01:24:56.847-0800	restoring test1.c1 from /usr/local/mongobak/test1/c1.bson
2021-02-24T01:24:56.861-0800	no indexes to restore
2021-02-24T01:24:56.861-0800	finished restoring test1.c1 (1 document)
2021-02-24T01:24:56.861-0800	done
[root@ct7_1 bin]# ./mongo 127.0.0.1:27017/test1 -u test1 -p admin123
MongoDB shell version v4.0.23
connecting to: mongodb://127.0.0.1:27017/test1?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("97fc11a2-b625-41c5-bfac-a2b9d467ec16") }
MongoDB server version: 4.0.23
> db.c1.find()
{ "_id" : ObjectId("60361b09b7059a594ad87034"), "name" : "ddd" }
{ "_id" : ObjectId("603610e05e96fb5011ed26b8"), "name" : "ahahaha" }
# 结果是ddd并不会被删除,直接还原了ahahaha文档

使用–drop

> db.c1.find()
{ "_id" : ObjectId("60361b09b7059a594ad87034"), "name" : "ddd" }
{ "_id" : ObjectId("603610e05e96fb5011ed26b8"), "name" : "ahahaha" }
# 删除ahahaha文档
> db.c1.remove({name:"ahahaha"})
WriteResult({ "nRemoved" : 1 })
> db.c1.find()
{ "_id" : ObjectId("60361b09b7059a594ad87034"), "name" : "ddd" }
> ^C
bye
# 还原有ahahaha的备份文件
[root@ct7_1 bin]# ./mongorestore -u test1 -p admin123 -d test1 --drop /usr/local/mongobak/test1
2021-02-24T01:29:07.942-0800	the --db and --collection args should only be used when restoring from a BSON file. Other uses are deprecated and will not exist in the future; use --nsInclude instead
2021-02-24T01:29:07.942-0800	building a list of collections to restore from /usr/local/mongobak/test1 dir
2021-02-24T01:29:07.967-0800	reading metadata for test1.c1 from /usr/local/mongobak/test1/c1.metadata.json
2021-02-24T01:29:08.000-0800	restoring test1.c1 from /usr/local/mongobak/test1/c1.bson
2021-02-24T01:29:08.015-0800	no indexes to restore
2021-02-24T01:29:08.015-0800	finished restoring test1.c1 (1 document)
2021-02-24T01:29:08.015-0800	done
[root@ct7_1 bin]# ./mongo 127.0.0.1:27017/test1 -u test1 -p admin123
MongoDB shell version v4.0.23
connecting to: mongodb://127.0.0.1:27017/test1?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("dc0e8da7-6eba-4455-a427-90ed4d60de18") }
MongoDB server version: 4.0.23
> db.c1.find()
{ "_id" : ObjectId("603610e05e96fb5011ed26b8"), "name" : "ahahaha" }
# 会删除ddd的文档

3.6 可视化管理工具

adminMongo web/pc端网页管理 https://adminmongo.markmoffat.com

Robo 3T * 客户端软件 https://robomongo.org/download/

MongoVUE 客户端软件

RoBo 3T

下载安装启动~

因为mongodb开启了授权模式,所以连接时要填好账号密码:

在这里插入图片描述

管理工具界面

在这里插入图片描述

4. MongoDB For SpringBoot

4.1 创建项目

创建SpringBoot项目,引入MongoDB工具包

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

在属性文件中配置MongoDB链接方式

spring:
  data:
    mongodb:
      host: 192.168.0.106
      database: test1
      port: 27017
      # 或使用uri链接
      # uri: mongodb://192.168.0.106:27017/test1
      username: test1
      password: admin123

运行项目,可见控制台

2021-03-02 21:48:03.196  INFO 7744 --- [168.0.106:27017] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:2, serverValue:3}] to 192.168.0.106:27017

4.2 创建实体类

实体类对应MongoDB的集合(表)

@Data
// 映射集合名,可以省略,省略后则自动使用类名小写映射
@Document(collection = "c1")
// 复合索引
// @CompoundIndex(def = "{'userId':1,'seq':-1}")
public class Comment implements Serializable {

    // 映射 _id 主键
    @Id
    private String id;
    // 对应MongoDB的字段,如果名称一致则可不写
    @Field("content")
    private String content;
    private LocalDateTime publishTime;
    // 单字段索引
    @Indexed
    private String userId;
    private String nickname;
}

4.3 Dao、Service

import com.ssx.studymongodb.po.Comment;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 * 继承MongoRepository,提供了一些列操作MongoDB的方法
 * MongoRepository<Comment,String> 指定实体类和主键的数据类型
 * @author: huangzw
 * @create: 2021-03-02 22:08
 */
public interface CommentDao extends MongoRepository<Comment,String> {
}
@Service
public class CommentService {

    @Autowired
    private CommentDao commentDao;

    /**
     * 保存评论
     * @param comment
     */
    public void saveComment(Comment comment){
        //如需自定义主键,此处可以声明主键名称,如不指定,则MongoDB会自动生成主键
        Comment save = commentDao.save(comment);
        System.out.println("save:"+save.getId());
    }

    /**
     * 更新评论
     * @param comment
     */
    public void updateComment(Comment comment){
        Comment update = commentDao.save(comment);
        System.out.println("update:"+update.getId());
    }

    /**
     * 根据主键删除评论
     * @param id
     */
    public void deleteComment(String id){
        commentDao.deleteById(id);
    }

    /**
     * 查询全部评论
     * @return
     */
    public List<Comment> list(){
        List<Comment> all = commentDao.findAll();
        return all;
    }

    /**
     * 根据id查找评论
     * @param id
     * @return
     */
    public Comment getComment(String id){
        Comment byId = commentDao.findById(id).get();
        return byId;
    }

}

然后就可以编写测试类逐个测试体验了。

4.4 分页

dao添加分页方法

/**
* 根据userid进行分页查询
* 方法名的写法是固定的,findBy属性名
* @param userid
* @param pageable
* @return
*/
Page<Comment> findByUserid(String userid, Pageable pageable);

service调用新方法

/**
* 根据userid查询评论列表
* 分页
* @param userid
* @param page
* @param size
* @return
*/
public Page<Comment> findCommentListByUserid(String userid,int page,int size){
    // page对应在mongodb中是从0开始的,所以需要 -1
    Page<Comment> byUserid = commentDao.findByUserid(userid, PageRequest.of(page - 1, size));
    return byUserid;
}

JUnit测试

@Test
public void findCommentByUserid(){
    Page<Comment> commentListByUserid = commentService.findCommentListByUserid("123", 2, 2);
    System.out.println(commentListByUserid.getTotalElements());
    commentListByUserid.getContent().forEach(System.out::println);
}

4.5 MongoTemplate

业务场景:当评论被点赞时,要实现点赞数量加一,常规的操作是要将原评论的点赞数加载出来,然后+1再保存。这里就需要进行两次磁盘读写,效率变低。由此引出更高效的操作方案。

mongoTemplate底层实则是将方法拼装成复杂的一条指令,只需进行一次磁盘IO。

编写service类

import com.ssx.studymongodb.po.Comment;
import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.stereotype.Service;

/**
 * 使用 MongoTemplate操作MongoDB
 * @author: huangzw
 * @create: 2021-03-02 23:22
 */
@Service
public class CommentTemplateService {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 点赞
     * 给评论的点赞数 +1
     * @param id
     */
    public void addLikeNum(String id){
        //查询条件
        Query query = Query.query(Criteria.where("_id").is(id)); // .addCriteria().addCriteria()

        //更新条件
        Update update = new Update();
        update.inc("likenum");// increment 增量 +1

        mongoTemplate.updateFirst(query, update, Comment.class);
    }
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页