MongoDB

MongoDB

MongoDB 是非关系数据库当中功能最丰富,最像关系数据库的

1、介绍

MongoDB优势:

1:JSON结构和对象模型接近,开发代码量少

2:JSON动态模型意味着更容易响应新的业务需求

3:复制集提供了 99.999%高可用

4:分片架构支持海量数据无缝扩容

数据库结构

MongoDB属于NoSQL数据库,自然也是没有表相关概念的,该数据库存储使用的是集合,集合中存储的是文档(树状结构数据)

核心概念

数据库

MongoDB 的一个实例可以拥有一个或者多个相互独立的数据库, 每个数据库都有自己的集合

命令: show databases;

“show dbs” 命令可以显示所有有数据的列表。

运行"use"命令,可以连接到一个指定的数据库

有三个保留数据库:

  1. admin

    从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器

  2. local

这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合

  1. config

当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息

集合

类似mysql中的表

集合可以看做是拥有动态模式的表,json格式,可以更加业务需求自动拓展,一个集合可以用于n个文档

合法的集合名

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

文档

文档是 MongoDB 中基本的数据单元,类似于 mysql 的行

文档是键值对的一个有序集合,语法格式就是 JSON 格式

MongoDB区分类型和大小写

MongoDB的文档不能有重复的键

文档键命名规范:

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

字段

域:field

数据类型

String(字符串): mongodb中的字符串是UTF-8有效的

Integer(整数): 存储数值。整数可以是32位或64位,具体取决于您的服务器

Boolean(布尔): 存储布尔(true/false)值

Double(双精度): 存储浮点值

Arrays(数组): 将数组或列表或多个值存储到⼀个键中

Timestamp(时间戳): 存储时间戳

Object(对象): 嵌⼊式⽂档

Date(⽇期): 以UNIX时间格式存储当前⽇期或时间

Null (空值): 存储Null值

Symbol(符号): 与字符串相同,⽤于具有特定符号类型的语⾔

Object ID(对象ID) : 存储⽂档ID

Binary data(⼆进制数据): 存储⼆进制数据

Code(代码): 将JavaScript代码存储到⽂档中

Regular expression(正则表达式): 存储正则表达式

注意

1:mongodb 自带javascript shell语法,即可以使用js方式操作 mongodb

2:mongodb 没有主外键的概念

3:mongodb 的没有id自增的概念, 但是提供了Object Id

2、安装和连接

https://www.mongodb.com/download-center/community

安装客户端

Linux

1:将mongodb安装包拉入linux路径: /usr/local/software

2:安装mongodb

cd /usr/local/software

rpm -ivh mongodb-org-server-4.0.10-1.el7.x86_64.rpm

3:修改mongodb配置文件满足远程连接

vi /etc/mongod.conf

​ bindIp: 0.0.0.0 # 0.0.0.0 绑定所有的网卡

4:启动mongodb

​ systemctl start mongod

5:开放防火墙端口

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

firewall-cmd --reload

6:客户端连接

window

双击安装, 一路next下去

安装好后,默认会启动MongoDB服务器,可以在服务列表中找到MongoDB Server查看是否处于运行状态,已经处于运行状态则直接进入安装目录/Server/bin,运行mongo.exe,出现以下画面表示安装成功了

MongoDB默认端口27017

可以在 bin 目录下创建txt文件,改名为 startup.bat ,在文件内写入

mongod -config "F:\Program Files\MongoDB\Server\4.2\bin\mongod.cfg"

客户端

img

3、增删改操作

在线文档教程: https://www.runoob.com/mongodb/mongodb-tutorial.html

数据库与集合

当双击打开 mongo.exe 的时候,默认就是使用 localhost:27017 连接服务器

mongo localhost:27017

show dbs   						查询所有数据库
use 数据库名   					创建并且选中数据库。数据库已存在则直接选中,不存在则会创建
db   								查询当前选择的数据库
db.dropDatabase()   				删除当前选中的数据库
show collections或者show tables		查询当前库中的集合
db.createCollection("集合名")   	创建集合
db.集合名.stats();					查看集合信息
db.集合名.drop()   				删除集合
db.集合名.remove(条件);  		仅仅删除文档,集合不删。如果不加条件, 表示删除所有文档

注意: db.集合名 == db.getCollection("集合名")

MongoDB没有专门的创建数据库的命令, 可以使用use 来选择某个数据库, 如果库不存在, 将会创建,但是只有往该库加入文档后才保存成文件

