我们继续MongoDB系列博客的第三篇,记录下springboot整合MongoDB的基本curd操作,各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!

目录

测试环境准备

测试MongoTemplate的curd

insert 操作

save:没有则创建,存在则更新

删除操作

修改操作

基本查询、范围查询、模糊查询

排序

分页查询

管道Aggregation查询

管道Aggregation分页查询

通过BasicQuery指定返回的字段

通过Aggregation.project指定返回的字段


测试环境准备

测试环境的准备工作就不贴图了,就是创建一个springboot项目,贴一下测试用到的实体类和pom依赖

@Data
@Builder
@Document("user")
public class User {
    private String username;
    private String sex;
    private String address;
    private String createTime;
    private Integer age;
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>mongo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mongo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- SpringBoot 测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- SpringBoot Web容器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- mongodb -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

测试数据

    public User getUser(){
        return User.builder().username("zhaoliu").age(10).sex("男").address(
                "rizhao").build();
    }
    public List<User> getUserList(){
        User user2 =
                User.builder().username("zhangsan").age(10).sex("男").address("jinan").build();
        User user3 =
                User.builder().username("lisi").age(20).sex("女").address("jinan").build();
        List<User> userList = new ArrayList<>();
        userList.add(user2);
        userList.add(user3);
        return userList;
    }

    public void clearDb(){
        mongoTemplate.dropCollection(User.class);
    }

测试MongoTemplate的curd

insert 操作

    @Test
    public void insert(){
        clearDb();

        // insert one
        User user = getUser();
        User user1 = mongoTemplate.insert(user);
    
        // insert many
        List<User> userList = getUserList();
        mongoTemplate.insert(userList,User.class);
        //mongoTemplate.insertAll(userList);
    }

查看数据库结果如下:

如上,上面我们构建User对象时,并没有为createTime属性赋值,也没有为id属性赋值,在保存后,数据库中并没有createTime, 不同于保存mysql 对象属性不赋值会有默认保存进数据库, 比如这个字符串类型的createTime 会默认为空保存,并且也没有id属性,但是保存时mongoDB会默认生成一个Object类型的_id。

上面我们User试题中并没有id属性,保存后在数据库中默认生成了一个Object类型的_id,看下加上id属性后的效果:

    private String id;

同样执行上面的测试方法,执行结果如下:

 如上:虽然我们在User对象中加了id属性,但是保存时并没有单独的id字段,id会自动映射成"_id"吗?测试一下:

User user = User.builder().id("qazwsx").username("zhaoliu").age(20).sex("男").address("rizhao").build();

 我们为id赋值,再次保存后,发现_id的值为qazwsx,可以确定id属性自动映射成了 _id。 我们不想让id自动映射为_id,就想要数据库中保存id怎么办呢,可以使用@Field显示的指定它对应的属性名。

也可以使用@Field注解指定保存到数据库中字段的名字,比如指定User对象id属性保存到数据库中为uid,可以这样:

@Field("uid")
private String id;

User user2 = User.builder().id("zbc").username("yjh").age(18).build();
mongoTemplate.insert(user2);

执行结果如下:

 如果我们既不想使用数据库默认生成的_id,也不想用id自动映射的 _id,可以使用@Id注解标识任意字段为数据库的 _id,比如使用@Id标识username属性,保存后username就会作为数据库的 _id。当然一般我们不会这么办,毕竟username作为主键还是不合适的,这里只是为了测试。

@Id
private String username;

数据库结果如下:

简单总结下保存时的一些细节:

1.保存时mongoDB会默认生成一个Object类型的_id。

2.不初始化属性,保存后数据库没有此filed。

3.执行保存时在java class中的id属性,会自动映射成"_id"。

4.使用@Id标记的字段也会在数据库中显示为_id

接下来的就只贴测试方法不在贴数据库截图了,大家感兴趣可以自己在本地试下:

save:没有则创建,存在则更新

    @Test
    public void save(){
        clearDb();
        // id为 610253fe88164b310a41ca2f 的数据age修改为100
        User user = User.builder().id("610253fe88164b310a41ca2f").username("zhaoliu").sex("男").age(100).build();
        mongoTemplate.save(user);
        // 创建testuser集合 并新增一条数据
        mongoTemplate.save(user,"testuser");
    }

删除操作

    @Test
    public void delete(){
        Query query = new Query();
        Criteria criteria = Criteria.where("_id").is("60ec045d0c385469452d1c21");
        query.addCriteria(criteria);
        mongoTemplate.remove(query,User.class);
        Query query1 = new Query(Criteria.where("_id").ne("60ec0c56b0f4dc6363dfc02a"));
        mongoTemplate.remove(query1,"testuser");
        // delete all datas in collection
        mongoTemplate.dropCollection(User.class);
        // delete collection
        mongoTemplate.dropCollection("mytest1");
    }

修改操作

