SpringBoot+MangoDB查询操作(MongoTemplate)总结
实体类的结构是这样的
实体类T1
@Data
@Document("[mongoDB对应的索引]")
public class T1 {
private String id;
private Integer count = 0;
private String startTime;
private String message;
private List<T2> details;
}
实体类T2
@Data
public class T2 implements Serializable {
private String url;
private String status;
private Integer pageCount;
private String createTime;
private List<T3> details;
}
实体类T3
@Data
public class T3 implements Serializable {
private String status;
private String message;
private String createTime;
}
注入模板类
@Autowired
private MongoTemplate mongoTemplate;
1.简单构造查询
构造Query对象
想实现的效果:如果传入id就根据ID查询对象,如果没有传入ID根据创建时间查询最新的对象
Query query = new Query();
if (StrUtil.isNotEmpty(id)) {
query.addCriteria(Criteria.where("_id").is(id));//is:等于
} else {
query.with(Sort.by(Sort.Order.desc("startTime")));//降序
}
query.fields().exclude("details.details");//exclude:不需要查询这个字段
T1 t1 = mongoTemplate.findOne(query, T1.class);//findOne:查询集合第一个对象
Query query = new Query();
query.fields().include("_id");//include:只需要查询这个字段
query.fields().include("count");
query.fields().include("startTime");
query.with(Sort.by(Sort.Order.desc("startTime")));
query.limit(10);//分页
List<T1> list = mongoTemplate.find(query, T1.class);
2.聚合管道查询
构造AggregationResults对象
想实现的效果:根据T3时间排序取出前十条,因为文档是嵌套的,需要使用unwind方法展开才能获取对应的值
List<T3> list = new ArrayList<>();
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.unwind("details"),//unwind:展开文档
Aggregation.unwind("details.details"),
Aggregation.sort(Sort.Direction.DESC, "details.details.startTime"),//T3的时间排序,就是一层点一层
Aggregation.limit(10)//分页
).withOptions(Aggregation.newAggregationoptions().allowdiskUse(true).build());
AggregationResults<JSONObject> results = mongoTemplate.aggregate(aggregation, "[集合名称]", JSONObject.class);
//直接映射T3,发现details里的details取不到值,转为JSON格式再映射就拿到了。JSONObject使用到fastjson包
for (JSONObject jsonObject : results) {
T3 t3 = new T3();
JSONObject jsonObject1 = jsonObject.getJSONObject("details").getJSONObject("details");
String status = jsonObject1.getString("status");
String startTime = jsonObject1.getString("createTime");
String message = jsonObject1.getString("message");
t3.setStatus(status);
t3.setCreateTime(startTime);
t3.setMessage(message);
list.add(t3);
}
return list;
动态条件构造查询
想实现的效果:根据T2字段,如果传入时间或者链接,就通过传参查询,如果没有传入则查询全部。并且传入的参数还有页数和页码。mangoDB没有工具类进行分页,所以需要手动分页。并且不像关系型数据库可以直接传参进行分页,是通过skip()跳过进行分页(可能会有深度分页问题)
public CommonPage<T2> queryDetails(DataVo dataVo) {
Integer pageNum = dataVo.getPageNum();//页码
Integer pageSize = dataVo.getPageSize();//页数
if (pageNum <= 0) {
pageNum = 1;
}
if (pageSize <= 0) {
pageSize = 10;
}
Integer skipNum = (pageNum - 1) * pageSize;
String id = "";
if (StrUtil.isEmpty(dataVo.getId())) {
Query query = new Query();
query.with(Sort.by(Sort.Order.desc("startTime")));
query.fields().include("_id");
T1 ti = mongoTemplate.findOne(query, T1.class);
id = ti.getId();
} else {
id = dataVo.getId();
}
List<T2> resultList = new ArrayList<>();
List<Aggregationoperation> commonoperations = new ArrayList<>();
Criteria criteria = Criteria.where("_id").is(id);
UnwindOperation unwind = Aggregation.unwind("details");
SkipOperation skip = Aggregation.skip(skipNum);//跳过文档
LimitOperation limit = Aggregation.limit(pageSize);
SortOperation sort = Aggregation.sort(Sort.Direction.DESC, "details.createTime");
if (StrUtil.isNotEmpty(dataVo.getUrl())) {
String exprSpecialWord = escapeExprSpecialWord(dataVo.getUrl());
Pattern pattern = Pattern.compile("^.*" + exprSpecialWord + ".*$", Pattern.CASE_INSENSITIVE);
criteria.andOperator(Criteria.where("details.url").regex(pattern));
}
if (StrUtil.isNotEmpty(dataVo.getStartTime()) && StrUtil.isNotEmpty(dataVo.getEndTime())) {
criteria.andOperator(Criteria.where("details.createTime").lte(dataVo.getEndTime()).gte(dataVo.getStartTime()));
}
if (dataVo.getStatus() != null && dataVo.getStatus() != 0) {
if (dataVo.getStatus() == 1) {
criteria.andOperator(Criteria.where("details.failPageCount").is(0).and("details.pageCount").gt(0));
} else {
Criteria criteriaFail = new Criteria();
criteriaFail.orOperator(Criteria.where("details.failPageCount").is(0).and("details.pageCount").is(0),//或条件构造器
Criteria.where("details.failPageCount").gt(0).and("details.pageCount").gt(0));
criteria.andOperator(criteriaFail);
}
}
MatchOperation match = Aggregation.match(criteria);
commonoperations.add(unwind);//match条件不能在unwind之前
commonoperations.add(match);
commonoperations.add(skip);
commonoperations.add(limit);
commonoperations.add(sort);
Aggregation aggregation = Aggregation.newAggregation(commonoperations).withOptions(Aggregation.newAggregationoptions().allowdiskUse(true).build());
AggregationResults<JSONObject> results = mongoTemplate.aggregate(aggregation, "[集合名称]", JSONObject.class);
for (JSONObject r : results) {
T2 param = new T2();
JSONObject jsonObject = r.getJSONObject("details");
Integer pageCount = jsonObject.getInteger("pageCount");
Integer failPageCount = jsonObject.getInteger("failPageCount");
param.setUrl(jsonObject.getString("url"));
param.setPageCount(pageCount);
param.setFailPageCount(failPageCount);
param.setCreateTime(jsonObject.getString("createTime"));
if (failPageCount == 0 && pageCount > 0) {
param.setStatus(1);
} else {
param.setStatus(2);
}
param.setDetails(JSONUtil.toList(jsonObject.getString("details"), T3.class));
resultList.add(param);
}
//手动分页计数 移除跳过和分页条件
commonoperations.remove(skip);
commonoperations.remove(limit);
CountOperation count = Aggregation.count().as("count");
commonoperations.add(count);
Aggregation aggregation2 = Aggregation.newAggregation(commonoperations).withOptions(Aggregation.newAggregationoptions().allowdiskUse(true).build());
AggregationResults<JSONObject> results2 = mongoTemplate.aggregate(aggregation2, "[集合名称]", JSONObject.class);
long total = 0;
for (JSONObject jsonObject : results2) {
total = jsonObject.getLong("count");
}
// 设置分页参数
Integer totalPage = Math.toIntExact(total / pageSize + (total % pageSize > 0 ? 1 : 0));
CommonPage<T2> commonPage = CommonPage.restPage(resultList);
commonPage.setPageNum(pageNum);
commonPage.setPageSize(pageSize);
commonPage.setTotalPage(totalPage);
commonPage.setTotal(total);
return commonPage;
}
以上代码使用过程中出现以下问题:
1.sort时间排序有误,需要在分页前就进行排序,故commonoperations.add(sort);放在limit之前;
2.if动态查询条件不支持组合的条件查询,因为只创建了一个对象,多条件查询(两个或三个条件)会有误,故使用
List<Criteria> criteriaList = new ArrayList<>();//创建列表
criteriaList.add(Criteria.where("_id").is(id));//后面所有的动态条件都是这样添加
//...
Criteria criteria = new Criteria();
criteria.andOperator(criteriaList.toArray(new Criteria[0]));//转换成一个criteria
MatchOperation match = Aggregation.match(criteria);
分页数据封装
@NoArgsConstructor
public class CommonPage<T> {
private Integer pageNum;
private Integer pageSize;
private Integer totalPage;
private Long total;
private List<T> list;
/**
* 将pageHelper分页后的list转为分页信息
*/
public static <T> CommonPage<T> restPage(List<T> list) {
CommonPage<T> result = new CommonPage<T>();
PageInfo<T> pageInfo = new PageInfo<T>(list);
result.setTotalPage(pageInfo.getPages());
result.setPageNum(pageInfo.getPageNum());
result.setPageSize(pageInfo.getPageSize());
result.setTotal(pageInfo.getTotal());
result.setList(pageInfo.getList());
return result;
}
/**
* 将SpringData分页后的list转为分页信息
*/
public static <T> CommonPage<T> restPage(Page<T> pageInfo) {
CommonPage<T> result = new CommonPage<T>();
result.setTotalPage(pageInfo.getTotalPages());
result.setPageNum(pageInfo.getNumber());
result.setPageSize(pageInfo.getSize());
result.setTotal(pageInfo.getTotalElements());
result.setList(pageInfo.getContent());
return result;
}
//get set方法 有参构造略
}
public static String escapeExprSpecialWord(String keyword) {
String[] fbsArr = {"\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|"};
for (String key : fbsArr) {
if (keyword.contains(key)) {
keyword = keyword.replace(key, "\\" + key);
}
}
return keyword;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。