SpringBoot之MongoTemplate的查询可以怎么耍

学习一个新的数据库,一般怎么下手呢?基本的CURD没跑了,当可以熟练的增、删、改、查一个数据库时,可以说对这个数据库算是入门了,如果需要更进一步的话,就需要了解下数据库的特性,比如索引、事物、锁、分布式支持等

本篇博文为mongodb的入门篇,将介绍一下基本的查询操作,在Spring中可以怎么玩

原文可参看: 190113-SpringBoot高级篇MongoDB之查询基本使用姿势

I. 基本使用

0. 环境准备

在正式开始之前,先准备好环境,搭建好工程,对于这一步的详细信息,可以参考博文: 181213-SpringBoot高级篇MongoDB之基本环境搭建与使用

接下来,在一个集合中,准备一下数据如下,我们的基本查询范围就是这些数据

data

1. 根据字段进行查询

最常见的查询场景,比如我们根据查询user=一灰灰blog的数据,这里主要会使用Query + Criteria 来完成

@Component
public class MongoReadWrapper {private static final String COLLECTION_NAME = "demo";@Autowiredprivate MongoTemplate mongoTemplate;/*** 指定field查询*/public void specialFieldQuery() {Query query = new Query(Criteria.where("user").is("一灰灰blog"));// 查询一条满足条件的数据Map result = mongoTemplate.findOne(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | specialFieldQueryOne: " + result);// 满足所有条件的数据List<Map> ans = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | specialFieldQueryAll: " + ans);}
}

上面是一个实际的case,从中可以知道一般的查询方式为:

  • Criteria.where(xxx).is(xxx)来指定具体的查询条件
  • 封装Query对象 new Query(criteria)
  • 借助mongoTemplate执行查询 mongoTemplate.findOne(query, resultType, collectionName)

其中findOne表示只获取一条满足条件的数据;find则会将所有满足条件的返回;上面执行之后,删除结果如

query: Query: { "user" : "一灰灰blog" }, Fields: { }, Sort: { } | specialFieldQueryOne: {_id=5c2368b258f984a4fda63cee, user=一灰灰blog, desc=帅气逼人的码农界老秀}
query: Query: { "user" : "一灰灰blog" }, Fields: { }, Sort: { } | specialFieldQueryAll: [{_id=5c2368b258f984a4fda63cee, user=一灰灰blog, desc=帅气逼人的码农界老秀}, {_id=5c3afaf4e3ac8e8d2d39238a, user=一灰灰blog, desc=帅气逼人的码农界老秀3}, {_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}, {_id=5c3b0031e3ac8e8d2d39238e, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=20.0}, {_id=5c3b003ee3ac8e8d2d39238f, user=一灰灰blog, desc=帅气逼人的码农界老秀6, sign=hello world}]

2. and多条件查询

前面是只有一个条件满足,现在如果是要求同时满足多个条件,则利用org.springframework.data.mongodb.core.query.Criteria#and来斜街多个查询条件

/*** 多个查询条件同时满足*/
public void andQuery() {Query query = new Query(Criteria.where("user").is("一灰灰blog").and("age").is(18));Map result = mongoTemplate.findOne(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | andQuery: " + result);
}

删除结果如下

query: Query: { "user" : "一灰灰blog", "age" : 18 }, Fields: { }, Sort: { } | andQuery: {_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}

3. or或查询

and对应的就是or,多个条件中只要一个满足即可,这个与and的使用有些区别, 借助org.springframework.data.mongodb.core.query.Criteria#orOperator来实现,传参为多个Criteria对象,其中每一个表示一种查询条件

/*** 或查询*/
public void orQuery() {// 等同于 db.getCollection('demo').find({"user": "一灰灰blog", $or: [{ "age": 18}, { "sign": {$exists: true}}]})Query query = new Query(Criteria.where("user").is("一灰灰blog").orOperator(Criteria.where("age").is(18), Criteria.where("sign").exists(true)));List<Map> result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | orQuery: " + result);// 单独的or查询// 等同于Query: { "$or" : [{ "age" : 18 }, { "sign" : { "$exists" : true } }] }, Fields: { }, Sort: { }query = new Query(new Criteria().orOperator(Criteria.where("age").is(18), Criteria.where("sign").exists(true)));result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | orQuery: " + result);
}

执行后输出结果为

query: Query: { "user" : "一灰灰blog", "$or" : [{ "age" : 18 }, { "sign" : { "$exists" : true } }] }, Fields: { }, Sort: { } | orQuery: [{_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}, {_id=5c3b003ee3ac8e8d2d39238f, user=一灰灰blog, desc=帅气逼人的码农界老秀6, sign=hello world}]
query: Query: { "$or" : [{ "age" : 18 }, { "sign" : { "$exists" : true } }] }, Fields: { }, Sort: { } | orQuery: [{_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}, {_id=5c3b003ee3ac8e8d2d39238f, user=一灰灰blog, desc=帅气逼人的码农界老秀6, sign=hello world}, {_id=5c3b0538e3ac8e8d2d392390, user=二灰灰blog, desc=帅气逼人的码农界老秀6, sign=hello world}]

4. in查询

标准的in查询case

/*** in查询*/
public void inQuery() {// 相当于:Query query = new Query(Criteria.where("age").in(Arrays.asList(18, 20, 30)));List<Map> result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | inQuery: " + result);
}

输出

query: Query: { "age" : { "$in" : [18, 20, 30] } }, Fields: { }, Sort: { } | inQuery: [{_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}, {_id=5c3b0031e3ac8e8d2d39238e, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=20.0}]

5. 数值比较

数值的比较大小,主要使用的是 get, gt, lt, let

/*** 数字类型,比较查询 >*/
public void compareBigQuery() {// age > 18Query query = new Query(Criteria.where("age").gt(18));List<Map> result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | compareBigQuery: " + result);// age >= 18query = new Query(Criteria.where("age").gte(18));result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | compareBigQuery: " + result);
}/*** 数字类型,比较查询 <*/
public void compareSmallQuery() {// age < 20Query query = new Query(Criteria.where("age").lt(20));List<Map> result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | compareSmallQuery: " + result);// age <= 20query = new Query(Criteria.where("age").lte(20));result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | compareSmallQuery: " + result);
}

输出

query: Query: { "age" : { "$gt" : 18 } }, Fields: { }, Sort: { } | compareBigQuery: [{_id=5c3b0031e3ac8e8d2d39238e, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=20.0}]
query: Query: { "age" : { "$gte" : 18 } }, Fields: { }, Sort: { } | compareBigQuery: [{_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}, {_id=5c3b0031e3ac8e8d2d39238e, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=20.0}]
query: Query: { "age" : { "$lt" : 20 } }, Fields: { }, Sort: { } | compareSmallQuery: [{_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}]
query: Query: { "age" : { "$lte" : 20 } }, Fields: { }, Sort: { } | compareSmallQuery: [{_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}, {_id=5c3b0031e3ac8e8d2d39238e, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=20.0}]

6. 正则查询

牛逼高大上的功能

/*** 正则查询*/
public void regexQuery() {Query query = new Query(Criteria.where("user").regex("^一灰灰blog"));List<Map> result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | regexQuery: " + result);
}

输出

query: Query: { "user" : { "$regex" : "^一灰灰blog", "$options" : "" } }, Fields: { }, Sort: { } | regexQuery: [{_id=5c2368b258f984a4fda63cee, user=一灰灰blog, desc=帅气逼人的码农界老秀}, {_id=5c3afacde3ac8e8d2d392389, user=一灰灰blog2, desc=帅气逼人的码农界老秀2}, {_id=5c3afaf4e3ac8e8d2d39238a, user=一灰灰blog, desc=帅气逼人的码农界老秀3}, {_id=5c3afafbe3ac8e8d2d39238b, user=一灰灰blog4, desc=帅气逼人的码农界老秀4}, {_id=5c3afb0ae3ac8e8d2d39238c, user=一灰灰blog5, desc=帅气逼人的码农界老秀5}, {_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}, {_id=5c3b0031e3ac8e8d2d39238e, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=20.0}, {_id=5c3b003ee3ac8e8d2d39238f, user=一灰灰blog, desc=帅气逼人的码农界老秀6, sign=hello world}]

7. 查询总数

统计常用,这个主要利用的是mongoTemplate.count方法

/*** 查询总数*/
public void countQuery() {Query query = new Query(Criteria.where("user").is("一灰灰blog"));long cnt = mongoTemplate.count(query, COLLECTION_NAME);System.out.println("query: " + query + " | cnt " + cnt);
}

输出

query: Query: { "user" : "一灰灰blog" }, Fields: { }, Sort: { } | cnt 5

8. 分组查询

这个对应的是mysql中的group查询,但是在mongodb中,更多的是通过聚合查询,可以完成很多类似的操作,下面借助聚合,来看一下分组计算总数怎么玩

/** 分组查询*/
public void groupQuery() {// 根据用户名进行分组统计,每个用户名对应的数量// aggregate([ { "$group" : { "_id" : "user" , "userCount" : { "$sum" : 1}}}] )Aggregation aggregation = Aggregation.newAggregation(Aggregation.group("user").count().as("userCount"));AggregationResults<Map> ans = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);System.out.println("query: " + aggregation + " | groupQuery " + ans.getMappedResults());
}

注意下,这里用Aggregation而不是前面的QueryCriteria,输出如下

query: { "aggregate" : "__collection__", "pipeline" : [{ "$group" : { "_id" : "$user", "userCount" : { "$sum" : 1 } } }] } | groupQuery [{_id=一灰灰blog, userCount=5}, {_id=一灰灰blog2, userCount=1}, {_id=一灰灰blog4, userCount=1}, {_id=二灰灰blog, userCount=1}, {_id=一灰灰blog5, userCount=1}]

9. 排序

sort,比较常见的了,在mongodb中有个有意思的地方在于某个字段,document中并不一定存在,这是会怎样呢?

/*** 排序查询*/
public void sortQuery() {// sort查询条件,需要用with来衔接Query query = Query.query(Criteria.where("user").is("一灰灰blog")).with(Sort.by("age"));List<Map> result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | sortQuery " + result);
}

输出结果如下,对于没有这个字段的document也被查出来了

query: Query: { "user" : "一灰灰blog" }, Fields: { }, Sort: { "age" : 1 } | sortQuery [{_id=5c2368b258f984a4fda63cee, user=一灰灰blog, desc=帅气逼人的码农界老秀}, {_id=5c3afaf4e3ac8e8d2d39238a, user=一灰灰blog, desc=帅气逼人的码农界老秀3}, {_id=5c3b003ee3ac8e8d2d39238f, user=一灰灰blog, desc=帅气逼人的码农界老秀6, sign=hello world}, {_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}, {_id=5c3b0031e3ac8e8d2d39238e, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=20.0}]

10. 分页

数据量多的时候,分页查询比较常见,用得多就是limit和skip了

/*** 分页查询*/
public void pageQuery() {// limit限定查询2条Query query = Query.query(Criteria.where("user").is("一灰灰blog")).with(Sort.by("age")).limit(2);List<Map> result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | limitPageQuery " + result);// skip()方法来跳过指定数量的数据query = Query.query(Criteria.where("user").is("一灰灰blog")).with(Sort.by("age")).skip(2);result = mongoTemplate.find(query, Map.class, COLLECTION_NAME);System.out.println("query: " + query + " | skipPageQuery " + result);
}

输出结果表明,limit用来限制查询多少条数据,skip则表示跳过前面多少条数据

query: Query: { "user" : "一灰灰blog" }, Fields: { }, Sort: { "age" : 1 } | limitPageQuery [{_id=5c2368b258f984a4fda63cee, user=一灰灰blog, desc=帅气逼人的码农界老秀}, {_id=5c3afaf4e3ac8e8d2d39238a, user=一灰灰blog, desc=帅气逼人的码农界老秀3}]
query: Query: { "user" : "一灰灰blog" }, Fields: { }, Sort: { "age" : 1 } | skipPageQuery [{_id=5c3b003ee3ac8e8d2d39238f, user=一灰灰blog, desc=帅气逼人的码农界老秀6, sign=hello world}, {_id=5c3afb1ce3ac8e8d2d39238d, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=18.0}, {_id=5c3b0031e3ac8e8d2d39238e, user=一灰灰blog, desc=帅气逼人的码农界老秀6, age=20.0}]

11. 小结

上面给出的一些常见的查询姿势,当然并不全面,比如我们如果需要查询document中的部分字段怎么办?比如document内部结果比较复杂,有内嵌的对象或者数组时,嵌套查询可以怎么玩?索引什么的又可以怎么利用起来,从而优化查询效率?如何通过传说中自动生成的_id来获取文档创建的时间戳?

先留着这些疑问,后面再补上

II. 其他

0. 项目

  • 工程:spring-boot-demo
  • module: mongo-template
  • 相关博文: 181213-SpringBoot高级篇MongoDB之基本环境搭建与使用

1. 一灰灰Blog

  • 一灰灰Blog个人博客 https://blog.hhui.top
  • 一灰灰Blog-Spring专题博客 http://spring.hhui.top

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

  • 微博地址: 小灰灰Blog
  • QQ: 一灰灰/3302797840

3. 扫描关注

一灰灰blog

QrCode

知识星球

goals

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/252543.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

这可能是我见过最详细的快速排序!

关于快速排序&#xff0c;网上&#xff0c;和维基都有完成的解释&#xff0c;他们都是。。。。。。&#xff0c;俺觉得都是&#xff0c;太过于总结话语在概述一些东西&#xff1b; 而我却从最本质的东西&#xff0c;一步一步的深入&#xff1b;在深入的学习过程中&#xff0c;我…

LINQ to SQL 实现 GROUP BY、聚合、ORDER BY

前言 本示例主要实现 LINQ 查询&#xff0c;先分组&#xff0c;再聚合&#xff0c;最后在排序。示例很简单&#xff0c;但是使用 LINQ 却生成了不同的 SQL 实现。 1) 采用手动编写 SQL 实现 SELECT ROW_NUMBER() OVER(ORDER BY T.RealTotal DESC) AS SN, * FROM ( SELECT (S…

Mysql之事务

什么是事务 假如你下了一笔订单&#xff0c;会有以下数据库操作&#xff1a; 1. 生成一笔订单记录 2. 减少库存 3. 从你的账户中减少金额 4. 生成支付记录 这边的四个操作缺一不可&#xff0c;一旦某一个操作出现异常&#xff0c;则全部操作都需要全部回滚。而事务的作…

JVM垃圾回收机制总结

对于垃圾回收机制我先抛出三个问题&#xff1a; ①哪些内存需要回收&#xff1f; ②什么时候回收&#xff1f; ③如何回收&#xff1f; 下面我们主要针对这三个问题来研究JVM GC 一、哪些内存需要回收&#xff1f; 1.JAVA使用可达性分析法来判断对象是否需要回收。 这个算法的基…

虚拟机增加内存方法

楼主由于要在虚拟机里面装一个oracle&#xff0c;在安装过程中&#xff0c;提示物理内存不符合最低标准&#xff0c;如图1. 图1 因为懒得新建一个虚拟机了&#xff0c;所以考虑给虚拟机新增磁盘空间。 首先说明&#xff0c;新增磁盘空间&#xff0c;必须保证当前虚拟机里每个新…

myBatis xml if、where、if-else?、foreach 心得

MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验&#xff0c;你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格&#xff0c;还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这…

bzoj千题计划213:bzoj2660: [Beijing wc2012]最多的方案

http://www.lydsy.com/JudgeOnline/problem.php?id2660 很容易想到是先把n表示成最大的两个斐波那契数相加&#xff0c;然后再拆分这两个斐波那契数 把数表示成斐波那契进制的形式&#xff0c;第i位表示有没有第i个斐波那契数 比如16133 001001 那么拆分一个数就是把一个1…

面对对象-封装

private 私有的 package/friendly/default 不写 protected 受保护的 public 公共的 那么什么情况该用什么修饰符呢&#xff1f;从作用域来看&#xff0c;public能够适用所有的情况。 但是大家在工作的时候&#xff0c;又不会真正全部都适用public,那么到底什么情况改用什么修饰…

本文详解5G是个什么鬼,程序员都准备好了吗?

无线移动通讯发展历史 最近5G的概念炒的如火如荼&#xff0c;为此&#xff0c;华为和高通还干了一仗。这篇文章从技术层面给大家分析&#xff0c;什么是5G&#xff0c;它和4G比&#xff0c;高级在哪里&#xff1f; 我们来看看移动互联网的技术发展&#xff1a; 然后我们在来看看…

安装kerberos报错 error: command 'gcc' failed with exit status 1

pip install kerberos 报错&#xff1a;error: command gcc failed with exit status 1 安装环境工具 yum install gcc libffi-devel python-devel openssl-devel 再次安装kerberos安装成功 转载于:https://www.cnblogs.com/panbc/p/8268574.html

jquery正则表达式验证:验证全是数字

需求说明&#xff1a; 前端页面使用正则表达式验证输入框中输入的内容全是数字。 代码说明&#xff1a; 这里只介绍正则表达式&#xff0c;其他部分的代码不做介绍。如果有其他需要自行修改即可。 步骤一&#xff1a;建立一个页面可以是html、jsp等&#xff0c;引入jquery-3.2.…

0613课堂汇总

一&#xff1a; 数据类型&#xff1a; 基本数据类型{byte(8)/short(16)/char(16)/int(32)/float(32)/long(64)/double(64)/boolean(1)}引用数据类型{*除了基本数据类型都是引用数据类型 *包括API中的类&#xff08;String,File&#xff09;*自定义的类&#xff08;Personal A…

Istio流量管理实践之(5): 使用cert-manager部署Istio自定义入口网关及进行证书管理...

Istio Gateway提供多个自定义入口网关的支持能力&#xff0c;通过开放一系列端口用于承载网格边缘的进入连接&#xff0c;同时可以使用不同loadbalancer来隔离不同的入口流量。cert-manager可用于使用存储在Kubernetes Secret资源中的任意签名密钥对来获取证书。本文提供了手动…

log4配置

log4j 和 log4j2 方式一&#xff1a;log4j2.xml 添加 jar 包 1 <!-- log4j-core --> 2 <!-- 3 <dependency> 4 <groupId>org.apache.logging.log4j</groupId> 5 <artifactId>log4j-core</artifactId> 6 …

[bzoj3625][Codeforces 250 E]The Child and Binary Tree(生成函数+多项式运算+FFT)

3625: [Codeforces Round #250]小朋友和二叉树 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 650 Solved: 283[Submit][Status][Discuss]Description 我们的小朋友很喜欢计算机科学&#xff0c;而且尤其喜欢二叉树。考虑一个含有n个互异正整数的序列c[1],c[2],...,c[n]。…

常用内建模块

一.datetime 1.模块导入: from datetime import datetime 2.获取当前日期和时间: >>> now datetime.now() >>> print(now) 2019-01-13 14:19:38.1810003.获取指定日期和时间: >>> dt datetime(2019,1,10,15,0) >>> print(dt) 2019-01-10…

子序列进阶问题

题目&#xff1a; 有一个数组&#xff0c;让找到两个不重复的连续子序列A,B &#xff0c;求Max(Sum(A)-Sum(B) 分析&#xff1a; AB必定连续&#xff0c;设两端连接处index为{X&#xff0c;x1}&#xff0c;X可取0~n-1 设F(x)为连接处index为{X&#xff0c;x1}时 Max(Sum(A)…

day5-shelve模块

一、概述前面章节我们讲述了json和pickle模块的序列化和反序列化处理&#xff0c;他们有一个不足是在python 3中不能多次dump和load&#xff0c;shelve模块则可以规避这个问题。shelve模块是一个简单的k,v将内存数据通过文件持久化的模块&#xff0c;可以持久化任何pickle可支持…

程序员:请你不要对业务「置之不理」

成长是条孤独的路&#xff0c;一个人会走得更快&#xff1b;有志同道合者同行&#xff0c;会走得更远。本篇内容整理自 21 天鲲鹏新青年计划线上分享内容。鲲鹏新青年计划是由 TGO 鲲鹏会组织的线上分享活动&#xff0c;希望能帮助更多同学一起学习、成长。12 月 28 日&#xf…

在Ubuntu系统下如何将chrome浏览器的bookmarks导出到本地

1. 打开chrome浏览器在页面的右上角点击那个三个小点的位置&#xff0c;找到bookmarks&#xff0c;然后点击bookmarks manager,然后在organize右侧大倒三角下选择&#xff0c;export bookmarks to HTML&#xff0c;选择要保存的位置&#xff0c;利用同样的方法下次就可以直接导…