    /**
     * Update.update(key,value)也可完成修改 ---> 修改一个字段
     * Update.update(key,value).set("key,value) ---> 修改两个字段
     * Update.update(key,value).set("key,value).set(key,value).set...... ---> 修改多个字段
     * 1.修改满足条件的第一条数据 使用updateFirst
     * 2.修改满足条件的所有数据 使用updateMulti
     * 3.upsert: 按条件查询  查询到数据则修改  没查询到则添加  并且upsert只会更新匹配到的第一条数据
     *   如下:若查询到有username为wangwu的数据则将sex改为男
     *        若没查询到有username为wangwu的数据则新插入一条数据(username:wangwu sex:男)
     */
    @Test
    public void update(){
        /*ObjectId objectId = new ObjectId("60ee4af0771c712494b9ac4d");
        Query query = new Query();
        Criteria criteria = Criteria.where("_id").is(objectId);
        query.addCriteria(criteria);
        Update update = new Update();
        update.set("username","zhangsan");*/
        Criteria criteria = Criteria.where("username").is("lisi123");
        Query query = Query.query(criteria);
        Update update = Update.update("username", "lisi");
        //mongoTemplate.updateFirst(query,update,User.class);
        //mongoTemplate.updateMulti(query,update,User.class);
        //mongoTemplate.upsert(query,update,User.class);
        Criteria criteria1 = Criteria.where("username").is("wangwu");
        Query query1 = Query.query(criteria1);
        Update update1 = Update.update("sex","男");
        mongoTemplate.upsert(query1,update1,User.class);
    }

基本查询、范围查询、模糊查询

需要注意的是范围查询,范围查询需要使用Criteria 的andOperator(Criteria... criteria)方法,比如按照age的范围进行查询时需要这样写:

Criteria criteria3 = new Criteria();
criteria3.andOperator(Criteria.where("age").gt(10),Criteria.where("age").lt(50));

 而不能像追加多个条件一样使用如下的方式:

Criteria criteria3 = Criteria.where("age").gt(10).and("age").lt(50);
Criteria criteria3 = new Criteria(); criteria3.and("age").gt(10); criteria3.and("age").lt(50);

 否则会报如下错误:

InvalidMongoDbApiUsageException: Due to limitations of the com.mongodb.BasicDocument, you can't add a second 'age' expression specified as 'age : Document{{$lt=50}}'. Criteria already contains 'age : Document{{$gt=10}}'.