MongoDB中,不用创建集合, 因为没有固定的结构, 直接使用db.集合名称.命令 来操作就可以了, 如果非要显示创建的话

使用: db.createCollection(“集合名称”)

注意:

1:没有显示指定 id 时, 会自动添加 id

2:MongoDB 每个文档大小不能超过16MB

3:可以使用 Object.bsonsize(“文档名”) 来看大小

文档

1、文档添加

语法:

db.集合名.insertOne( 文档 ) : 往集合中插入一个文档

db.集合名.insertMany(文档):往集合中插入多个文档

db.集合名.insert( 文档 ) : 往集合中插入一个文档或者多个

注意:

  1. 往集合中新增文档,当集合不存在时会自动先创建集合,再往集合中添加文档,但是不要依赖自动创建集合的特性
  2. 当操作成功时,集合会给文档生成一个**_id**字段,该字段就是文档的主键,也能在插入数据时自己指定该字段的值,但是不建议这样做

示例:

# 给users集合添加一个文档:name:"dafei" age:18
db.users.insert({id: 1, name: "dafei", age: 18})
db.users.insert({id: 2, name: "xiaofei", age: 17})

2、文档更新

语法:

在 MongoDB 中,所有条件都是使用 花括号

# update users set xx=1 where xx = 1
db.集合名.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)
简化方法:
db.集合名.updateOne   # 等价于 multi:false
db.集合名.updateMany   # 等价于 multi:true

参数说明:
# query——update的查询条件,类似sql update查询内where后面的
# update——update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql查询内set后面的
# upsert——可选,如果query查询不出满足条件的记录,是否插入,true为插入;默认是false,不插入
# multi——可选,默认是false,只更新找到的第一条记录;如果为true,就把按条件查出来多条记录全部更新
# writeConcern——可选,抛出异常的级别

示例:

# 把一个带有name=dafei的文档,修改其age值为30
db.users.updateOne(
    {name: "dafei"},
    {$set: {age: 30}},
    {
    	upsert:false   # 如果满足条件数据则修改,如果没有则不添加
       #multi:false    true表示所有满足条件都改,false表示只改第一条
    }
)

# 修改所有name=dafei的文档,修改其name=大飞,age=20
db.users.updateMany(
    {name: "dafei"},
    {$set: {name: "大飞", age: 20}}
)

# 修改所有的文档,修改其name=xxx,age=10
db.users.updateMany(
    {},
    {$set: {name: "xxx", age: 10}}
)
添加列

直接set一个不存在的列即可

# 给 age=18 文档添加 sex=男 属性
db.users.update(
    {age:18}, 
    {$set:{sex:'男'}},
    {
    	multi:true
    }
)

删除列

使用$unset

# 将 name=xiaofei 的文档中 sex 列删除
db.users.update(
    {name:'xiaofei'}, 
    {$unset:{sex:''}},
    {
    	multi:true
    }
)

3、文档删除

语法:

db.集合名.remove(
    <query>,
    {
		justOne: <boolean>,
        writeConcern: <document>
    }
)
简化方法:
删除1个:db.集合名.deleteOne( ... )
删除所有:db.集合名.deleteMany( ... )

参数说明:
# query :(可选)删除的文档的条件
# justOne : (可选)如果设为 true 或 1,则只删除一个文档;默认 false,表示删除所有匹配条件的文档
# writeConcern :(可选)抛出异常的级别

示例:

# 删除_id=xxx的文档
db.users.deleteOne({_id: ObjectId("621c8e73fb279b933fd47623")})

# 删除所有带有name=dafei的文档
db.users.deleteMany({name: "dafei"})

# 删除当前数据库中所有文档
db.users.deleteMany({})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-74TeP3Tw-1649925080538)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20220228170212075.png)]

4、查询操作

数据准备

db.users.insert({"id":NumberLong(1),"name":"dafei","age":NumberInt(18)})
db.users.insert({"id":NumberLong(2),"name":"xiaofei","age":NumberInt(20)})
db.users.insert({"id":NumberLong(3),"name":"zhang quan dan","age":NumberInt(33)})
db.users.insert({"id":NumberLong(4),"name":"zhang kun","age":NumberInt(26)})
db.users.insert({"id":NumberLong(5),"name":"afei","age":NumberInt(18)})
db.users.insert({"id":NumberLong(6),"name":"cai xv kun","age":NumberInt(29)})
db.users.insert({"id":NumberLong(7),"name":"jia nai liang","age":NumberInt(25)})
db.users.insert({"id":NumberLong(8),"name":"fu rong wang","age":NumberInt(28)})
db.users.insert({"id":NumberLong(9),"name":"wang da","age":NumberInt(31)})
db.users.insert({"id":NumberLong(10),"name":"da wang","age":NumberInt(32)})
db.users.insert({"id":NumberLong(11),"name":"will","age":NumberInt(26)})

