MongoDB
RDBMS vs NoSQL
RDBMS
- 高度组织化结构化数据
- 结构化查询语言(SQL) (SQL)
- 数据和关系都存储在单独的表中。
- 数据操纵语言,数据定义语言
- 严格的一致性
- 基础事务
NoSQL
- 代表着不仅仅是SQL
- 没有声明性查询语言
- 没有预定义的模式
- 键 - 值对存储,列存储,文档存储,图形数据库
- 最终一致性,而非ACID属性
- 非结构化和不可预知的数据
- CAP定理
- 高性能,高可用性和可伸缩性
文档(Document-Oriented)存储
-
特点:文档数据库将数据以文档的形式储存,类似 JSON,是一系列数据项的集合。每个数据项都有一个名称与
对应的值,值既可以是简单的数据类型,如字符串、数字和日期等;也可以是复杂的类型,如有序列表和关联对象。
-
优点:数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构。
-
缺点:查询性能不高,缺乏统一的查询语法。
-
应用场景:日志、 Web 应用等。
-
NoSQL 代表:MongoDB、CouchDB
MongoDB的特点和适用场景
实用性
MongoDB是一个面向文档的数据库,它并不是关系型数据库,直接存取BSON,这意味着MongoDB更加灵活,因为可以在文档中直接插入数组之类的复杂数据类型,并且文档的key和value不是固定的数据类型和大小,所以开发者在使用MongoDB时无须预定义关系型数据库中的”表”等数据库对象,设计数据库将变得非常方便,可以大大地提升开发进度。
可用性和负载均衡
MongoDB在高可用和读负载均衡上的实现非常简洁和友好,MongoDB自带了副本集的概念,通过设计适合自己业务的副本集和驱动程序,可以非常有效和方便地实现高可用,读负载均衡。而在其他数据库产品中想实现以上功能,往往需要额外安装复杂的中间件,大大提升了系统复杂度,故障排查难度和运维成本。
扩展性
在扩展性方面,假设应用数据增长非常迅猛的话,通过不断地添加磁盘容量和内存容量往往是不现实的,而手工的分库分表又会带来非常繁重的工作量和技术复杂度。在扩展性上,MongoDB有非常有效的,现成的解决方案。通过自带的Mongos集群,只需要在适当的时候继续添加Mongo分片,就可以实现程序段自动水平扩展和路由,一方面缓解单个节点的读写压力,另外一方面可有效地均衡磁盘容量的使用情况。整个mongos集群对应用层完全透明,并可完美地做到各个Mongos集群组件的高可用性。
数据压缩
自从MongoDB 3.0推出以后,MongoDB引入了一个高性能的存储引擎WiredTiger,并且它在数据压缩性能上得到了极大的提升,跟之前的MMAP引擎相比,压缩比至少可增加5倍以上,可以极大地改善磁盘空间使用率。
其他特性
相比其他关系型数据库,MongoDB引入了”固定集合”的概念。所谓固定集合,就是指整个集合的大小是预先定义并固定的,内部就是一个循环队列,假如集合满了,MongoDB后台会自动去清理旧数据,并且由于每次都是写入固定空间,可大大地提升写入速度。这个特性就非常适用于日志型应用,不用再去纠结日志疯狂增长的清理措施和写入效率问题。另外需要更加精细的淘汰策略设置,还可以使用TTL索引(time-to-live index),即具有生命周期的索引,它允许为每条记录设置一个过期时间,当某条记录达到它的设置条件时可被自动删除。
基本术语对比
sql 术语概念 | MongoDB术语概念 |
---|---|
database(数据库) | database(数据库) |
table(表) | collection(集合) |
row(行) | document or BSON document(文档) |
column(列) | field(字段) |
index(索引) | index(索引) |
table joins(表连接) | embedded document and linking(嵌入的文档和链接) |
primary key Specify any unique column or column combination as primary key.(指定任意唯一的列或列组合作为主键) | primary keyIn MongoDB, the primary key isautomatically set to the _id fifield.(在 MongoDB 中,主键被自动设置为 _id 字段) |
aggregation (e.g. group by) | MongoDB provides three ways to perform aggregation: the aggregation pipeline, the map-reduce function, and single purpose aggregation methods.(聚合操作) |
MongoDB 数据类型
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位 |
Boolean | 布尔值。用于存储布尔值(真/假) |
Double | 双精度浮点值。用于存储浮点值 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比 |
Arrays | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间 |
Object | 用于内嵌文档 |
Null | 用于创建空值 |
Symbol | 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建Date 对象,传入年月日信息 |
Object ID | 对象 ID。用于创建文档的 ID |
Binary Data | 二进制数据。用于存储二进制数据 |
Code | 代码类型。用于在文档中存储 JavaScript 代码 |
Regular expression | 正则表达式类型。用于存储正则表达式 |
常用权限
权限 | 说明 |
---|---|
read | 允许用户读取指定数据库 |
readWrite | 允许用户读写指定数据库 |
userAdmin | 允许用户向 system.users 集合写入,可以在指定数据库里创建、删除和管理用户 |
dbAdmin | 允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profifile |
clusterAdmin | 必须在 admin 数据库中定义,赋予用户所有分片和复制集相关函数的管理权限。 |
readAnyDatabase | 必须在 admin 数据库中定义,赋予用户所有数据库的读权限。 |
readWriteAnyDatabase | 必须在 admin 数据库中定义,赋予用户所有数据库的读写权限 |
userAdminAnyDatabase | 必须在 admin 数据库中定义,赋予用户所有数据库的 userAdmin 权限 |
dbAdminAnyDatabase | 必须在 admin 数据库中定义,赋予用户所有数据库的 dbAdmin 权限 |
root | 必须在 admin 数据库中定义,超级账号,超级权限。 |
创建用户
- user :用户名
- pwd :密码
- customData :存放用户相关的自定义数据,该属性也可忽略
- roles :数组类型,配置用户的权限
- db : 生效的数据库
db.createUser({user:"uaad",pwd:"uaad",roles:[{role:"userAdminAnyDatabase",db:"admin"}]})
修改mongod.cfg配置文件
#security:
security:
#开启用户权限认证
authorization: enabled
-
重启mongodb数据库
net stop mongodb net start mongodb net start nongodb --auth
数据库的操作
- 切换或创建数据库:use 数据库名称(如果数据库存在就切换,不存在就创建,需要注意的是数据库中如果没有数据就不会展示)
- 展示数据库:show dbs(展示所有的数据库) db(展示当前所在的数据库)
- 删除数据库(需要有权限):db.dropDatabase()
collection的操作
-
创建集合:db.createCollection(name, options) ,name:要创建的集合名称。options:可选参数,指定有关内存大小及索引的选项。
-
在 MongoDB 中创建文档时会自动创建集合,除非你对创建的集合有特殊的需求。
# 方式一: db.c2.insert({"a":1}) # 当第一个文档插入时,集合就会被创建并包含该文档 # 方式二: db.c3 # 创建一个空集合,里面没有数据时通过 show tables 或 show collections 是无法查看到的。需要向集合 中插入一个文档才能看见
字段 | 类型 | 描述 |
---|---|---|
capped | 布尔 | (可选)如果为 true,则创建固定集合。固定集合是指有固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。当该值为 true 时,必须指定 size 参数。 |
size | 数值 | (可选)限制集合空间的大小,默认为没有限制(以字节计)。如果 capped 为 true,必须指定该字段。 |
autoIndexId | 布尔 | (可选)如果为 true,自动在 _id 字段创建索引。默认为 true。 |
max | 数值 | (可选)限制集合中包含文档的最大数量,默认为没有限制。 |
- 查看集合: show tables 或 show collections
- 通过 db.集合名称.stats() 查看集合详情。
- 删除集合: db.集合名称.drop()
Document 操作
-
单条插入:db.集合名.insert(document名),插入文档时如果没有指定 _id 则默认为 ObjectId 类型, _id 不能重复,且在插入后不可变。
- db.c1.insert({“name”:“a”})
- db.c1.insertOne({“name”:“a”})
- db.c1.save({“name”:“a”})
user1 = { "name":"zhangsan", "age":18, "hobbies":["music", "read"], "addr":{ "country":"China", "city":"BJ" } } db.user.insert(user1)
-
批量插入:
-
db.集合名.insert([{name:“a”}, {name:“b”}])
-
db.集合名.insertMany([{name:“a”}, {name:“b”}])
-
db.集合名.save([{name:“a”}, {name:“b”}])
-
user1 = { "_id":1, "name":"zhangsan", "age":1, "hobbies":["music", "read"], "addr":{ "country":"China", "city":"BJ" } } user2 = { "_id":2, "name":"lisi", "age":2, "hobbies":["music", "read"], "addr":{ "country":"China", "city":"SH" } } user3 = { "_id":3, "name":"wangwu", "age":3, "hobbies":["music", "read"], "addr":{ "country":"China", "city":"GZ" } } user4 = { "_id":4, "name":"zhaoliu", "age":4, "hobbies":["music", "read"], "addr":{ "country":"China", "city":"SZ" } } user5 = { "_id":5, "name":"tianqi", "age":5, "hobbies":["music", "read"], "addr":{ "country":"China", "city":"TY" } } db.user.insert([user1, user2, user3, user4, user5])
-
-
更新文档:db.集合名.update(query, update, options)
- query :update 的查询条件,类似 SQL update 语句中的 where 部分。
- update :update 的对象和一些更新的操作符(如 s e t , set, set,inc…)等,也可以理解为 SQL update 语句中的 set 部分。
- upsert :可选,如果不存在 update 的文档,是否插入该文档。true 为插入,默认是 false,不插入。
- multi :可选,是否批量更新。true 表示按条件查询出来的多条记录全部更新,false 只更新找到的第一条记录,默认是 false。
-
注意:更新文档是更新整个文档的操作,如果修改的值只有 name 和 age,除了 _id 以外其他属性将会被删除。
user = {
"name":"wangwu",
"age":20,
"hobbies":["music", "read"],
"addr":{
"country":"China",
"city":"BJ"
}
}
# 修改单条
db.user.updateOne({"name":"lisi"}, {"$set": user})
# 查找到的匹配数据如果是多条,只会修改第一条
db.user.update({"name":"lisi"}, user) # 修改单条等价于 updateOne()
# 查找到的匹配数据如果是多条,修改所有匹配到的记录
db.user.update({"name":"lisi"}, {"$set": user}, false, true) # 修改多条
db.user.updateMany({"name":"张三123123"}, {"$set": user}) # 修改多条
更新操作符
-
db.集合名.update({query},{更新操作符:{update}})
-
query :update 的查询条件,类似 SQL update 语句中的 where 部分。
-
update :update 的对象和一些更新的操作符(如 s e t , set, set,inc…)等,也可以理解为 SQL update 语句中的 set
部分。
-
-
常用操作符
操作符 作用 $set 用来指定一个键并更新键值,若键不存在并创建。 $inc 可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。 $unset 主要是用来删除键。 $push 向文档的某个数组类型的键添加一个数组元素,不过滤重复的数据。添加时键存在,要求键值类型必须是数组;键不存在,则创建数组类型的键。 $pop 删除数据元素。1 表示从数组的尾部删除,-1 表示从数组的头部删除元素。 $pull 从数组中删除满足条件的元素。 $pullAll 从数组中删除满足条件的多个元素。 $rename 对键进行重新命名。
删除文档
-
db.集合名.remove(, {justOne: })
- query :(可选)删除的文档的条件。
- justOne :(可选)如果设为 true,则只删除一个文档,False删除所有匹配的数据
#删除符合条件的第一个文档 db.user.deleteOne(<query>) #删除所有数据命令 db.user.remove({}) #清空该集合(表) 等价于上一条 db.user.deleteMany({})
查询文档
# 等同于db.user.find({})
db.user.find()
# 去重
db.user.distinct('name')
find() 方法以非结构化的方式来显示所有文档。如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
# pretty() 方法以格式化的方式来显示所有文档
db.user.find().pretty()
运算
比较
#1、select * from user where id = 3
db.user.find({"_id":3})
#2、select * from user where id != 3
db.user.find({"_id":{"$ne":3}})
#3、select * from user where id > 3
db.user.find({"_id":{"$gt":3}})
#4、select * from user where age < 3
db.user.find({"age":{"$lt":3}})
#5、select * from user where id >= 3
db.user.find({"_id":{"$gte":3}})
#6、select * from user where id <= 3
db.user.find({"_id":{"$lte":3}})
逻辑
- MongoDB中字典内用逗号分隔多个条件是and关系,或者直接用 $and , $or , $not (与或非)
#逻辑运算:$and,$or,$not
#1 select * from user where id >=3 and id <=4;
db.user.find({"_id":{"$gte":3,"$lte":4}})
#2 select * from user where id >=3 and id <=4 and age >=4;
db.user.find({
"_id":{"$gte":3,"$lte":4},
"age":{"$gte":4}
})
db.user.find({
"$and": [
{"_id": {"$gte":3, "$lte":4}},
{"age": {"$gte":4}}
]
})
#3 select * from user where id >=0 and id <=1 or id >=4 or name = "tianqi";
db.user.find({
$or: [
{"_id": {$gte:0, $lte:1}},
{"_id": {$lte:4}},
{"name": "tianqi"}
]
})
db.user.find({
"$or": [
{"$and": [
{"_id": {"$gte": 0}},
{"_id": {"$lte": 1}}
]},
{"_id": {"$gte": 4}},
{"name": "tianqi"}
]
});
#4 select * from user where id % 2 = 1;
db.user.find({"_id":{"$mod":[2,1]}})
#上一条取反
db.user.find({
"_id":{"$not":{"$mod":[2,1]}}
})
成员
- 成员运算无非in和not in,MongoDB中形式为 $in , $nin
#1、select * from user where age in (1,2,3);
db.user.find({"age":{"$in":[1,2,3]}})
#2、select * from user where name not in ("zhangsan","lisi");
db.user.find({"name":{"$nin":["zhangsan","lisi"]}})
$type
-
MongoDB中可以使用的类型如下表所示:
类型 数字 备注 Double 1 String 2 Object 3 Array 4 Binary data 5 Undefined 6 已废弃。 Object id 7 Boolean 8 Date 9 Null 10 Regular Expression 11 javaScript 13 Symbol 14 JavaScript(with scope) 15 32-bit integer 16 TimeStamp 17 64-bit integer 18 Min key 255 Query with -1 Max key 127 -
# 查询name是字符串类型的数据
db.user.find({name:{$type:2}})
正则
-
正则定义在 / / 内
#1、select * from user where name regexp '^z.*?(n|u)$'; #匹配规则:z开头、n或u结尾,不区分大小写 db.user.find({'name':/^z.*?(n|u)$/i})
投影
-
MongoDB投影意思是只选择必要的数据而不是选择一整个文件的数据。
-
在MongoDB中,当执行 find() 方法,那么它会显示一个文档所有字段。要限制这一点,需要设置的字段列表值1或0。1用来显示字段而0是用来隐藏字段, _id 会默认显示出来
#1、select name,age from user where id=3; db.user.find({'_id':3},{'_id':0,'name':1,'age':1}) #2、select name,age from user where name regexp "^z.*(n|u)$"; db.user.find({ "name":/^z.*(n|u)$/i }, { "_id":0, "name":1, "age":1 } )
数组
#查询数组相关
#查hobbies中有dancing的人
db.user.find({
"hobbies":"dancing"
})
#查看既有dancing爱好又有tea爱好的人
db.user.find({
"hobbies":{"$all":["dancing","tea"]}
})
#查看索引第2个爱好为dancing的人(索引从0开始计算)
db.user.find({
"hobbies.2":"dancing"
})
#查看所有人的第1个到第2个爱好,第一个{}表示查询条件为所有,第二个是显示条件(左闭右开)
db.user.find(
{},
{
"_id":0,
"name":0,
"age":0,
"addr":0,
"hobbies":{"$slice":[0,2]},
}
)
#查看所有人最后两个爱好,第一个{}表示查询条件为所有,第二个是显示条件
db.user.find(
{},
{
"_id":0,
"name":0,
"age":0,
"addr":0,
"hobbies":{"$slice":-2},
}
)
#查询子文档有"country":"China"的人
db.user.find(
{
"addr.country":"China"
}
)
排序
-
在MongoDB中使用使用 sort() 方法对数据进行排序, sort() 方法可以通过参数指定排序的字段,并使用 1和 -1 来指定排序的方式,其中 1 为升序排列,而-1是用于降序排列。
# 按姓名正序 db.user.find().sort({"name":1}) # 按年龄倒序 按id正序 db.user.find().sort({"age":-1,'_id':1})
分页
-
limit表示取多少个document,skip代表跳过几个document,分页公式如下:
db.user.find().skip((pageNum–1)*pageSize).limit(pageSize) db.user.find().limit(2).skip(0) # 前两个 db.user.find().limit(2).skip(2) # 第三个和第四个 db.user.find().limit(2).skip(4) # 第五个和第六个
统计
# 查询_id大于3的人数
# 方式一
db.user.count({'_id':{"$gt":3}})
# 方式二
db.user.find({_id:{"$gt":3}}).count()
SpringBoot 配置 Mongodb
导入spring data mongodb 依赖
<!-- spring data mongodb 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
application.yml文件中配置mongodb
spring:
data:
# mongodb配置
mongodb:
# 服务器地址
host: 127.0.0.1
# 端口
port: 27017
# 用户名
username: uaad
# 密码
password: hanyiming
# 认证数据库
authentication-database: admin
# 操作的数据库
database: test
定义与mongodb数据库文档响应的类
/**
* 把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档
* 可以省略,如果省略,则默认使用类名小写映射集合
* 若未加 @Document ,则 save 到 people
* 若添加 @Document ,则 save 到 collection1
*/
@Data
public class People implements Serializable{
// @Indexed :声明该字段需要索引,建索引可以大大的提高查询效率。
// @CompoundIndex :复合索引的声明,建复合索引可以有效地提高多字段的查询效率
//主键标识,该属性的值会自动对应mongodb的主键字段"_id",如果该属性名就叫“id”,则该注解可以省略,否则必须写
@Id
private String id;
//该属性对应mongodb的字段的名字,如果一致,则无需该注解
@Field("name")
private String name;
private int age;
}
具体操作mongodb数据库的语法
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private PeopleRepository peopleRepository;
/**
* 插入文档
*/
@Test
public void insert() {
People people = new People();
people.setAge(15);
people.setName("李四");
People insert = mongoTemplate.insert(people);
System.out.println(insert);
}
/**
* 更新文档
*/
@Test
public void update() {
People people = new People();
people.setId("61e7b43790ea156906d8741e");
people.setAge(15);
people.setName("更新测试");
//使用save时id不存在就是新增,id存在就是修改
//需要注意如果使用更新操作字段为空的话数据库中的字段会自动删除
People save = mongoTemplate.save(people);
System.out.println(save);
}
/**
* updateFirst
* 修改第一个符合条件的数据
*/
@Test
public void updateFirst() {
// 设置查询体,查询条件具体内容
Criteria criteria = Criteria.where("name").is("李四");
// query设置查询条件
Query query = new Query(criteria);
// 设置修改哪些属性
Update update = new Update();
update.set("name", "李四123");
// People.class 告诉Spring Data MongoDB 上面的属性是哪个类。
// 类对应集合,就知道具体操作集合的哪个属性
UpdateResult result = mongoTemplate.updateFirst(query, update, People.class);
// 修改数量,如果修改前和修改后相同,返回0
System.out.println(result.getModifiedCount());
// 匹配数量。最多返回1,即使有多个张三返回也是1.
System.out.println(result.getMatchedCount());
}
/**
* updateMulti
*/
@Test
public void updateMulti() {
// 设置查询体,查询条件具体内容
Criteria criteria = Criteria.where("name").is("李四");
// query设置查询条件
Query query = new Query(criteria);
// 设置修改哪些属性
Update update = new Update();
update.set("age", 18);
// People.class 告诉Spring Data MongoDB 上面的属性是哪个类。
// 类对应集合,就知道具体操作集合的哪个属性
UpdateResult result = mongoTemplate.updateMulti(query, update, People.class);
// 修改数量。返回所有匹配结果中真实被修改数量
System.out.println(result.getModifiedCount());
// 匹配数量
System.out.println(result.getMatchedCount());
}
/**
* remove
* 根据主键删除
*/
@Test
public void remove() {
//根据主键删除
// People peo = new People();
// peo.setId("61e7b43790ea156906d8741e");
// DeleteResult result = mongoTemplate.remove(peo);
// System.out.println(result.getDeletedCount());
//根据实体类属性名删除
/* Query query = new Query(Criteria.where("name").is("李四"));
//第二个参数告诉Spring Data Mongodb ,name属性对应的实体类的属性
DeleteResult remove = mongoTemplate.remove(query, People.class);
System.out.println(remove.getDeletedCount());*/
//根据集合属性删除
Query query = new Query(Criteria.where("name").is("李四"));
//第二个参数告诉Spring Data Mongodb ,name属性对应的集合属性
DeleteResult remove = mongoTemplate.remove(query, "people");
System.out.println(remove.getDeletedCount());
}
/**
* select
* 查询全部
*/
@Test
public void select() {
List<People> list = mongoTemplate.findAll(People.class);
list.forEach(System.out::println);
}
/**
* 查询第一条数据
*/
@Test
void selectOne() {
// 获取到结果中第一条数据
// new Query() 表示没有条件
People people = mongoTemplate.findOne(new Query(), People.class);
System.out.println(people);
}
/**
* 条件查询
*/
@Test
void find() {
//查询年龄大于等于13的 select * from people where age >= 3
Query query = new Query(Criteria.where("age").gte(13));
List<People> list = mongoTemplate.find(query, People.class);
list.forEach(System.out::println);
}
/**
* 根据主键进行查询
*/
@Test
void findById() {
People peo = mongoTemplate.findById("61e7c20307207f50c83e8e71", People.class);
System.out.println(peo);
}
/**
* 根据字段是否为空进行查询
*/
@Test
void exists() {
Query query = new Query(Criteria.where("name").exists(true));
List<People> list = mongoTemplate.find(query, People.class);
list.forEach(System.out::println);
}
/**
* 区间查询
* 根据大于等于并且小于等于查询
*/
@Test
void range() {
//select * from people where age <= 12 and age >= 14
Query query = new Query(Criteria.where("age").gte(12).lte(14));
List<People> list = mongoTemplate.find(query, People.class);
list.forEach(System.out::println);
}
/**
* 正则表达式查询(模糊查询)
*/
@Test
void regex() {
// java中正则不需要有// 而mongodb中需要
Query query = new Query(Criteria.where("name").regex("张"));
List<People> list = mongoTemplate.find(query, People.class);
list.forEach(System.out::println);
}
/**
* 查询去重复结果
*/
@Test
void findDistinct() {
/**
* findDistinct:
* 查询条件query
* 根据哪个属性去重复。是POJO的属性名称。返回值为此属性去重后的集合。
* 属性所在实体类。
* 属性的类型,此类型作为结果中List集合的泛型。
*/
//select distinct name from people
List<String> list = mongoTemplate.findDistinct(new Query(), "name", People.class, String.class);
list.forEach(System.out::println);
}
/**
* 多条件查询 and
*/
@Test
void and() {
Criteria c = new Criteria();
//select * from people where name = "李四123" and age = 12
c.andOperator(Criteria.where("name").is("李四123"), Criteria.where("age").is(12));
Query query = new Query(c);
List<People> list = mongoTemplate.find(query, People.class);
list.forEach(System.out::println);
}
/**
* 多条件查询 or
*/
@Test
void or() {
Criteria c = new Criteria();
//select * from people where name = "李四" or age = 998
c.orOperator(Criteria.where("name").is("李四"), Criteria.where("age").is(998));
List<People> list = mongoTemplate.find(new Query(c), People.class);
list.forEach(System.out::println);
}
/**
* 条件查询,and 和 or
*/
@Test
void orAnd() {
//select * from people where (name = "张三" and age = 18) or (name = "李四" and age = 20)
Criteria and1 = new Criteria();
and1.andOperator(Criteria.where("name").is("张三"), Criteria.where("age").is(18));
Criteria and2 = new Criteria();
and2.andOperator(Criteria.where("name").is("李四"), Criteria.where("age").is(20));
Criteria c = new Criteria();
c.orOperator(and1, and2);
List<People> list = mongoTemplate.find(new Query(c), People.class);
list.forEach(System.out::println);
}
/**
* 结果排序
*/
@Test
void sort() {
Query query = new Query(Criteria.where("age").gte(2));
query.with(Sort.by(Sort.Direction.ASC, "age"));
List<People> list = mongoTemplate.find(query, People.class);
list.forEach(System.out::println);
}
/**
* 分页查询
*/
@Test
void page() {
Query query = new Query();
/**
* 分页
* page:索引,从0开始,不能为负数
* size:页面大小,必须大于0
*/
// query.with(PageRequest.of(1,2));
//排序后分页
// query.with(PageRequest.of(0, 2, Sort.Direction.DESC, "age"));
//先排序后分页
query.with(PageRequest.of(0, 2, Sort.by(Sort.Direction.DESC, "age")));
List<People> list = mongoTemplate.find(query, People.class);
list.forEach(System.out::println);
}
/**
* 聚合操作:查询文档总数
*/
@Test
void aggregate01() {
/**
* Aggregation.group(String ...)设置分组条件,如果没有分组,参数省略。
* count() 取总条数
* as() 给查询出来的总条数起别名
*/
TypedAggregation<People> aggregation = TypedAggregation.newAggregation(People.class,
Aggregation.group().count().as("count"));
//执行聚合命令,第二个参数Map表示返回结果放入到Map中。
AggregationResults<Map> result = mongoTemplate.aggregate(aggregation, Map.class);
// 获取到返回结果。
System.out.println(result.getUniqueMappedResult());
System.out.println(result.getUniqueMappedResult().get("count"));
}
/**
* 聚合操作:分组计算每组的总数
*/
@Test
void aggregate02() {
/**
* group()参数必须是在People类中存在。
* 设置group参数,表示按照哪个属性进行分组
*/
//select count(1) as count from people group by name
TypedAggregation<People> aggregation = TypedAggregation.newAggregation(People.class,
Aggregation.group("name").count().as("count"));
AggregationResults<Map> result = mongoTemplate.aggregate(aggregation, Map.class);
// 当执行聚合函数返回结果为多行时使用此方法。
List<Map> list = result.getMappedResults();
list.forEach(System.out::println);
}
/**
* 聚合操作:带有查询条件的分组计算
*/
@Test
void aggregate() {
//Aggregation.match写在group前面表示先过滤条件在分组。写在后面表示先分组在过滤条件
//select count(1) as count from people where name = "李四" group by name
// TypedAggregation<People> aggregation = TypedAggregation.newAggregation(People.class,
// Aggregation.match(Criteria.where("name").is("李四")),
// Aggregation.group("name").count().as("count"));
//select count(1) as count from people group by name having name = "李四"
TypedAggregation<People> aggregation = TypedAggregation.newAggregation(People.class,
Aggregation.group("name").count().as("count"),
Aggregation.match(Criteria.where("_id").is("李四")));
AggregationResults<Map> result = mongoTemplate.aggregate(aggregation, Map.class);
List<Map> list = result.getMappedResults();
list.forEach(System.out::println);
}
}