    /**
     * 基本查询 模糊查询 范围查询
     * 使用regex(Pattern pattern) 实现模糊查询
     * 完全匹配:Pattern pattern = Pattern.compile("^张$", Pattern.CASE_INSENSITIVE);
     * 右匹配:Pattern pattern = Pattern.compile("^.*张$", Pattern.CASE_INSENSITIVE);
     * 左匹配:Pattern pattern = Pattern.compile("^张.*$", Pattern.CASE_INSENSITIVE);
     * 模糊匹配:Pattern pattern = Pattern.compile("^.*张.*$", Pattern.CASE_INSENSITIVE);
     */
    @Test
    public void select(){
        Criteria criteria = Criteria.where("username").is("wangwu");
        Query query = Query.query(criteria);
        List<User> userList = mongoTemplate.find(query, User.class);
        System.out.println(userList);
        List<User> all = mongoTemplate.findAll(User.class);
        System.out.println(all);
        // 模糊查询
        Pattern pattern = Pattern.compile("^lisi.*$", Pattern.CASE_INSENSITIVE);
        Criteria criteria1 = Criteria.where("username").regex(pattern);
        Query query1 = Query.query(criteria1);
        User user = mongoTemplate.findOne(query1, User.class);
        System.out.println(user);
        Criteria criteria2 = Criteria.where("_id").is("60ee4af0771c712494b9ac4d");
        Query query2 = Query.query(criteria2);
        User user1 = mongoTemplate.findOne(query2, User.class);
        System.out.println(user1);
        User user2 = mongoTemplate.findById("60ee4af0771c712494b9ac4d", User.class);
        System.out.println(user2);
        long count = mongoTemplate.count(query, User.class);
        System.out.println(count);
        boolean exists = mongoTemplate.exists(query, User.class);
        System.out.println(exists);
        // 范围查询
        // InvalidMongoDbApiUsageException: Due to limitations of the com.mongodb.BasicDocument, you can't add a second 'age' expression specified as 'age : Document{{$lt=50}}'. Criteria already contains 'age : Document{{$gt=10}}'.
        // Criteria criteria3 = Criteria.where("age").gt(10).and("age").lt(50);
        // Criteria criteria3 = new Criteria(); criteria3.and("age").gt(10); criteria3.and("age").lt(50);
        Criteria criteria3 = new Criteria();
        criteria3.andOperator(Criteria.where("age").gt(10),Criteria.where("age").lt(50));
        Query query3 = Query.query(criteria3);
        List<User> userList1 = mongoTemplate.find(query3, User.class);
        System.out.println(userList1);
        // 查询指Map定collection中的数据
        Criteria criteria10 = Criteria.where("name").is("zhangsan");
        Query query10 = Query.query(criteria10);
        List<Map> testuser = mongoTemplate.find(query10, Map.class,"testuser");
        System.out.println(testuser);

    }

排序

/**
     * 排序
     * 1.默认升序 Sort.by("age")
     * 2.可通过Sort.by(Sort.Order.desc("age")) 或 Sort.by(Sort.Direction.DESC,"age") 指定排序方式
     * 3.
     */
    @Test
    public void select1(){
        Query query = new Query();
        Sort sort = Sort.by("age");
        query.with(sort);
        List<User> userList = mongoTemplate.find(query, User.class);
        System.out.println(userList);
        Sort sort1 = Sort.by(Sort.Order.desc("age"));
        query.with(sort1);
        List<User> userList1 = mongoTemplate.find(query, User.class);
        System.out.println(userList1);
        Sort sort2 = Sort.by(Sort.Direction.DESC,"age");
        query.with(sort2);
        List<User> userList2 = mongoTemplate.find(query, User.class);
        System.out.println(userList2);
    }

分页查询

@Test
    public void select2(){
        Pageable page = PageRequest.of(0, 2);
        Query query = new Query();
        query.with(page);
        List<User> userList = mongoTemplate.find(query, User.class);
        System.out.println(userList + "---" + userList.size());
        Sort sort = Sort.by("age");
        Pageable pageable = PageRequest.of(0,2,sort);
        Query query1 = new Query();
        query1.with(pageable);
        List<User> userList1 = mongoTemplate.find(query1, User.class);
        System.out.println(userList1);
        Pageable pageable1 = PageRequest.of(0, 2, Sort.Direction.DESC, new String[]{"age"});
        Query query2 = new Query();
        query2.with(pageable1);
        List<User> userList2 = mongoTemplate.find(query2, User.class);
        System.out.println(userList2);
        // 分页1
        long count = mongoTemplate.count(new Query(), User.class);
        System.out.println(count);
        Page<User> userPage = new PageImpl<User>(userList2,pageable1,count);
        System.out.println("---getTotalElements---" + userPage.getTotalElements());// 总记录数
        System.out.println("---getTotalPages---" + userPage.getTotalPages());// 总页数
        System.out.println("---getNumber---" + userPage.getNumber());// 当前页
        System.out.println("---getSize---" + userPage.getSize());// 每页大小
        System.out.println("---getContent---" + userPage.getContent()); // 数据
        System.out.println("---getNumberOfElements---" + userPage.getNumberOfElements());// 当前页的元素数
        // 分页2
        Page<User> userPage1 = PageableExecutionUtils.getPage(userList2, pageable1, () -> count);
        System.out.println("---getTotalElements---" + userPage1.getTotalElements());// 总记录数
        System.out.println("---getTotalPages---" + userPage1.getTotalPages());// 总页数
        System.out.println("---getNumber---" + userPage1.getNumber());// 当前页
        System.out.println("---getSize---" + userPage1.getSize());// 每页大小
        System.out.println("---getContent---" + userPage1.getContent()); // 数据
        System.out.println("---getNumberOfElements---" + userPage1.getNumberOfElements());// 当前页的元素数
    }

管道Aggregation查询

/**
     * AggregationResults<T> 一般用查询的类接就好
     * [Document{{_id=60ee4af0771c712494b9ac4d, age=30.0}}, Document{{_id=60ee9cd8d82d3d76d2ed2204, age=30.0}}]
     * [User(id=60ee4af0771c712494b9ac4d, username=null, password=null, sex=null, address=null, createTime=null, age=30), User(id=60ee9cd8d82d3d76d2ed2204, username=null, password=null, sex=null, address=null, createTime=null, age=30)]
     */
    @Test
    public void aggregation(){
        // select * from user where age > 20
        Criteria criteria = Criteria.where("age").gt(20);
        // 使用List<AggregationOperation>封装查询条件 或者直接用Aggregation构建 如:Aggregation.match(criteria)
        List<AggregationOperation> operations = new ArrayList<>();
        operations.add(Aggregation.match(criteria));
        TypedAggregation<User> aggregation = Aggregation.newAggregation(User.class,operations);
        AggregationResults<Document> aggregationResults =
                mongoTemplate.aggregate(aggregation, Document.class);
        System.out.println(aggregationResults.getMappedResults());
        // select age,count(*) from user group by age
        List<AggregationOperation> operations1 = new ArrayList<>();
        operations1.add(Aggregation.group("age").sum("age").as("counts"));
        TypedAggregation<User> typedAggregation = TypedAggregation.newAggregation(User.class, operations1);
        AggregationResults<User> aggregationResults1 = mongoTemplate.aggregate(typedAggregation,
                User.class);
        System.out.println(aggregationResults1.getMappedResults());
        Set<String> names = new HashSet<String>();
        names.add("lisi");
        names.add("wangwu");
        Aggregation agg = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("username").in(names)),
                Aggregation.match(Criteria.where("age").gt(10))
        );
        AggregationResults<User> aggregationResults2 = mongoTemplate.aggregate(agg, "user", User.class);
        System.out.println(aggregationResults2.getMappedResults());
    }