查询全部

语法:

db.集合名.find(query, projection)

# query: 是条件
# projection: 指定返回哪些列,里面是列名和boolean值 :{name:true}
		注意:
		_id是默认返回,设置 {"_id": 0}就表示不显示
		0、null、undefined 都表示是false
		除了"_id"之外,所有属性要么都是0、要么都是1 。错误写法:{name:1,age:0}

示例:

# 查所有用户
db.users.find()

db.users.find({})   # {} 是条件,表示查询集合中所有文档

db.users.find({}, {name:1})  # 第二个 {} 表示查询哪些列

1、排序

语法:

db.users.find({}).sort({字段: 1}) 		 #升序
db.users.find({}).sort({字段: -1}) 		 #降序
db.users.find({}).sort({列1:1 , 列2:1})  	 #多列排序

示例:

# 查询所有用户按年龄排序
db.users.find({}).sort({age:1}) 		 #正序、升序
db.users.find({}).sort({age:-1})  		 #倒序、降序

# 表示按年龄降序,如果年龄一致,按 id 正序排序
db.users.find({}).sort({age:-1, id:1})   #多列排序

2、分页

语法:

db.集合.find({}).skip(n).limit(每页显示条数)

# sikp(num): 跳过num个文档,相当于start
# limit(num): 限制显示num个文档,相当于pageSize
db.users.find().skip((currentPage-1) * pageSize).limit(pageSize)

示例:

# 显示第一页,每页三条
db.users.find({}).skip(0).limit(3)
# 显示第二页,每页三条
db.users.find({}).skip(3).limit(3)

# 显示第n页,每页三条
db.users.find({}).skip(3*(n-1)).limit(3)

带条件

1、比较运算符

语法:

find(  {字段: {比较操作符1: 值1, 比较操作符2: 值2, ...} } )  #若有多个操作符,则其之间的关系是and

比较操作符:

  • (>) 大于 - $gt
  • (<) 小于 - $lt
  • (>=) 大于等于 - $gte
  • (<= ) 小于等于 - $lte
  • (!=) 不等 - $ne
  • in 运算 - KaTeX parse error: Expected '}', got 'EOF' at end of input: … 如:**{name: {in: [“xiaoyao”,“bunny”]}}
  • 判断存在 - KaTeX parse error: Expected '}', got 'EOF' at end of input: … 如:**{name: {exists:true}}

示例:

# 查询age > 30的用户
db.users.find(
    { 
    	age: {$gt:30} 
    }
) 

# 查询名字为 dafei 或 xiaofei的用户
db.users.find(
    {  name: {$in: ["dafei","xiaofei"]}  }
)

# 判断判断指定列是否存在,查询有 name 列的所有文档
db.users.find(
    {  name: {$exists:true}  }
)
可以和前面结合使用
db.users.find({name: {$exists:true}},{name:1})

2、逻辑运算符

语法:

find(   {逻辑操作符: [条件1, 条件2, ...]}   )

逻辑操作符

  • (&&) 与 - $and
  • (||) 或 - $or
  • (!) 非 - $not

示例:

# 查年龄在28 到 30间的用户信息[28,30]
db.users.find(
    {
    	age:{ $gte:28, $lte:30 }  #表示 and 关系
    }
)
db.users.find(
	{
	    $and:[
            {age:{$gte:28}},
            {age:{$lte:30}}
        ]
	}
)

# 查看年龄小于28或者年龄大于30用户信息
db.users.find(
   {$or: [{age: {$lt: 28}}, {age: {$gt:30}}]}
)

# 查看年龄等于28或者等于30用户信息
db.users.find(
   {$or: [{age:28}, {age: 30}]}
    #或者是 { age:{$in:[28, 30]}}
)

3、模糊查询

MongoDB的模糊查询使用的是正则表达式的语法 如:{name: {KaTeX parse error: Undefined control sequence: \* at position 11: regex: /^.\̲*̲keyword\.*/}}

