# 使用Criteria构造查询条件
请求实体
@Data
public class SysUserRequest {
private String userName;
private String phoneNumber;
private String beginTime;
private String endTime;
private Double lowestMoney;
private Double highestMoney;
private String TagScope;
private String[] tags;
private Integer pageNum = 1;
private Integer pageSize = 10;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
构造查询条件
SysUserRequest sysUserRequest = new SysUserRequest();
sysUserRequest.setUserName("xxl");
sysUserRequest.setPhoneNumber("15500000000");
// 创建条件对象
Criteria criteria = new Criteria();
// 1. 全等于 (手机号全字匹配)
if (StringUtils.isNotBlank(sysUserRequest.getPhoneNumber())) {
criteria.and("phone_number").is(sysUserRequest.getPhoneNumber());
}
// 2. 模糊查询 (名称模糊搜索)
if (StringUtils.isNotBlank(sysUserRequest.getUserName())) {
criteria.and("name").regex(Pattern.compile("^.*" + sysUserRequest.getUserName() + ".*$", Pattern.CASE_INSENSITIVE));
}
// 3. 单个条件查询多个字段
if (StringUtils.isNotEmpty(sysUserRequest.getUserName())) {
criteria.orOperator(
Criteria.where("user_name").is(sysUserRequest.getUserName()),
Criteria.where("nick_name").in(sysUserRequest.getUserName())
);
}
// 4. 日期范围
if (StringUtils.isNotEmpty(sysUserRequest.getBeginTime()) && StringUtils.isNotEmpty(sysUserRequest.getEndTime())) {
criteria.andOperator(Criteria.where("birthday").gte(sysUserRequest.getBeginTime()), Criteria.where("birthday").lte(sysUserRequest.getEndTime()));
}
// 5. 数值范围 (存款总金额)
if (sysUserRequest.getLowestMoney() != null && sysUserRequest.getHighestMoney() != null) {
criteria.and("money").gte(sysUserRequest.getLowestMoney()).lte(sysUserRequest.getHighestMoney());
}
if (sysUserRequest.getTags() != null && !CollectionUtils.isEmpty(Arrays.asList(sysUserRequest.getTags()))) {
if ("any".equals(sysUserRequest.getTagScope())) {
// 6. 数组字段满足任一
criteria.and("tags").in(sysUserRequest.getTags());
} else if ("all".equals(sysUserRequest.getTagScope())) {
// 7. 数组字段满足全部 (客户标签)
criteria.and("tags").all(sysUserRequest.getTags());
}
}
Query query = new Query();
query.addCriteria(criteria);
// 8. 查询返回指定字段 (自定义列表)
query.fields().include("user_name");
// 10. 分页
query.with(PageRequest.of(sysUserRequest.getPageNum() - 1, sysUserRequest.getPageSize(),
// 11. 排序
Sort.by(Sort.Order.desc("earliest_add_time"))));
// 分页(方式二,使用skip+limit)
query.with(Sort.by(Sort.Order.desc("birthday")))
.skip((long) (sysUserRequest.getPageNum() - 1) * sysUserRequest.getPageSize())
.limit(sysUserRequest.getPageSize());
// 执行查询
List<SysUser> list = mongoTemplate.find(query, SysUser.class);
// 12. 总记录数
long total = mongoTemplate.count(query, SysUser.class);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
补充Criteria方法说明
Criteria | Mongodb | 说明 |
---|---|---|
and() | $and | 并且 |
andOperator() | $and | 并且 |
orOperator() | $or | 或者 |
is() | $is | 等于 |
in() | $in | 是否被包含在数组或者list内 |
nin() | $nin | 不包含 |
gt() | $gt | 大于 |
gte() | $gte | 大于等于 |
lt() | $lt | 小于 |
lte() | $lte | 小于等于 |
regex() | $regex | 正则表达式用于模式匹配,基本上是用于文档中的发现字符串 |
set() | $set | 给字段赋值,字段不存在,增加字段并赋值 |
# Aggregation函数
Aggregation官方SQL语法:Aggregation Pipeline Stages — MongoDB Manual (opens new window)
# 常用函数
- Aggregation.group() : 聚合函数,将某个字段或者某个数组作为分组统计的依据,在group的基础上又扩展出以下函数:
- sum() : 求和
- max() : 获取最大值
- min() : 获取最小值
- avg() : 获取平均值
- count() : 统计条目数
- first () : 获取group by 后的某个字段的首个值
- last() : 获取 group by 后的某个字段的最后一个值
- push() : 在结果文档中插入值到一个数组中
- addToSet() : 在结果文档中插入值到一个数组中,但不创建副本(作为集合)。
- Aggregation.match() : 过滤函数,主要存储过滤数据的条件,输出符合条件的记录,相当于where条件。
- is():==相等
- Aggregation.project(): 修改数据结构函数,将前面管道中的获取的字段进行重名,增加,修改字段等操作。
- Aggregation.unwind():将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。当preserveNullAndEmptyArrays为true时,将包括字段为null,空,或者缺失的数据;
- Aggregation.sort(): 排序函数,将上级管道的内容按照某个字段进行排序并且输出。值为1升、-1降。sort一般放在group后,也就是说得到结果后再排序,如果先排序再分组没什么意义;
- Aggregation.limit(): 限制输出函数,将聚合返回的内容限定在某个条目之内。通常作为页面大小
- Aggregation.skip(): 跳过指定数量的条目再开始返回数据的函数,通常和sort(),limit()配合,实现数据翻页查询等操作。
- Aggregation.lookup(): 连表查询,将被关联集合添加到执行操作的集合中。
# group、match
# mongo语句
db.getCollection("sys_user").aggregate([
{
$match: {
birthday: {
$gte: ISODate('1900-01-01 00:00:00.014'),
$lte: ISODate('2023-10-23 15:30:00.014')
},
userName: 'xxl'
}
},
{
$group: {
_id: "$idNumber",
sum: { $sum: 1 },
userName: { $first: "$userName" },
phoneNumber: { $first: "$phoneNumber" },
birthday: { $first: "$birthday" }
}
},
{
$sort: { sum: -1 }
},
{
$skip: 0
},
{
$limit: 10
}
])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# java代码
int page = 1;
int size = 10;
Date startTime = DateUtil.parse("1900-01-01 00:00:00");
Date endTime = new Date();
String userName = "xxl";
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("birthday").gte(startTime).lte(endTime)),
Aggregation.match(Criteria.where("userName").is(userName)),
Aggregation.group("idNumber").count().as("sum")
.first("userName").as("userName")
.first("phoneNumber").as("phoneNumber")
.first("birthday").as("birthday"),
Aggregation.sort(Sort.by("sum").descending()),
Aggregation.skip(page > 1 ? (page - 1) * size : 0),
Aggregation.limit(size)
);
List<SysUser> results = mongoTemplate.aggregate(aggregation, "sys_user", SysUser.class).getMappedResults();
System.out.println(results);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# project筛选字段
# mongo语句
db.getCollection("sys_user").aggregate([
{
$group: {
_id: "$idNumber",
sum: {
$sum: "$money"
},
userName: {
$first: "$userName"
},
phoneNumber: {
$first: "$phoneNumber"
},
birthday: {
$last: "$birthday"
}
}
},
{
"$project": {
"_id": 1,
"sum": 1,
"userName": 1,
"phoneNumber": 1,
"birth": "$birthday"
}
}
])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# java代码
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.group(new String[]{"_id"})
.sum("money").as("sum")
.first("userName").as("userName")
.first("phoneNumber").as("phoneNumber")
.last("birthday").as("birthday"),
Aggregation.project("_id", "sum", "userName", "phoneNumber")
.and("birthday").as("birth") // 重新命名字段
);
List<SysUser> results = mongoTemplate.aggregate(aggregation, "sys_user", SysUser.class).getMappedResults();
System.out.println(results);
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# unwind拆分数组
# mongo语句
db.getCollection('sys_user').aggregate([
{
$match: {
userName: "xxl"
}
},
{
$unwind: {
path: "$tags",
includeArrayIndex: "arrayIndex"
}
}
])
# 原始数据
{
"_id": ObjectId("658712b96a3c742d4070f6ca"),
"userName": "xxl",
"phoneNumber": "15285602889",
"address": "北州市戴栋25802号",
"idNumber": "790324-1128",
"birthday": ISODate("1961-12-16T06:03:38.014Z"),
"money": NumberInt("204"),
"_class": "com.xxl.mongodb.result.SysUser",
"tags": [
"python",
"c",
"c#",
"java"
],
"child": {
"userName": "xxl2",
"phoneNumber": "110",
"address": "洛杉矶",
"idNumber": "911",
"birthday": ISODate("2023-12-24T16:31:40.753Z"),
"money": NumberInt("9999"),
"_class": "com.xxl.mongodb.result.SysUser"
}
}
# 查询出的数据
_id userName phoneNumber address idNumber birthday money _class tags child arrayIndex
658712b96a3c742d4070f6ca xxl 15285602889 北州市戴栋25802号 790324-1128 1961-12-16 06:03:38.014 204 com.xxl.mongodb.result.SysUser python (Document) 7 Fields 0
658712b96a3c742d4070f6ca xxl 15285602889 北州市戴栋25802号 790324-1128 1961-12-16 06:03:38.014 204 com.xxl.mongodb.result.SysUser c (Document) 7 Fields 1
658712b96a3c742d4070f6ca xxl 15285602889 北州市戴栋25802号 790324-1128 1961-12-16 06:03:38.014 204 com.xxl.mongodb.result.SysUser c# (Document) 7 Fields 2
658712b96a3c742d4070f6ca xxl 15285602889 北州市戴栋25802号 790324-1128 1961-12-16 06:03:38.014 204 com.xxl.mongodb.result.SysUser java (Document) 7 Fields 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# java代码
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(new Criteria().and("userName").is("xxl")),
Aggregation.unwind("tags", true)
);
List<SysUser> results = mongoTemplate.aggregate(aggregation, "sys_user", SysUser.class).getMappedResults();
System.out.println(results);
1
2
3
4
5
6
2
3
4
5
6
# lookup多表关联查询
// 创建新集合,增加关联数据
db.sys_user_label.insert({"user_name" : "xxl", "label_name" : "唱"})
db.sys_user_label.insert({"user_name" : "xxl", "label_name" : "跳"})
db.sys_user_label.insert({"user_name" : "xxl", "label_name" : "Rap"})
1
2
3
4
2
3
4
# mongo语句
db.getCollection('sys_user').aggregate([
{
$lookup: {
from: "sys_user_label", // 被关联表名
localField: "userName", // 主表(mro_accounts)中用于关联的字段
foreignField: "user_name", // 被关联表(mro_profiles)中用于关联的字段
as: "label" // 被关联的表的别名
}
}
])
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# java代码
Aggregation aggregation = Aggregation.newAggregation(
//分别对应from, localField, foreignField, as
Aggregation.lookup("sys_user_label", "userName", "user_name", "label")
);
List<SysUser> results = mongoTemplate.aggregate(aggregation, "sys_user", SysUser.class).getMappedResults();
System.out.println(results);
1
2
3
4
5
6
2
3
4
5
6
# 参考资料
https://blog.csdn.net/Java_Rookie_Xiao/article/details/125602833
mongodb聚合在Java中的使用(包含mongo多表关联查询) - B1nbin - 博客园 (cnblogs.com) (opens new window)