管道Aggregation分页查询

@Test
    public void aggregation1(){
        int pageNum = 0;
        int pageSize = 2;
        Pageable pageable = PageRequest.of(pageNum,pageSize);
        int totalCount;
        // 查询条件
        List<AggregationOperation> operations = new ArrayList<>();
        // 模拟一下带条件的查询
        String username = "zhaoliu";
        if(StringUtils.isNotBlank(username)){
            operations.add(Aggregation.match(Criteria.where("username").ne("zhaoliu")));
            Aggregation aggregation = Aggregation.newAggregation(operations);
            AggregationResults<User> aggregationResults = mongoTemplate.aggregate(aggregation, "user",
                    User.class);
            totalCount = aggregationResults.getMappedResults().size();
        }else{
            totalCount = mongoTemplate.findAll(User.class).size();
        }
        // 分页信息
        operations.add(Aggregation.skip((long)pageNum * pageSize));
        operations.add(Aggregation.limit(pageSize));
        // 排序  或者在Pageable中添加排序
        operations.add(Aggregation.sort(Sort.Direction.DESC, "age"));
        //当前页数据
        Aggregation aggregation = Aggregation.newAggregation(operations);
        AggregationResults<User> results = mongoTemplate.aggregate(aggregation, "user", User.class);
        // 分页查询
        Page<User> userPage = PageableExecutionUtils.getPage(results.getMappedResults(), pageable,
                () -> totalCount);
        System.out.println("---getTotalElements---" + userPage.getTotalElements());// 总记录数
        System.out.println("---getTotalPages---" + userPage.getTotalPages());// 总页数
        System.out.println("---getNumber---" + userPage.getNumber());// 当前页
        System.out.println("---getSize---" + userPage.getSize());// 每页大小
        System.out.println("---getContent---" + userPage.getContent()); // 数据
        System.out.println("---getNumberOfElements---" + userPage.getNumberOfElements());// 当前页的元素数
    }

通过BasicQuery指定返回的字段

/**
     * 通过BasicQuery指定返回的字段
     * 不设置的属性字段值为null
     * 如:[User(id=60ee4af0771c712494b9ac4d, username=lisi, sex=女, address=null, createTime=null, age=20)]
     */
    @Test
    public void select3(){
        // 查询条件
        BasicDBObject dbObject = new BasicDBObject();
        dbObject.put("username", "lisi");
        //指定返回的字段
        BasicDBObject fieldsObject = new BasicDBObject();
        fieldsObject.put("username",true);
        fieldsObject.put("age",true);
        fieldsObject.put("sex",true);
        Query query = new BasicQuery(dbObject.toJson(),fieldsObject.toJson());
        List<User> userList = mongoTemplate.find(query, User.class);
        System.out.println(userList);
    }

通过Aggregation.project指定返回的字段

/**
     * 通过Aggregation.project指定返回的字段
     * project :控制返回的字段,例如一个实体类,我们只需要部分字段
     * 同上面一样通过对象接收结果时,没设置的属性值为null
     * 如:[User(id=60ee4af0771c712494b9ac4d, username=lisi, password=null, sex=女, address=null, createTime=null, age=20)]
     * 我们可以使用Map接收
     * 如:[{_id=60ee4af0771c712494b9ac4d, username=lisi, sex=女, age=20.0}]
     * 综上两种方式,如果只想返回指定字段,可以使用map类型来接收返回结果,但是也要看返回数据的结构是否利于后续解析
     * 如果结构复杂,用对象的方式会方便些,虽然有一些我们不需要的属性,但是在最终接口返回前可以转换一下去掉不需要的属性
     */
    @Test
    public void select4(){
        Criteria criteria = Criteria.where("username").is("lisi");
        MatchOperation match = Aggregation.match(criteria);
        ProjectionOperation project = Aggregation.project("username","age","sex");
        Aggregation aggregation = Aggregation.newAggregation(match,project);
        AggregationResults<User> results = mongoTemplate.aggregate(aggregation, "user", User.class);
        System.out.println(results.getMappedResults());
        AggregationResults<Map> results1 = mongoTemplate.aggregate(aggregation, "user", Map.class);
        System.out.println(results1.getMappedResults());
    }

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