实际上MongoDB也是不擅长执行模糊查询的,在实际开发中也是不使用的,该功能了解即可

语法:

db.集合.find({列: {$regex: /关键字/}})
db.集合.find({列: {$regex: "关键字"}})

{name:/xxx/}   --->  %xxx%
{name:/^xxx/}  --->  xxx%
{name:/xxx$/}  --->  %xxx
{name:/xxx/i}    忽略大小写

示例:

# 查询name带有fei的用户信息
# sql: select * from users where name like '%fei%'
db.users.find(
    {name: {$regex:/fei/}}   #正则对象
    #{name: {$regex:"fei"}}   #正则表达式
)

# 查name中包含fei字样,并且年龄在28 到 30间的用户信息,
# sql:  select * from users where name like '%fei%' and age >= 28 and age <=30
db.users.find(
    {
    	$and: [
            {name: {$regex:/fei/}}, 
            {age: {$gte:28, $lte:30}}
        ]
    }
)

# 查询所有name=逍遥的文档
db.users.find({name:"逍遥"})
# 查询所有name=bunny 或者 age<30的文档
db.users.find({$or:[{name:"bunny"},{age:{$lt:30}}]})
# 查询所有 name含有wang 并且 30<=age<=32 的文档
db.users.find({$and:[{name:{$regex:/^.*wang.*$/}},{age:{$gte:30,$lte:32}
}]})

5、数组操作

给所有数据加数组字段

db.users.updateMany({}, { $set:{ hobby:[] } })

添加

1、$push

$push : 给数组字段添加数据, 允许数据元素重复

# 给name等于dafei的用户添加java 爱好
db.users.update(
    {name:'dafei'}, 
    {  $push:{  hobby:'java'  }  }
)

# 给name等于dafei的用户添加'java', 'c', 'vue' 爱好
db.users.update({name:'dafei'}, {
   $push:{hobby:{$each:['java', 'c', 'vue']}}
})
如果是 {hobby:['java','c']} 这样是将后面作为一整个元素加进文档

2、$addToSet

$addToSet: 给数组字段添加数据, 允许数据元素重复

db.users.update({name:'dafei'}, {$addToSet:{hobby:'java'}})

删除

1、$pop

$pop 删除数组中数据, 1:删除最后一个, -1: 删除第一个

局限:只能从头或者从尾删除,不能通过指定元素删除

# 需求删除name=dafei用户最后一个兴趣
db.users.update(
    {name:'dafei'},
    {  $pop:{ hobby:1 }  }
)

2、$pull

$pull 删除数组中数据, 通过指定内容删除

# 删除name=dafei用户java兴趣选项
db.users.update(
    {name:'dafei'}, 
    {  $pull:{hobby:'java'}  }
)

修改

1、通过索引修改

索引是从 0 开始的

如果索引位置没有数据,那么此语句就直接添加值

# 将name=dafei的用户索引为 1 的兴趣改为 go
db.users.update({name:'dafei'}, {$set:{'hobby.1':'go'}})

2、通过数组元素修改

# 将name=dafei的用户 c 兴趣 改为 c#
db.users.update({name:'dafei', hobby:'c'}, {$set:{'hobby.$':'c#'}})

查询

