首页 > 数据库 >SpringBoot 操作 MongoDB 新增和查询

SpringBoot 操作 MongoDB 新增和查询

时间:2023-05-06 15:47:53浏览次数:60  
标签:00 SpringBoot MongoDB age userId 查询 createDate name

MongoDB JAVA 新增+查询

上接 SpringBoot 整合 MongoDB,记一下 MongoDB 的 CRUD 方法。

Create 新增

使用 MongoRepository 方式的新增非常简单,之前的整合中已经尝试过,这里再总结一下:

首先需要有对应的实体类对象:

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {

    @Id
    private String userId;
    private String name;
    private Integer age;
    private Date createDate;

}

然后创建这个实体类对应的仓库类,继承 MongoRepository 接口,泛型为实体类和实体类的ID类型:

public interface UserRepository extends MongoRepository<User, String> {
    // 无需实现
}

最后直接调用 UserRepository 的 save 方法就可以实现新增操作:

    @RequestMapping("/createUser")
    public User createUser(){
        User user = new User("0723","Qiyuan",21, new Date());
        User saveUser = userRepository.save(user);
        System.out.println(saveUser);
        return saveUser;
    }

访问这个请求地址,会返回这个 User 的信息,说明新增数据成功:

{"userId":"0723","name":"Qiyuan","age":21,"createDate":"2023-05-06T02:46:28.598+00:00"}

如果是批量新增,则对应的将对象放入 List 中即可:

    @RequestMapping("/createUserList")
    public List<User> createUserList(){
        // 将新增的对象放入 List
        List<User> userList = new ArrayList<>();
        userList.add(new User("0718","Irror",18, new Date()));
        userList.add(new User("0123","Inory",19, new Date()));
        List<User> saveUserList = userRepository.saveAll(userList);
        System.out.println(saveUserList);
        return saveUserList;
    }

访问这个请求地址,会以 List 的形式返回增加的 User 的信息,说明增加成功:

[{"userId":"0718","name":"Irror","age":18,"createDate":"2023-05-06T02:48:14.460+00:00"},
{"userId":"0123","name":"Inory","age":19,"createDate":"2023-05-06T02:48:14.460+00:00"}]

查看数据库中的数据,与增加的数据也一致(ID 0118 的是以前加的)。

img

Read 查询

MongoDB 的查询方式有很多种,这里都试一下吧。

仓库类

MongoRepository 提供了许多增删改查的方法,查询的方法即 findAll(),之前已经使用过,但这个方法除了直接查询所有,通过不同的参数还支持排序、分页、条件查询,对应了 findAll() 方法的四个重载。

先看直接使用,调用 findAll() 可以获取集合中的所有对象:

    @RequestMapping("/getAllUsers")
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

请求这个接口,返回对象列表:

[{"userId":"0118","name":"qiyuanc","age":20,"createDate":"2023-04-14T15:13:00.000+00:00"},
{"userId":"0723","name":"Qiyuan","age":21,"createDate":"2023-05-06T02:46:28.598+00:00"},
{"userId":"0718","name":"Irror","age":18,"createDate":"2023-05-06T02:48:14.460+00:00"},
{"userId":"0123","name":"Inory","age":19,"createDate":"2023-05-06T02:48:14.460+00:00"}]

通过构造一个排序 Sort 对象并传入,可以实现排序查询:

    @RequestMapping("/getUsersBySort")
    public List<User> getUsersBySort() {
        // Sort.Direction.ASC 升序  DESC 降序
        Sort sort = Sort.by(Sort.Direction.ASC, "age");
        // 根据传入的排序条件查询
        List<User> users = userRepository.findAll(sort);
        return userRepository.findAll();
    }

请求这个接口,返回的结果就是按年龄升序排列的了:

[{"userId":"0718","name":"Irror","age":18,"createDate":"2023-05-06T02:48:14.460+00:00"},
{"userId":"0123","name":"Inory","age":19,"createDate":"2023-05-06T02:48:14.460+00:00"},
{"userId":"0118","name":"qiyuanc","age":20,"createDate":"2023-04-14T15:13:00.000+00:00"},
{"userId":"0723","name":"Qiyuan","age":21,"createDate":"2023-05-06T02:46:28.598+00:00"}]

通过构造一个分页 PageRequest 对象并传入,可以实现分页查询,需要注意,MongoDB 的页数从0开始:

    @RequestMapping("/getUsersByPage/{page}/{rows}")
    public Page<User> getUsersByPage(@PathVariable int page, @PathVariable int rows) {
        // 构造方法访问权限为 protected
        // MongoDB 页数从0开始 需要 -1
        PageRequest pageRequest = PageRequest.of(page-1, rows);
        return userRepository.findAll(pageRequest);
    }

请求 /getUsersByPage/1/2 返回的就是包含第一页的两条数据的分页对象:

{"content":
	[{"userId":"0118","name":"qiyuanc","age":20,"createDate":"2023-04-14T15:13:00.000+00:00"},
	{"userId":"0723","name":"Qiyuan","age":21,"createDate":"2023-05-06T02:46:28.598+00:00"}],
"pageable":
	{"sort":{"sorted":false,"unsorted":true,"empty":true},"offset":0,"pageNumber":0,"pageSize":2,"unpaged":false,"paged":true},
"totalPages":2,"totalElements":4,"last":false,"number":0,"size":2,
"sort":{"sorted":false,"unsorted":true,"empty":true},
"numberOfElements":2,"first":true,"empty":false}

最后是条件查询,需要构建模板 Example 对象,在构建这个对象前又需要一个匹配器指定匹配规则、一个实体对象存放匹配参数,还是挺麻烦的,网上能搜到的内容也少,可能就不怎么常用:

    @RequestMapping("/getUsersByExample")
    public List<User> getUsersByExample() {
        // 匹配规则:忽略大小写 + name 包含
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withIgnoreCase()
                .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains());

        User user = new User();
        user.setName("qiyuan");

        // 查询模板
        Example<User> example = Example.of(user, matcher);
        List<User> userList = userRepository.findAll(example);

        return userList;
    }

请求这个接口就返回了条件查询的结果,名字包含 qiyuan 的对象:

[{"userId":"0118","name":"qiyuanc","age":20,"createDate":"2023-04-14T15:13:00.000+00:00"},
{"userId":"0723","name":"Qiyuan","age":21,"createDate":"2023-05-06T02:46:28.598+00:00"}]

仓库类的查询方式大概就这么多,虽然可以直接用,但条件查询好像不是很友好啊。。。

@Qurey注解

上面是直接使用仓库类自带的方法进行查询,在简单场景下应该是够用,但复杂一点的场景就会麻烦。所以 MongoDB 支持使用 @Query 注解自定义查询方法,使用的也是 MongoDB 的原生查询语句。

在仓库类 UserRepository 中添加两个方法,一个是上面实现了的根据名字查询(忽略大小写)的方法,还有一个是查询年龄小于输入参数的方法:

public interface UserRepository extends MongoRepository<User, String> {
    // 自定义查询方法
    @Query("{ 'name' : { $regex: ?0, $options: 'i' } }")
    List<User> findByNameContainingIgnoreCase(String name);

    @Query("{ 'age' : { $lt: ?0 } }")
    List<User> findByAgeLessThan(int age);
}

这两个方法都通过 @Query 注解自定义了查询逻辑,这里使用了 $regex 来进行模糊匹配,$options 选项设置为 'i' 表示不区分大小写,$lt 即 LessThan,?0 则代表了第一个参数。

使用时直接调用,传入相应的参数即可:

    @RequestMapping("/getUserByName/{name}")
    public List<User> getUserByName(@PathVariable String name){
        // 调用仓库类的方法
        List<User> saveUserList = userRepository.findByNameContainingIgnoreCase(name);
        return saveUserList;
    }

    @RequestMapping("/getUserByLessThanAge/{age}")
    public List<User> getUserByLessThanAge(@PathVariable int age){
        // 调用仓库类的方法
        List<User> saveUserList = userRepository.findByAgeLessThan(age);
        return saveUserList;
    }

为了方便我都使用了路径参数,请求 /getUserByName/qiyuan 会返回名字包含 qiyuan 的用户

[{"userId":"0118","name":"qiyuanc","age":20,"createDate":"2023-04-14T15:13:00.000+00:00"},
{"userId":"0723","name":"Qiyuan","age":21,"createDate":"2023-05-06T02:46:28.598+00:00"}]

请求 /getUserByLessThanAge/20 会返回年龄小于20的用户:

[{"userId":"0718","name":"Irror","age":18,"createDate":"2023-05-06T02:48:14.460+00:00"},
{"userId":"0123","name":"Inory","age":19,"createDate":"2023-05-06T02:48:14.460+00:00"}]

这种方式通过自己写查询语句,比仓库类自带的方法灵活多了,但也相对复杂一定,有舍有得。

Query对象

除了使用 @Query 预先定义查询方法外,也可以通过创建 Query 对象并设置其中的 Criteria 指定查询条件,这种方式胜在随处可用,但需要引入 MongoTemplate 对象:

    @Autowired
    private MongoTemplate mongoTemplate;

举个例子,写一个支持名字和年龄查询的方法:

    @RequestMapping("/getUserByQuery/{name}/{date}")
    public List<User> getUserByQuery(@PathVariable String name, @PathVariable int age){

        // 指定查询的集合
        String collectionName = "user";

        // 构造查询对象
        Query query = Query.query(Criteria.where("name").regex(".*" + name + ".*", "i")
                .and("age").gte(age));
        // 调用 mongoTemplate 查询
        List<User> users = mongoTemplate.find(query, User.class, collectionName);

        return users;
    }

其中的 Criteria 就是查询条件了,通过链式编程的方式可以一直往下写。最后通过 mongoTemplate 对象进行查询,注意需要指定查询的集合。