db.users.update({name:'dafei', hobby:'c'}

6、聚合操作[拓展]

聚合查询、统计、分组、平均值、最大值、最小值、总数

比如:

计算一段时间内的销售总额, 均值

计算一段时间的净利润

分析购买人的年龄分布

分析学生成绩

统计员工的绩效

聚合框架

什么是Mongodb聚合框架

MongoDB聚合框架(Aggregation Framewordk) 是一个计算框架,他可以作用在一个或集合集合中,对集合中的数据进行一系列运算,将这些数据转化为期望的形式

从效果而言, 聚合框架相当于SQL查询中 Group by 、left join

原理理解

管道(Pipeline) 与 步骤(Stage)

整个聚合运算工程称之为管道, 它是由多个步骤组成

每个管道:

1:接收一系列文档(原始数据)

2:每一个步骤对这些文档进行一系列运算

3:结果文档输出给下一个步骤

pipeline = [$stage1, $stage2, .... $stageN]

db.集合.aggregate(
    pipeline,
    {
    	options
    }
)

eg:
db.user.aggregate(
    [
        {
        	$group:{
        		_id:"$name",
        		namecount:{$sum:1}
        	}
        }
    ]
);

常见步骤

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档
  • ** m a t c h ∗ ∗ : 用 于 过 滤 数 据 , 只 输 出 符 合 条 件 的 文 档 。 match**:用于过滤数据,只输出符合条件的文档。 matchmatch使用MongoDB的标准查询操作
  • $limit:用来限制MongoDB聚合管道返回的文档数
  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档
  • $group:将集合中的文档分组,可用于统计结果
  • $sort:将输入文档排序后输出
  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值
  • $geoNear:输出接近某一地理位置的有序文档。

练习

准备数据

var book1={
   title: 'MongoDB Overview', 
   description: 'MongoDB is no sql database',
   by_user: 'runoob.com',
   url: 'http://www.runoob.com',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 100
}
var book2={
   title: 'NoSQL Overview', 
   description: 'No sql database is very fast',
   by_user: 'runoob.com',
   url: 'http://www.runoob.com',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 10
}
var book3={
   title: 'Neo4j Overview', 
   description: 'Neo4j is no sql database',
   by_user: 'Neo4j',
   url: 'http://www.neo4j.com',
   tags: ['neo4j', 'database', 'NoSQL'],
   likes: 750
}

db.books.insert(book1);
db.books.insert(book2);
db.books.insert(book3);

聚合操作

db.books.aggregate([
    {
    	$match:{ likes:{$gte:20} } # 过滤likes≥20
    },
    {
    	$group:{
    		_id:"$by_user",   # 根据by_user列进行分组
			sum:{$sum:"$likes"},  #分组后对数据进行求和
			avg:{$avg:"$likes"},
			min:{$min:"$likes"},
			max:{$max:"$likes"},
			push:{$push:"$likes"},  #分组分类,将分组结果放在一个集合内,集合列名push
			addToSet:{$addToSet:"$likes"},
			first:{$first:"$likes"},
			last:{$last:"$likes"}
		}
	},
    {
		$project:{
			_id:1,
			sum:1,
			avg:1
    	}
    }
])

执行前两个 m a t c h 、 match 、 matchgroup 操作,结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VEKQR7z5-1649925080542)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20220301102435582.png)]

执行整个语句的结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L1lxvd9P-1649925080543)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20220301102651417.png)]

7、文档设计

范式

反范式

使用冗余字段方式替换关联映射

使用数组方式替换一对多

多对多关系设计:

8、设置用户

以下操作必须在cmd命令行中操作,执行以下命令

//1.选中admin数据库
use admin
//2.往里面添加一个超级管理员账号
db.createUser({user:"root", pwd: "admin", roles:["root"]})
//user:账号    pwd:密码    roles:角色->root超级管理员

修改MongoDB的配置文件:安装目录/Server/bin/mongod.cfg

#约在29行位置,配置开启权限认证
security:
  authorization: enabled

完成上面配置后重启服务器

在登录时就必须要输入密码,否则不能执行任何的命令

9、集成springboot

完成数据库的 crud 功能

启动服务

依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.2.RELEASE</version>
</parent> 

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>    
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!--spring boot data mongodb-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
</dependencies>

配置

# application.properties
# 配置数据库连接
#格式: mongodb://账号:密码@ip:端口/数据库?认证数据库
#spring.data.mongodb.uri=mongodb://root:admin@localhost/mongodemo?authSource=admin
spring.data.mongodb.uri=mongodb://localhost:27017/mongodemo
# 配置MongoTemplate的执行日志
logging.level.org.springframework.data.mongodb.core=debug

domain

@AllArgsConstructor
@NoArgsConstructor
@Data
@Document("users") //设置文档所在的集合
public class User {
    //文档的id建议使用 String 类型,一般使用ObjectId类型来封装,并且贴上@Id注解
    // 自动映射为 _id 自动封装ObjectId
    @Id
    private String id;
    private String name;
    private Integer age;
    //数组推荐使用 ArrayList
    private List<String> hobby = new ArrayList<>();
}

实现

1、方式一 MongoRepository

里面的 save、update 操作是全栈更新

加入对于 id1 插入了一条数据,然后在对 id1 更新 空数据 new User() ,则数据就是空的

新数据覆盖旧的

  • 为什么 UserRepository 接口可以直接调用 CRUD 方法?

    ​ UserRepository 继承了 MongoRepository接口,它又继承了一系列接口,接口中定义类 crud 方法

    ​ MongoRepository—PagingAndSortRepository—CrudRepository—Repository

  • 为什么不需要实现类?

    ​ spring容器中创建了代理实现类

    ​ spring容器启动时,根据 data-mongodb依赖,将 Repository 导入,springboot通过自动配置原理,加载 Repository 接口整个继承体系,其中 UserRepository 继承了 Repository,所以框架会通过动态代理方式,创建其实现类,并交给 spring容器管理

//用户持久化接口,类似 Mapper 接口
/**
 *  继承接口:MongoRepository
 *		1、接口泛型1:操作对象 User
 *		2、接口泛型2:操作对象主键类型 string
*/
@Repository
public interface UserRepository extends MongoRepository<User, String> {}

//数据库 CRUD 操作
public interface IUserService {
    void save(User user);
    void delete(String id);
    void update(User user);
    User get(String id);
    List<User> list();
}

@Service
public class UserServiceImpl  implements IUserService{
    
    //使用容器注入代理实现类,直接调用里面的方法
    @Autowired
    private UserRepository userRepository;
    
    @Override
    public void save(User user) {
        userRepository.save(user);
    }
    @Override
    public void delete(String id) {
        userRepository.deleteById(id);
    }
    @Override
    public void update(User user) {
        userRepository.save(user);
    }
    @Override
    public User get(String id) {
        //userRepository.findById(id) 返回值是 Optional
        return userRepository.findById(id).get();  
    }
    @Override
    public List<User> list() {
        return userRepository.findAll();
    }
}
--------------------------------------------------------------
@SpringBootTest
public class UserTest {
    @Autowired
    private IUserService userService;
    @Test
    public void testSave(){
        User user = new User();
        user.setId(21L);
        user.setName("dafei");
        user.setAge(18);
        userService.save(user);
    }
    @Test
    public void testUpdate(){
        //由于这里的更新是全栈更新,数据容易丢失,所以需要先查询、再替换、再更新
        //User user = new User();
        //user.setId("5de507fca0852c6c7ebc1eac");
        //user.setId(21L);
        //user.setName("dafei2222");
        //user.setAge(18);
        
        //1、查询
        User user = userService.get("5de507fca0852c6c7ebc1eac")
        //2、替换
        user.setName("dafei2222");
        user.setAge(18);
        //3、更新
        userService.update(user);
    }
    @Test
    public void testDelete(){
        userService.delete("5de507fca0852c6c7ebc1eac");
    }
    @Test
    public void testGet(){
        System.out.println(userService.get("5de507fca0852c6c7ebc1eac"));
    }
    @Test
    public void testList(){
        System.out.println(userService.list());
    }
}

现在想通过 name 字段来查询,但是 UserRepository 接口实现类并没有此种方法, 只有 findById()

此时仅仅需要在接口内定义一个抽象方法,作为通过 name 字段查询的方法,此处是因为 JPA 的查询规范

操作原理:在spring动态代理时,会根据JPA查询规范解析自定义方法,拼接出MQL查询语句,实现查询操作

JPA 查询规范:

​ 定义 JPA 约束的查询方法,方法格式要求:

​ 前缀 + 属性名 + 操作符

​ 前缀:findBy 、queryBy 开头

​ 属性名: 表的某个列(实体对象属性),首字母大写

​ 操作符:And、LessThan、After、ISNull

@Repository
public interface UserRepository extends MongoRepository<User, String> {
	// 使用Spring Data命名规范做高级查询
    List<User> findByName(String name);
}

参考下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UbJ73bdq-1649925080545)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20220328175200705.png)]

2、方式二 MongodbTemplate

JPA查询方法简单,但对于多条件查询(高级查询),JPA 无法拼接,需要使用 MongodbTemplate

​ springdata 是spring团队为了同一数据库(关系型与非关系型)操作而提供一套访问数据库的API规范

​ data-mongodb 是这个规范下创建子项目

​ data-mongodb 访问数据库的api核心类 :MongodbTemplate 类

// spring封装操作模板,MongodbTemplate 类,直接使用即可
@Service
public class UserServiceImpl implements IUserService{
    //直接使用,容器已经创建好了
    @Autowired
    private MongoTemplate template;
    
    @Override
    public void save(User user) {
        template.save(user);
    }
    @Override
    public void delete(String id) {
        template.remove(id);
    }
    @Override
    public void update(User user) {
        template.save(user);
    }
    @Override
    public User get(String id) {
        return template.findById(id, User.class);
    }
    @Override
    public List<User> list() {
        return template.findAll(User.class);
    }
}
条件查询