如请求 /getUserByGreaterThanDate/qiyuan/2023-05-01 查询名字包括 qiyuan 且年龄大于等于 21 的用户:

[{"userId":"0723","name":"Qiyuan","age":21,"createDate":"2023-05-06T02:46:28.598+00:00"}]

使用 Query 对象查询的方式本质还是构造 MongoDB 原生的查询语句去查询,如上面这个查询参数对应的就是

Query: { "name" : { "$regularExpression" : { "pattern" : ".*qiyuan.*", "options" : "i"}}, "age" : { "$gte" : 21}}, Fields: {}, Sort: {}

因此这种方式可以说是最灵活的了,可以指定的东西非常多。

总结

在 MongoDB 中尝试了基本的新增、查询操作,还有修改、查询没搞。其实是因为修改搞半天搞不好,累了,下次再说吧。

标签:00,SpringBoot,MongoDB,age,userId,查询,createDate,name
From: https://www.cnblogs.com/qiyuanc/p/Back15.html

相关文章

  • 聊聊关于,SpringBoot写后端接口
    前言:一个后端接口大致分为四个部分组成:接口地址(url)、接口请求方式(get、post等)、请求数据(request)、响应数据(response)。如何构建这几个部分每个公司要求都不同,没有什么“一定是最好的”标准,但一个优秀的后端接口和一个糟糕的后端接口对比起来差异还是蛮大的,其中最重要的关键点就是......
  • SpringBoot 自动扫描第三方包及spring.factories失效的问题
    为什么会找不到Spring依赖注入就是要让spring找到要注入的类并且识别到了@Component、@Service等注解。1.当在开发的第三方包里写明了@Component、@Service等等2.引入了包,不论第三方库的引入,还是本地jar。总之是要引入到工程的这时候还加入不到IOC容器,那就说明Spri......
  • SQL_常用查询
    <说明>SNO---学号SN----学生姓名 SheName---数据表名<说明> 【查询】select*from SheName   //取所有数据selectcount(*)from SheName //统计数据条数select SNO,SNfrom SheName//查询全体学生的学号和姓名【修改】【删除】de......
  • 用最低成本实现高性能写入、查询、存储,揭秘 TDengine 技术实现逻辑
    从《写入性能:TDengine最高达到InfluxDB的10.3倍,TimeScaleDB的6.74倍》、《查询性能:TDengine最高达到了InfluxDB的37倍、TimescaleDB的28.6倍》两篇文章中,我们发现,TDengine(TimeSeriesDatabase)不仅在写入和查询性能上超越了InfluxDB和TimescaleDB,在数据处理过......
  • Springboot 系列 (30) - Springboot+HBase 大数据存储(八)| Springboot Client/Server
    Kerberos(SecureNetworkAuthenticationSystem,网络安全认证系统),是一种网络认证协议,其设计目标是通过密钥系统为Client/Server提供强大的认证服务。该认证过程的实现不依赖于主机操作系统的认证,无需基于的信任,不要求网络上所有主机的物理安全,并假定网络上传送的数据包可以被......
  • 使用Node.js调用Sqlite3模块写的大数据查询接口
    使用Node.js调用Sqlite3模块写的大数据查询接口constsqlite3=require('sqlite3');consthttp=require('http');consturl=require('url');constSqliteDb=async(dbFile)=>{constpri={};pri.db=newsqlite3.Database(dbFile);......
  • SLS日志查询遇到的一些问题
    SLS日志查询遇到的一些问题根据执行时间查询结果不准确的问题原因:索引类型造成的;解决:进入索引设置,改为double即可;注意,只对更改后的日志生效,之前的旧日志不生效;一些常用查询语句查询执行时间大于5秒的*and__topic__:访问记录日志andoperation_hours>5查询平均执行时......
  • Elasticsearch模糊查询
    Elasticsearch模糊查询ES模糊查询共有三种:1.match分词匹配查询和match_phrase短语查询Elasticsearch的match_phrase短语查询跟match的区别就是,关键词作为一个整体进行搜索,而不是拆分成一个个关键词。当匹配对象为中文时,建议使用:MatchPhraseQueryBuilderquery=......
  • .net 6 使用 NEST 查询,时间字段传值踩坑
    0x01业务描述说明:同事搭建的业务系统,最开始使用 log4net 记录到本地日志.然后多个项目为了日志统一,全部记录在 Elasticsearch ,使用  log4net.ElasticSearchAppender.DotNetCore.然后搭建了Kibanal  对 Elasticsearch 进行查询. 但是项目组开发人员众多,不是每......
  • IDEA编写的SpringBoot项目修改后自动编译刷新
    问题的描述:       IDEA编写传统web应用使用外置的Tomcat时候,IDEA设置了外置的Tomcat的编译刷新,前端代码修改后是可以自动编译,页面刷新就能看到效果的。而开发SpringBoot项目的时候,因为它使用的是内置的Tomcat,所以即使是在html页面上修改内容,也必......