注意包名

import org.springframework.data.mongodb.core.query.Query;
@SpringBootTest
public class QueryTest {
    
    //直接使用
    @Autowired
    private MongoTemplate mongoTemplate;
    
    // 查询所有name=dafei的文档
    // mql:db.users.find({name:"dafei"})
    @Test
    public void testQuery1() throws Exception {
        // Query 查询对象:理解为MQL语句拼接对象
        Query query = new Query();
        
        // Criteria 条件封装对象
        // 相当于 {"name": "dafei"},是限制条件
        Criteria criteria = Criteria.where("name").is("dafei");
        
        // 添加限制条件
        query.addCriteria(criteria);
        
        //执行查询语句:指定集合名与返回值类型
        List<User> list = mongoTemplate.find(query, User.class, "users");
        list.forEach(System.err::println);//在可能会出错和调试时使用System.err
    }
}
逻辑运算查询
@SpringBootTest
public class QueryTest {
    
    //直接使用
    @Autowired
    private MongoTemplate mongoTemplate;
    
    // 查询所有name=dafei 或者 age<30的文档
    // db.users.find({ $or:[ { name:"dafei" }, { age:{$lt:30} } ] })
    @Test
    public void testQuery3() throws Exception {
        // 创建查询对象
        Query query = new Query();
        
        // 构建限制条件 { "$or": [{"name": "dafei"}, {"age": {"$lt": 30}}] }
        Criteria criteria = new Criteria();
        // and关系就用andOperator
        criteria.orOperator(
        	Criteria.where("name").is("dafei"),
        	Criteria.where("age").lt(30)
        );
        
        // 添加限制条件
        query.addCriteria(criteria);
        
        //执行查询语句
        List<User> list = mongoTemplate.find(query, User.class, "users");
        list.forEach(System.err::println);
    }
}
模糊运算
@SpringBootTest
public class QueryTest {
    
    //直接使用
    @Autowired
    private MongoTemplate mongoTemplate;
    
    
    /**
     * 查询所有name含有fei并且30<=age<=32的文档
     * 	db.users.find({
     * 		"$and":[
     *			{"name":  {"$regex":".*fei.*"}  }, 
     *			{"age":  {"$gte":30,   "$lte":32}  }
     *		]
     * 	})
     */
    @Test
    public void testQuery4() throws Exception {
        // 创建查询对象
        Query query = new Query();
        
        // 构建限制条件
        Criteria criteria = new Criteria().andOperator(
                Criteria.where("name").regex(".*fei.*"),
                Criteria.where("age").gte(30).lte(32)
        );
        
        // 添加限制条件
        query.addCriteria(criteria);
        
        //执行查询语句
        List<User> list = mongoTemplate.find(query, User.class, "users");
        list.forEach(System.err::println);
    }
}
分页查询

两种方式:使用Sort、使用Pageable(推荐)

@SpringBootTest
public class QueryTest {
    
    //直接使用
    @Autowired
    private MongoTemplate mongoTemplate;
    
    //一般不这么用
    // 分页查询文档,显示第2页,每页显示3个,按照id升序排列
    // mql:db.users.find({}).sort({id:1}).skip(3).limit(3)
    @Test
    public void testQuery2() throws Exception {
        // 创建查询对象:理解为MQL语句拼接对象
        Query query = new Query();
        
        //排序对象,参数1:排序规则;参数2:排序列名
        Sort sort = Sort.by(Sort.Direction.ASC,"id")
        
        // 设置排序规则
        query.with(sort);
       
        // 设置分页信息
        query.skip(3).limit(3);
        
        //执行查询语句
        List<User> list = mongoTemplate.find(query, User.class, "users");
        list.forEach(System.err::println);
    }
---------------------------------------------------------------------------------- 
    //推荐
    @Test
    public void testQuery2() throws Exception {
        // 查询对象
        Query query = new Query();
        
        // 分页参数对象,类似 QueryObject
        //参数1:当前页,偏移量,从0开始;参数2:每页显示条数;参数3:排序规则;参数4:排序列
        //显示第2页,每页显示3个,按照id升序排列
        Pageable pageable = PageRequest.of(1, 3, Sort.Direction.ASC, "id");
       
        // 设置分页信息
        query.with(pageable);
        
        //执行查询语句
        List<User> list = mongoTemplate.find(query, User.class, "users");
        list.forEach(System.err::println);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值