SpringBoot 集成 Spring Data Mongodb 操作 MongoDB 详解

SpringBoot 集成 Spring Data Mongodb 操作 MongoDB 详解

文章目录

  !版权声明:本博客内容均为原创,每篇博文作为知识积累,写博不易,转载请注明出处。


系统环境:

  • Java JDK 版本:1.8
  • SpringBoot 版本:2.3.0.RELEASE

参考地址:

示例项目地址:

一、MongoDB 简介

MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,且与关系数据库的最为相像的。它支持的数据结构非常松散,是类似 json 的 bson 格式,因此可以存储比较复杂的数据类型。Mongo 最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

二、MongoDB 特征

MongoDB 是一个文档数据库,它的数据以文档方式进行存储,将数据存储在类似 JSON 的 BSON 文档中,其特征如下:

  • 数据以 BSON 方式存储
    • 允许灵活和动态的模式。
    • 支持数组和嵌套对象作为值。
    • 处理数据的最自然,最有效的方式。
    • 文档模型轻松映射到应用程序代码中的对象
  • 强大的查询语言
    • 支持聚合和其他现代用例,例如基于地理的搜索,图形搜索和文本搜索。
    • 查询本身就是 JSON,因此很容易组合。不再需要串联字符串来动态生成 SQL 查询。
    • 丰富而富有表现力的查询语言,无论您在文档中有多嵌套,都可以按任何字段进行过滤和排序。
  • 拥有关系数据库的所有功能
    • 支持查询联接。
    • 具有快照隔离功能的分布式多文档 ACID 事务。
    • 两种类型的关系,而不是一种"引用"和"嵌入式"。
  • 分布式数据库为核心
    • 水平扩展
    • 内置了高可用性
    • 地理分布并且易于使用
  • MongoDB 免费使用

三、MongoDB 概念

简单介绍下 MongoDB 的概念知识,方便后续使用 SpringBoot 操作 MongoDB 时候对 MongoDB 相关概念知道其作用。

本文章并不是用于介绍 MongoDB 知识,而是介绍在 Java 语言中 SpringBoot 框架里如何操作 MongoDB。所以,在操作 MongoDB 前,最好对其知识点进行一下系统的学习。

1、基本概念

MongoDB 基本概念指的是学习 MongoDB 最先应该了解的词汇,比如 MongoDB 中的"数据库"、"集合"、"文档"这三个名词:

  • 文档(Document): 文档是 MongoDB 中最基本的数据单元,由键值对组成,类似于 JSON 格式,可以存储不同字段,字段的值可以包括其他文档,数组和文档数组。
  • 集合(Collection): 集合指的是文档组(类似于 Mysql 中的表的概念),里面可以存储许多文档。
  • 数据库(Database): MongoDB 中可以存在多个数据库,每个数据库中中用有不同的集合与用户权限,这样可以供不同的项目组使用不同的数据库。

当然,还有其它一些概念,比如:

  • _id(主键): 主键主要作用是用于保证数据完整性,加快数据库的访问速度,方便快速定位某个文档。在 MongoDB 中可以手动指定文档主键 ID,如果未手动指定则 MongoDB 会生成 12 位的 ObjectID。
  • index(索引): 索引是一种特殊的数据结构,存储在一个易于遍历读取的数据集合中,其能够对数据库文档中的数据进行排序的一种结构。索引通常能极大提高文档查询效率,如果没有设置索引,MongoDB 会遍历集合中的整个文档,选取符合查询条件的文档记录。这种查询效率是非常低的,当处理大量时,查询可能需要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
  • field(字段): 文档中的字段,类似于关系型数据库中的列。
  • aggregation(聚合) MongoDB 中聚合主要用于处理数据处理,例如统计平均值、求和等,可以快速通过聚合操作,汇总数据,尤其是对绘制图表添加了便利。

2、数据类型

以下为 MongoDB 中常用的几种数据类型:

  • String: 字符串,存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
  • Integer: 整型数值,用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
  • Boolean: 布尔值,用于存储布尔值(true/false)。
  • Double: 双精度浮点值,用于存储浮点值。
  • Min/Max keys: 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
  • Array: 用于将数组或列表或多个值存储为一个键。
  • Timestamp: 时间戳。记录文档修改或添加的具体时间。
  • Object: 用于内嵌文档。
  • Null: 用于创建空值。
  • Symbol: 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
  • Date: 日期时间,用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
  • Object ID: 对象 ID,用于创建文档的 ID。
  • Binary Data: 二进制数据,用于存储二进制数据。
  • Code: 代码类型,用于在文档中存储 JavaScript 代码。
  • Regular expression: 正则表达式类型,用于存储正则表达式。

四、Springboot 操作 MongoDB 示例

这里使用 Spring Data MongoDB 封装的 MongoDB 官方 Java 驱动 MongoTemplate 对 MongoDB 进行操作。

关于使用简单的 Repositories 方式来操作 MongoDB 这种用法只能实现较简单的操作,使用简单但是灵活性比较差,所以这里就不介绍这种使用方式了。

1、Maven 引入相关依赖

Maven 引入 SpringBoot 和 MongoDB 相关依赖组件:

 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 4    <modelVersion>4.0.0</modelVersion>
 5
 6    <parent>
 7        <groupId>org.springframework.boot</groupId>
 8        <artifactId>spring-boot-starter-parent</artifactId>
 9        <version>2.3.0.RELEASE</version>
10    </parent>
11
12    <groupId>mydlq.club</groupId>
13    <artifactId>springboot-mongodb-template-example</artifactId>
14    <version>0.0.1</version>
15    <name>springboot-mongodb-template-example</name>
16    <description>Demo project for Spring Boot MongoDB</description>
17
18    <properties>
19        <java.version>1.8</java.version>
20    </properties>
21
22    <dependencies>
23        <!-- SpringBoot Web -->
24        <dependency>
25            <groupId>org.springframework.boot</groupId>
26            <artifactId>spring-boot-starter-web</artifactId>
27        </dependency>
28        <!-- Lombok -->
29        <dependency>
30            <groupId>org.projectlombok</groupId>
31            <artifactId>lombok</artifactId>
32            <scope>provided</scope>
33        </dependency>
34        <!-- SpringBoot MongoDB -->
35        <dependency>
36            <groupId>org.springframework.boot</groupId>
37            <artifactId>spring-boot-starter-data-mongodb</artifactId>
38        </dependency>
39    </dependencies>
40
41    <build>
42        <plugins>
43            <plugin>
44                <groupId>org.springframework.boot</groupId>
45                <artifactId>spring-boot-maven-plugin</artifactId>
46            </plugin>
47        </plugins>
48    </build>
49
50</project>

依赖说明:

  • spring-boot-starter-web: SpringBoot 的 Web 依赖。
  • lombok: Lombok 工具依赖,便于生成实体对象的 Get 与 Set 方法。
  • spring-boot-starter-data-mongodb:Spring 对 MongoDb 提供的 Java Drive 封装的框架。

2、Application 文件中添加 MongoDB 连接配置

在 SpringBoot 的 application.yml 文件中添加连接 MongoDB 的配置参数,内容如下:

1spring:
2  data:
3    mongodb:
4      host: 127.0.0.1
5      port: 27017
6      database: test
7      username: admin
8      password: 123456

参数介绍:

  • spring.data.mongodb.host: 指定 MongoDB Server 地址
  • spring.data.mongodb.port: 指定 MongoDB Server 端口
  • spring.data.mongodb.database: 指定使用的数据库
  • spring.data.mongodb.username: MongoDB 用户名
  • spring.data.mongodb.password: MongoDB 密码

3、创建用于测试的实体类

创建用于示例中测试的实体 User 和 Status 类:

User.java

 1import com.fasterxml.jackson.annotation.JsonFormat;
 2import lombok.Data;
 3import lombok.ToString;
 4import lombok.experimental.Accessors;
 5import org.springframework.data.mongodb.core.mapping.MongoId;
 6import java.util.Date;
 7
 8@Data
 9@ToString
10@Accessors(chain = true)
11public class User {
12
13    /**
14     * 使用 @MongoID 能更清晰的指定 _id 主键
15     */
16    @MongoId
17    private String id;
18    private String name;
19    private String sex;
20    private Integer salary;
21    private Integer age;
22    @JsonFormat( pattern ="yyyy-MM-dd", timezone ="GMT+8")
23    private Date birthday;
24    private String remake;
25    private Status status;
26
27}

使用 Lombok 中的 @Accessors(chain = true) 注解,能让我们方便使用链式方法创建实体对象。

Status.java

 1import lombok.Data;
 2import lombok.ToString;
 3import lombok.experimental.Accessors;
 4
 5@Data
 6@ToString
 7@Accessors(chain = true)
 8public class Status {
 9
10    private Integer weight;
11    private Integer height;
12
13}

4、SpringBoot 启动类

创建 SpringBoot 启动类,方便测试:

 1import org.springframework.boot.SpringApplication;
 2import org.springframework.boot.autoconfigure.SpringBootApplication;
 3import springfox.documentation.swagger2.annotations.EnableSwagger2;
 4
 5@EnableSwagger2
 6@SpringBootApplication
 7public class Application {
 8
 9    public static void main(String[] args) {
10        SpringApplication.run(Application.class, args);
11    }
12
13}

5、MongoDB 集合操作

(1)、创建集合

示例代码如下:

 1import org.springframework.data.mongodb.core.CollectionOptions;
 2import org.springframework.data.mongodb.core.MongoTemplate;
 3import org.springframework.data.mongodb.core.query.Criteria;
 4import org.springframework.data.mongodb.core.query.CriteriaDefinition;
 5import org.springframework.data.mongodb.core.validation.Validator;
 6import org.springframework.stereotype.Service;
 7import javax.annotation.Resource;
 8
 9@Service
10public class CreateCollectionService {
11
12    @Resource
13    private MongoTemplate mongoTemplate;
14
15    /**
16     * 创建【集合】
17     * 
18     * 创建一个大小没有限制的集合(默认集合创建方式) 
19     * 
20     * @return 创建集合的结果
21     */
22    public Object createCollection() {
23        // 设置集合名称
24        String collectionName = "users1";
25        // 创建集合并返回集合信息
26        mongoTemplate.createCollection(collectionName);
27        // 检测新的集合是否存在,返回创建结果
28        return mongoTemplate.collectionExists(collectionName) ? "创建视图成功" : "创建视图失败";
29    }
30
31    /**
32     * 创建【固定大小集合】
33     * 
34     * 创建集合并设置 `capped=true` 创建 `固定大小集合`,可以配置参数 `size` 限制文档大小,可以配置参数 `max` 限制集合文档数量。
35     *
36     * @return 创建集合的结果
37     */
38    public Object createCollectionFixedSize() {
39        // 设置集合名称
40        String collectionName = "users2";
41        // 设置集合参数
42        long size = 1024L;
43        long max = 5L;
44        // 创建固定大小集合
45        CollectionOptions collectionOptions = CollectionOptions.empty()
46                // 创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。
47                .capped()
48                // 固定集合指定一个最大值,以千字节计(KB),如果 capped 为 true,也需要指定该字段。
49                .size(size)
50                // 指定固定集合中包含文档的最大数量。
51                .maxDocuments(max);
52        // 执行创建集合
53        mongoTemplate.createCollection(collectionName, collectionOptions);
54        // 检测新的集合是否存在,返回创建结果
55        return mongoTemplate.collectionExists(collectionName) ? "创建视图成功" : "创建视图失败";
56    }
57
58    /**
59     * 创建【验证文档数据】的集合
60     *
61     * 创建集合并在文档"插入"与"更新"时进行数据效验,如果符合创建集合设置的条件就进允许更新与插入,否则则按照设置的设置的策略进行处理。
62     *
63     * * 效验级别:
64     *   - off:关闭数据校验。
65     *   - strict:(默认值) 对所有的文档"插入"与"更新"操作有效。
66     *   - moderate:仅对"插入"和满足校验规则的"文档"做"更新"操作有效。对已存在的不符合校验规则的"文档"无效。 
67     * * 执行策略:
68     *   - error:(默认值) 文档必须满足校验规则,才能被写入。
69     *   - warn:对于"文档"不符合校验规则的 MongoDB 允许写入,但会记录一条告警到 mongod.log 中去。日志内容记录报错信息以及该"文档"的完整记录。
70     * 
71     * @return 创建集合结果
72     */
73    public Object createCollectionValidation() {
74        // 设置集合名称
75        String collectionName = "users3";
76        // 设置验证条件,只允许岁数大于20的用户信息插入
77        CriteriaDefinition criteria = Criteria.where("age").gt(20);
78        // 设置集合选项验证对象
79        CollectionOptions collectionOptions = CollectionOptions.empty()
80                .validator(Validator.criteria(criteria))
81                // 设置效验级别
82                .strictValidation()
83                // 设置效验不通过后执行的动作
84                .failOnValidationError();
85        // 执行创建集合
86        mongoTemplate.createCollection(collectionName, collectionOptions);
87        // 检测新的集合是否存在,返回创建结果
88        return mongoTemplate.collectionExists(collectionName) ? "创建集合成功" : "创建集合失败";
89    }
90
91}

(2)、查询集合

 1import org.springframework.data.mongodb.core.MongoTemplate;
 2import org.springframework.stereotype.Service;
 3import javax.annotation.Resource;
 4
 5@Service
 6public class QueryCollectionService {
 7
 8    @Resource
 9    private MongoTemplate mongoTemplate;
10
11    /**
12     * 获取【集合名称】列表
13     *
14     * @return 集合名称列表
15     */
16    public Object getCollectionNames() {
17        // 执行获取集合名称列表
18        return mongoTemplate.getCollectionNames();
19    }
20
21    /**
22     * 检测集合【是否存在】
23     *
24     * @return 集合是否存在
25     */
26    public boolean collectionExists() {
27        // 设置集合名称
28        String collectionName = "users";
29        // 检测新的集合是否存在,返回检测结果
30        return mongoTemplate.collectionExists(collectionName);
31    }
32
33}

(3)、删除集合

 1import org.springframework.data.mongodb.core.MongoTemplate;
 2import org.springframework.stereotype.Service;
 3import javax.annotation.Resource;
 4
 5@Service
 6public class RemoveCollectionService {
 7
 8    @Resource
 9    private MongoTemplate mongoTemplate;
10
11    /**
12     * 删除【集合】
13     *
14     * @return 创建集合结果
15     */
16    public Object dropCollection() {
17        // 设置集合名称
18        String collectionName = "users3";
19        // 执行删除集合
20        mongoTemplate.getCollection(collectionName).drop();
21        // 检测新的集合是否存在,返回删除结果
22        return !mongoTemplate.collectionExists(collectionName) ? "删除集合成功" : "删除集合失败";
23    }
24
25}

6、MongoDB 视图操作

 1import org.bson.Document;
 2import org.bson.conversions.Bson;
 3import org.springframework.data.mongodb.core.MongoTemplate;
 4import org.springframework.stereotype.Service;
 5import javax.annotation.Resource;
 6import java.util.ArrayList;
 7import java.util.List;
 8
 9@Service
10public class ViewService {
11
12    @Resource
13    private MongoTemplate mongoTemplate;
14
15    /**
16     * 创建视图
17     *
18     * @return 创建视图结果
19     */
20    public Object createView() {
21        // 设置视图名
22        String newViewName = "usersView";
23        // 设置获取数据的集合名称
24        String collectionName = "users";
25        // 定义视图的管道,可是设置视图显示的内容多个筛选条件
26        List<Bson> pipeline = new ArrayList<>();
27        // 设置条件,用于筛选集合中的文档数据,只有符合条件的才会映射到视图中
28        pipeline.add(Document.parse("{\"$match\":{\"sex\":\"女\"}}"));
29        // 执行创建视图
30        mongoTemplate.getDb().createView(newViewName, collectionName, pipeline);
31        // 检测新的集合是否存在,返回创建结果
32        return mongoTemplate.collectionExists(newViewName) ? "创建视图成功" : "创建视图失败";
33    }
34
35    /**
36     * 删除视图
37     *
38     * @return 删除视图结果
39     */
40    public Object dropView() {
41        // 设置待删除的视图名称
42        String viewName = "usersView";
43        // 检测视图是否存在
44        if (mongoTemplate.collectionExists(viewName)) {
45            // 删除视图
46            mongoTemplate.getDb().getCollection(viewName).drop();
47            return "删除视图成功";
48        }
49        // 检测新的集合是否存在,返回创建结果
50        return !mongoTemplate.collectionExists(viewName) ? "删除视图成功" : "删除视图失败";
51    }
52
53}

7、MongoDB 文档操作

(1)、文档插入

 1import lombok.extern.slf4j.Slf4j;
 2import mydlq.club.example.entity.Status;
 3import mydlq.club.example.entity.User;
 4import org.springframework.data.mongodb.core.MongoTemplate;
 5import org.springframework.stereotype.Service;
 6import javax.annotation.Resource;
 7import java.util.ArrayList;
 8import java.util.Collection;
 9import java.util.Date;
10import java.util.List;
11
12@Slf4j
13@Service
14public class InsertService {
15
16    /** 设置集合名称 */
17    private static final String COLLECTION_NAME = "users";
18
19    @Resource
20    private MongoTemplate mongoTemplate;
21
22    /**
23     * 插入【一条】文档数据,如果文档信息已经【存在就抛出异常】
24     *
25     * @return 插入的文档信息
26     */
27    public Object insert() {
28        // 设置用户信息
29        User user = new User()
30                .setId("10")
31                .setAge(22)
32                .setSex("男")
33                .setRemake("无")
34                .setSalary(1500)
35                .setName("zhangsan")
36                .setBirthday(new Date())
37                .setStatus(new Status().setHeight(180).setWeight(150));
38        // 插入一条用户数据,如果文档信息已经存在就抛出异常
39        User newUser = mongoTemplate.insert(user, COLLECTION_NAME);
40        // 输出存储结果
41        log.info("存储的用户信息为:{}", newUser);
42        return newUser;
43    }
44
45    /**
46     * 插入【多条】文档数据,如果文档信息已经【存在就抛出异常】
47     *
48     * @return 插入的多个文档信息
49     *
50     */
51    public Object insertMany(){
52        // 设置两个用户信息
53        User user1 = new User()
54                .setId("11")
55                .setAge(22)
56                .setSex("男")
57                .setRemake("无")
58                .setSalary(1500)
59                .setName("shiyi")
60                .setBirthday(new Date())
61                .setStatus(new Status().setHeight(180).setWeight(150));
62        User user2 = new User()
63                .setId("12")
64                .setAge(22)
65                .setSex("男")
66                .setRemake("无")
67                .setSalary(1500)
68                .setName("shier")
69                .setBirthday(new Date())
70                .setStatus(new Status().setHeight(180).setWeight(150));
71        // 使用户信息加入结合
72        List<User> userList = new ArrayList<>();
73        userList.add(user1);
74        userList.add(user2);
75        // 插入一条用户数据,如果某个文档信息已经存在就抛出异常
76        Collection<User> newUserList = mongoTemplate.insert(userList, COLLECTION_NAME);
77        // 输出存储结果
78        for (User user : newUserList) {
79            log.info("存储的用户信息为:{}", user);
80        }
81        return newUserList;
82    }
83
84}

(2)、文档存储

 1import lombok.extern.slf4j.Slf4j;
 2import mydlq.club.example.entity.Status;
 3import mydlq.club.example.entity.User;
 4import org.springframework.data.mongodb.core.MongoTemplate;
 5import org.springframework.stereotype.Service;
 6import javax.annotation.Resource;
 7import java.util.Date;
 8
 9@Slf4j
10@Service
11public class SaveService {
12
13    /** 设置集合名称 */
14    private static final String COLLECTION_NAME = "users";
15
16    @Resource
17    private MongoTemplate mongoTemplate;
18
19    /**
20     * 存储【一条】用户信息,如果文档信息已经【存在就执行更新】
21     *
22     * @return 存储的文档信息
23     */
24    public Object save() {
25        // 设置用户信息
26        User user = new User()
27                .setId("13")
28                .setAge(22)
29                .setSex("男")
30                .setRemake("无")
31                .setSalary(2800)
32                .setName("kuiba")
33                .setBirthday(new Date())
34                .setStatus(new Status().setHeight(169).setWeight(150));
35        // 存储用户信息,如果文档信息已经存在就执行更新
36        User newUser = mongoTemplate.save(user, COLLECTION_NAME);
37        // 输出存储结果
38        log.info("存储的用户信息为:{}", newUser);
39        return newUser;
40    }
41
42}

(3)、文档查询

  1import lombok.extern.slf4j.Slf4j;
  2import mydlq.club.example.entity.User;
  3import org.springframework.data.domain.Sort;
  4import org.springframework.data.mongodb.core.MongoTemplate;
  5import org.springframework.data.mongodb.core.query.Criteria;
  6import org.springframework.data.mongodb.core.query.Query;
  7import org.springframework.stereotype.Service;
  8import javax.annotation.Resource;
  9import java.util.Arrays;
 10import java.util.List;
 11
 12@Slf4j
 13@Service
 14public class QueryService {
 15
 16    /**
 17     * 设置集合名称
 18     */
 19    private static final String COLLECTION_NAME = "users";
 20
 21    @Resource
 22    private MongoTemplate mongoTemplate;
 23
 24    /**
 25     * 查询集合中的【全部】文档数据
 26     *
 27     * @return 全部文档列表
 28     */
 29    public Object findAll() {
 30        // 执行查询集合中全部文档信息
 31        List<User> documentList = mongoTemplate.findAll(User.class, COLLECTION_NAME);
 32        // 输出结果
 33        for (User user : documentList) {
 34            log.info("用户信息:{}", user);
 35        }
 36        return documentList;
 37    }
 38
 39    /**
 40     * 根据【文档ID】查询集合中文档数据
 41     *
 42     * @return 文档信息
 43     */
 44    public Object findById() {
 45        // 设置查询的文档 ID
 46        String id = "1";
 47        // 根据文档ID查询集合中文档数据,并转换为对应 Java 对象
 48        User user = mongoTemplate.findById(id, User.class, COLLECTION_NAME);
 49        // 输出结果
 50        log.info("用户信息:{}", user);
 51        return user;
 52    }
 53
 54    /**
 55     * 根据【条件】查询集合中【符合条件】的文档,只取【第一条】数据
 56     *
 57     * @return 符合条件的第一条文档
 58     */
 59    public Object findOne() {
 60        // 设置查询条件参数
 61        int age = 22;
 62        // 创建条件对象
 63        Criteria criteria = Criteria.where("age").is(age);
 64        // 创建查询对象,然后将条件对象添加到其中
 65        Query query = new Query(criteria);
 66        // 查询一条文档,如果查询结果中有多条文档,那么就取第一条
 67        User user = mongoTemplate.findOne(query, User.class, COLLECTION_NAME);
 68        // 输出结果
 69        log.info("用户信息:{}", user);
 70        return user;
 71    }
 72
 73    /**
 74     * 根据【条件】查询集合中【符合条件】的文档,获取其【文档列表】
 75     *
 76     * @return 符合条件的文档列表
 77     */
 78    public Object findByCondition() {
 79        // 设置查询条件参数
 80        String sex = "女";
 81        // 创建条件对象
 82        Criteria criteria = Criteria.where("sex").is(sex);
 83        // 创建查询对象,然后将条件对象添加到其中
 84        Query query = new Query(criteria);
 85        // 查询并返回结果
 86        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
 87        // 输出结果
 88        for (User user : documentList) {
 89            log.info("用户信息:{}", user);
 90        }
 91        return documentList;
 92    }
 93
 94    /**
 95     * 根据【条件】查询集合中【符合条件】的文档,获取其【文档列表】并【排序】
 96     *
 97     * @return 符合条件的文档列表
 98     */
 99    public Object findByConditionAndSort() {
100        // 设置查询条件参数
101        String sex = "男";
102        String sort = "age";
103        // 创建条件对象
104        Criteria criteria = Criteria.where("sex").is(sex);
105        // 创建查询对象,然后将条件对象添加到其中,然后根据指定字段进行排序
106        Query query = new Query(criteria).with(Sort.by(sort));
107        // 执行查询
108        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
109        // 输出结果
110        for (User user : documentList) {
111            log.info("用户信息:{}", user);
112        }
113        return documentList;
114    }
115
116    /**
117     * 根据【单个条件】查询集合中的文档数据,并【按指定字段进行排序】与【限制指定数目】
118     *
119     * @return 符合条件的文档列表
120     */
121    public Object findByConditionAndSortLimit() {
122        // 设置查询条件参数
123        String sex = "男";
124        String sort = "age";
125        int limit = 2;
126        // 创建条件对象
127        Criteria criteria = Criteria.where("sex").is(sex);
128        // 创建查询对象,然后将条件对象添加到其中
129        Query query = new Query(criteria).with(Sort.by(sort)).limit(limit);
130        // 执行查询
131        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
132        // 输出结果
133        for (User user : documentList) {
134            log.info("用户信息:{}", user);
135        }
136        return documentList;
137    }
138
139    /**
140     * 根据【单个条件】查询集合中的文档数据,并【按指定字段进行排序】与【并跳过指定数目】
141     *
142     * @return 符合条件的文档列表
143     */
144    public Object findByConditionAndSortSkip() {
145        // 设置查询条件参数
146        String sex = "男";
147        String sort = "age";
148        int skip = 1;
149        // 创建条件对象
150        Criteria criteria = Criteria.where("sex").is(sex);
151        // 创建查询对象,然后将条件对象添加到其中
152        Query query = new Query(criteria).with(Sort.by(sort)).skip(skip);
153        // 查询并返回结果
154        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
155        // 输出结果
156        for (User user : documentList) {
157            log.info("用户信息:{}", user);
158        }
159        return documentList;
160    }
161
162    /**
163     * 查询【存在指定字段名称】的文档数据
164     *
165     * @return 符合条件的文档列表
166     */
167    public Object findByExistsField() {
168        // 设置查询条件参数
169        String field = "sex";
170        // 创建条件
171        Criteria criteria = Criteria.where(field).exists(true);
172        // 创建查询对象,然后将条件对象添加到其中
173        Query query = new Query(criteria);
174        // 查询并返回结果
175        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
176        // 输出结果
177        for (User user : documentList) {
178            log.info("用户信息:{}", user);
179        }
180        return documentList;
181    }
182
183    /**
184     * 根据【AND】关联多个查询条件,查询集合中的文档数据
185     *
186     * @return 符合条件的文档列表
187     */
188    public Object findByAndCondition() {
189        // 设置查询条件参数
190        String sex = "男";
191        Integer age = 22;
192        // 创建条件
193        Criteria criteriaSex = Criteria.where("sex").is(sex);
194        Criteria criteriaAge = Criteria.where("age").is(age);
195        // 创建条件对象,将上面条件进行 AND 关联
196        Criteria criteria = new Criteria().andOperator(criteriaSex, criteriaAge);
197        // 创建查询对象,然后将条件对象添加到其中
198        Query query = new Query(criteria);
199        // 查询并返回结果
200        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
201        // 输出结果
202        for (User user : documentList) {
203            log.info("用户信息:{}", user);
204        }
205        return documentList;
206    }
207
208    /**
209     * 根据【OR】关联多个查询条件,查询集合中的文档数据
210     *
211     * @return 符合条件的文档列表
212     */
213    public Object findByOrCondition() {
214        // 设置查询条件参数
215        String sex = "男";
216        int age = 22;
217        // 创建条件
218        Criteria criteriaSex = Criteria.where("sex").is(sex);
219        Criteria criteriaAge = Criteria.where("age").is(age);
220        // 创建条件对象,将上面条件进行 OR 关联
221        Criteria criteria = new Criteria().orOperator(criteriaSex, criteriaAge);
222        // 创建查询对象,然后将条件对象添加到其中
223        Query query = new Query(criteria);
224        // 查询并返回结果
225        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
226        // 输出结果
227        for (User user : documentList) {
228            log.info("用户信息:{}", user);
229        }
230        return documentList;
231    }
232
233    /**
234     * 根据【IN】关联多个查询条件,查询集合中的文档数据
235     *
236     * @return 符合条件的文档列表
237     */
238    public Object findByInCondition() {
239        // 设置查询条件参数
240        Integer[] ages = {20, 22, 25};
241        // 创建条件
242        List<Integer> ageList = Arrays.asList(ages);
243        // 创建条件对象
244        Criteria criteria = Criteria.where("age").in(ageList);
245        // 创建查询对象,然后将条件对象添加到其中
246        Query query = new Query(criteria);
247        // 查询并返回结果
248        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
249        // 输出结果
250        for (User user : documentList) {
251            log.info("用户信息:{}", user);
252        }
253        return documentList;
254    }
255
256    /**
257     * 根据【逻辑运算符】查询集合中的文档数据
258     *
259     * @return 符合条件的文档列表
260     */
261    public Object findByOperator() {
262        // 设置查询条件参数
263        int min = 25;
264        int max = 35;
265        // 创建条件对象
266        Criteria criteria = Criteria.where("age").gt(min).lte(max);
267        // 创建查询对象,然后将条件对象添加到其中
268        Query query = new Query(criteria);
269        // 查询并返回结果
270        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
271        // 输出结果
272        for (User user : documentList) {
273            log.info("用户信息:{}", user);
274        }
275        return documentList;
276    }
277
278    /**
279     * 根据【正则表达式】查询集合中的文档数据
280     *
281     * @return 符合条件的文档列表
282     */
283    public Object findByRegex() {
284        // 设置查询条件参数
285        String regex = "^zh*";
286        // 创建条件对象
287        Criteria criteria = Criteria.where("name").regex(regex);
288        // 创建查询对象,然后将条件对象添加到其中
289        Query query = new Query(criteria);
290        // 查询并返回结果
291        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
292        // 输出结果
293        for (User user : documentList) {
294            log.info("用户信息:{}", user);
295        }
296        return documentList;
297    }
298
299    /**
300     * 统计集合中符合【查询条件】的文档【数量】
301     *
302     * @return 符合条件的文档列表
303     */
304    public Object countNumber() {
305        // 设置查询条件参数
306        int age = 22;
307        // 创建条件对象
308        Criteria criteria = Criteria.where("age").is(age);
309        // 创建查询对象,然后将条件对象添加到其中
310        Query query = new Query(criteria);
311        // 查询并返回结果
312        long count = mongoTemplate.count(query, User.class, COLLECTION_NAME);
313        // 输出结果
314        log.info("符合条件的文档数量:{}", count);
315        return count;
316    }
317
318}

(4)、文档更新

 1import com.mongodb.client.result.UpdateResult;
 2import lombok.extern.slf4j.Slf4j;
 3import mydlq.club.example.entity.User;
 4import org.springframework.data.domain.Sort;
 5import org.springframework.data.mongodb.core.MongoTemplate;
 6import org.springframework.data.mongodb.core.query.Criteria;
 7import org.springframework.data.mongodb.core.query.Query;
 8import org.springframework.data.mongodb.core.query.Update;
 9import org.springframework.stereotype.Service;
10import javax.annotation.Resource;
11
12@Slf4j
13@Service
14public class UpdateService {
15
16    /**
17     * 设置集合名称
18     */
19    private static final String COLLECTION_NAME = "users";
20
21    @Resource
22    private MongoTemplate mongoTemplate;
23
24    /**
25     * 更新集合中【匹配】查询到的第一条文档数据,如果没有找到就【创建并插入一个新文档】
26     *
27     * @return 执行更新的结果
28     */
29    public Object update() {
30        // 创建条件对象
31        Criteria criteria = Criteria.where("age").is(30);
32        // 创建查询对象,然后将条件对象添加到其中
33        Query query = new Query(criteria);
34        // 创建更新对象,并设置更新的内容
35        Update update = new Update().set("age", 33).set("name", "zhangsansan");
36        // 执行更新,如果没有找到匹配查询的文档,则创建并插入一个新文档
37        UpdateResult result = mongoTemplate.upsert(query, update, User.class, COLLECTION_NAME);
38        // 输出结果信息
39        String resultInfo = "匹配到" + result.getMatchedCount() + "条数据,对第一条数据进行了更改";
40        log.info("更新结果:{}", resultInfo);
41        return resultInfo;
42    }
43
44    /**
45     * 更新集合中【匹配】查询到的【文档数据集合】中的【第一条数据】
46     *
47     * @return 执行更新的结果
48     */
49    public Object updateFirst() {
50        // 创建条件对象
51        Criteria criteria = Criteria.where("name").is("zhangsan");
52        // 创建查询对象,然后将条件对象添加到其中,并设置排序
53        Query query = new Query(criteria).with(Sort.by("age").ascending());
54        // 创建更新对象,并设置更新的内容
55        Update update = new Update().set("age", 30).set("name", "zhangsansan");
56        // 执行更新
57        UpdateResult result = mongoTemplate.updateFirst(query, update, User.class, COLLECTION_NAME);
58        // 输出结果信息
59        String resultInfo = "共匹配到" + result.getMatchedCount() + "条数据,修改了" + result.getModifiedCount() + "条数据";
60        log.info("更新结果:{}", resultInfo);
61        return resultInfo;
62    }
63
64    /**
65     * 更新【匹配查询】到的【文档数据集合】中的【所有数据】
66     *
67     * @return 执行更新的结果
68     */
69    public Object updateMany() {
70        // 创建条件对象
71        Criteria criteria = Criteria.where("age").gt(28);
72        // 创建查询对象,然后将条件对象添加到其中
73        Query query = new Query(criteria);
74        // 设置更新字段和更新的内容
75        Update update = new Update().set("age", 29).set("salary", "1999");
76        // 执行更新
77        UpdateResult result = mongoTemplate.updateMulti(query, update, User.class, COLLECTION_NAME);
78        // 输出结果信息
79        String resultInfo = "总共匹配到" + result.getMatchedCount() + "条数据,修改了" + result.getModifiedCount() + "条数据";
80        log.info("更新结果:{}", resultInfo);
81        return resultInfo;
82    }
83
84}

(5)、文档删除

 1import com.mongodb.client.result.DeleteResult;
 2import lombok.extern.slf4j.Slf4j;
 3import mydlq.club.example.entity.User;
 4import org.springframework.data.mongodb.core.MongoTemplate;
 5import org.springframework.data.mongodb.core.query.Criteria;
 6import org.springframework.data.mongodb.core.query.Query;
 7import org.springframework.stereotype.Service;
 8import javax.annotation.Resource;
 9import java.util.List;
10
11@Slf4j
12@Service
13public class RemoveService {
14
15    /**
16     * 设置集合名称
17     */
18    private static final String COLLECTION_NAME = "users";
19
20    @Resource
21    private MongoTemplate mongoTemplate;
22
23    /**
24     * 删除集合中【符合条件】的【一个]或[多个】文档
25     *
26     * @return 删除用户信息的结果
27     */
28    public Object remove() {
29        // 设置查询条件参数
30        int age = 30;
31        String sex = "男";
32        // 创建条件对象
33        Criteria criteria = Criteria.where("age").is(age).and("sex").is(sex);
34        // 创建查询对象,然后将条件对象添加到其中
35        Query query = new Query(criteria);
36        // 执行删除查找到的匹配的全部文档信息
37        DeleteResult result = mongoTemplate.remove(query, COLLECTION_NAME);
38        // 输出结果信息
39        String resultInfo = "成功删除 " + result.getDeletedCount() + " 条文档信息";
40        log.info(resultInfo);
41        return resultInfo;
42    }
43
44    /**
45     * 删除【符合条件】的【单个文档】,并返回删除的文档。
46     *
47     * @return 删除的用户信息
48     */
49    public Object findAndRemove() {
50        // 设置查询条件参数
51        String name = "zhangsansan";
52        // 创建条件对象
53        Criteria criteria = Criteria.where("name").is(name);
54        // 创建查询对象,然后将条件对象添加到其中
55        Query query = new Query(criteria);
56        // 执行删除查找到的匹配的第一条文档,并返回删除的文档信息
57        User result = mongoTemplate.findAndRemove(query, User.class, COLLECTION_NAME);
58        // 输出结果信息
59        String resultInfo = "成功删除文档信息,文档内容为:" + result;
60        log.info(resultInfo);
61        return result;
62    }
63
64    /**
65     * 删除【符合条件】的【全部文档】,并返回删除的文档。
66     *
67     * @return 删除的全部用户信息
68     */
69    public Object findAllAndRemove() {
70        // 设置查询条件参数
71        int age = 22;
72        // 创建条件对象
73        Criteria criteria = Criteria.where("age").is(age);
74        // 创建查询对象,然后将条件对象添加到其中
75        Query query = new Query(criteria);
76        // 执行删除查找到的匹配的全部文档,并返回删除的全部文档信息
77        List<User> resultList = mongoTemplate.findAllAndRemove(query, User.class, COLLECTION_NAME);
78        // 输出结果信息
79        String resultInfo = "成功删除文档信息,文档内容为:" + resultList;
80        log.info(resultInfo);
81        return resultList;
82    }
83
84}

8、MongoDB 聚合操作

(1)、聚合表达式

  1import lombok.extern.slf4j.Slf4j;
  2import org.springframework.data.domain.Sort;
  3import org.springframework.data.mongodb.core.MongoTemplate;
  4import org.springframework.data.mongodb.core.aggregation.Aggregation;
  5import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
  6import org.springframework.data.mongodb.core.aggregation.AggregationResults;
  7import org.springframework.stereotype.Service;
  8import javax.annotation.Resource;
  9import java.util.Map;
 10
 11/**
 12 * 聚合表达式 $group
 13 *
 14 * @author mydlq
 15 */
 16@Slf4j
 17@Service
 18public class AggregateGroupService {
 19
 20    /**
 21     * 设置集合名称
 22     */
 23    private static final String COLLECTION_NAME = "users";
 24
 25    @Resource
 26    private MongoTemplate mongoTemplate;
 27
 28    /**
 29     * 使用管道操作符 $group 结合 $count 方法进行聚合统计
 30     *
 31     * @return 聚合结果
 32     */
 33    public Object aggregationGroupCount() {
 34        // 使用管道操作符 $group 进行分组,然后统计各个组的文档数量
 35        AggregationOperation group = Aggregation.group("age").count().as("numCount");
 36        // 将操作加入到聚合对象中
 37        Aggregation aggregation = Aggregation.newAggregation(group);
 38        // 执行聚合查询
 39        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
 40        for (Map result : results.getMappedResults()) {
 41            log.info("{}", result);
 42        }
 43        return results.getMappedResults();
 44    }
 45
 46    /**
 47     * 使用管道操作符 $group 结合表达式操作符 $max 进行聚合统计
 48     *
 49     * @return 聚合结果
 50     */
 51    public Object aggregationGroupMax() {
 52        // 使用管道操作符 $group 进行分组,然后统计各个组文档某字段最大值
 53        AggregationOperation group = Aggregation.group("sex").max("salary").as("salaryMax");
 54        // 将操作加入到聚合对象中
 55        Aggregation aggregation = Aggregation.newAggregation(group);
 56        // 执行聚合查询
 57        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
 58        for (Map result : results.getMappedResults()) {
 59            log.info("{}", result);
 60        }
 61        return results.getMappedResults();
 62    }
 63
 64    /**
 65     * 使用管道操作符 $group 结合表达式操作符 $min 进行聚合统计
 66     *
 67     * @return 聚合结果
 68     */
 69    public Object aggregationGroupMin() {
 70        // 使用管道操作符 $group 进行分组,然后统计各个组文档某字段最小值
 71        AggregationOperation group = Aggregation.group("sex").min("salary").as("salaryMin");
 72        // 将操作加入到聚合对象中
 73        Aggregation aggregation = Aggregation.newAggregation(group);
 74        // 执行聚合查询
 75        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
 76        for (Map result : results.getMappedResults()) {
 77            log.info("{}", result);
 78        }
 79        return results.getMappedResults();
 80    }
 81
 82    /**
 83     * 使用管道操作符 $group 结合表达式操作符 $sum 进行聚合统计
 84     *
 85     * @return 聚合结果
 86     */
 87    public Object aggregationGroupSum() {
 88        // 使用管道操作符 $group 进行分组,然后统计各个组文档某字段值合计
 89        AggregationOperation group = Aggregation.group("sex").sum("salary").as("salarySum");
 90        // 将操作加入到聚合对象中
 91        Aggregation aggregation = Aggregation.newAggregation(group);
 92        // 执行聚合查询
 93        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
 94        for (Map result : results.getMappedResults()) {
 95            log.info("{}", result);
 96        }
 97        return results.getMappedResults();
 98    }
 99
100    /**
101     * 使用管道操作符 $group 结合表达式操作符 $avg 进行聚合统计
102     *
103     * @return 聚合结果
104     */
105    public Object aggregationGroupAvg() {
106        // 使用管道操作符 $group 进行分组,然后统计各个组文档某字段值平均值
107        AggregationOperation group = Aggregation.group("sex").avg("salary").as("salaryAvg");
108        // 将操作加入到聚合对象中
109        Aggregation aggregation = Aggregation.newAggregation(group);
110        // 执行聚合查询
111        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
112        for (Map result : results.getMappedResults()) {
113            log.info("{}", result);
114        }
115        return results.getMappedResults();
116    }
117
118    /**
119     * 使用管道操作符 $group 结合表达式操作符 $first 获取每个组的包含某字段的文档的第一条数据
120     *
121     * @return 聚合结果
122     */
123    public Object aggregationGroupFirst() {
124        // 先对数据进行排序,然后使用管道操作符 $group 进行分组,最后统计各个组文档某字段值第一个值
125        AggregationOperation sort = Aggregation.sort(Sort.by("salary").ascending());
126        AggregationOperation group = Aggregation.group("sex").first("salary").as("salaryFirst");
127        // 将操作加入到聚合对象中
128        Aggregation aggregation = Aggregation.newAggregation(sort, group);
129        // 执行聚合查询
130        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
131        for (Map result : results.getMappedResults()) {
132            log.info("{}", result);
133        }
134        return results.getMappedResults();
135    }
136
137    /**
138     * 使用管道操作符 $group 结合表达式操作符 $last 获取每个组的包含某字段的文档的最后一条数据
139     *
140     * @return 聚合结果
141     */
142    public Object aggregationGroupLast() {
143        // 先对数据进行排序,然后使用管道操作符 $group 进行分组,最后统计各个组文档某字段值第最后一个值
144        AggregationOperation sort = Aggregation.sort(Sort.by("salary").ascending());
145        AggregationOperation group = Aggregation.group("sex").last("salary").as("salaryLast");
146        // 将操作加入到聚合对象中
147        Aggregation aggregation = Aggregation.newAggregation(sort, group);
148        // 执行聚合查询
149        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
150        for (Map result : results.getMappedResults()) {
151            log.info("{}", result);
152        }
153        return results.getMappedResults();
154    }
155
156    /**
157     * 使用管道操作符 $group 结合表达式操作符 $push 获取某字段列表
158     *
159     * @return 聚合结果
160     */
161    public Object aggregationGroupPush() {
162        // 先对数据进行排序,然后使用管道操作符 $group 进行分组,然后以数组形式列出某字段的全部值
163        AggregationOperation push = Aggregation.group("sex").push("salary").as("salaryFirst");
164        // 将操作加入到聚合对象中
165        Aggregation aggregation = Aggregation.newAggregation(push);
166        // 执行聚合查询
167        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
168        for (Map result : results.getMappedResults()) {
169            log.info("{}", result);
170        }
171        return results.getMappedResults();
172    }
173
174}

(2)、聚合管道操作符

  1import lombok.extern.slf4j.Slf4j;
  2import org.springframework.data.domain.Sort;
  3import org.springframework.data.mongodb.core.MongoTemplate;
  4import org.springframework.data.mongodb.core.aggregation.Aggregation;
  5import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
  6import org.springframework.data.mongodb.core.aggregation.AggregationResults;
  7import org.springframework.data.mongodb.core.query.Criteria;
  8import org.springframework.stereotype.Service;
  9import javax.annotation.Resource;
 10import java.util.Map;
 11
 12@Slf4j
 13@Service
 14public class AggregatePipelineService {
 15
 16    /**
 17     * 设置集合名称
 18     */
 19    private static final String COLLECTION_NAME = "users";
 20
 21    @Resource
 22    private MongoTemplate mongoTemplate;
 23
 24    /**
 25     * 使用 $group 和 $match 聚合,先使用 $match 过滤文档,然后再使用 $group 进行分组
 26     *
 27     * @return 聚合结果
 28     */
 29    public Object aggregateGroupMatch() {
 30        // 设置聚合条件,先使用 $match 过滤岁数大于 25 的用户,然后按性别分组,统计每组用户工资最高值
 31        AggregationOperation match = Aggregation.match(Criteria.where("age").lt(25));
 32        AggregationOperation group = Aggregation.group("sex").max("salary").as("sexSalary");
 33        // 将操作加入到聚合对象中
 34        Aggregation aggregation = Aggregation.newAggregation(match, group);
 35        // 执行聚合查询
 36        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
 37        for (Map result : results.getMappedResults()) {
 38            log.info("{}", result);
 39        }
 40        return results.getMappedResults();
 41    }
 42
 43    /**
 44     * 使用 $group 和 $sort 聚合,先使用 $group 进行分组,然后再使用 $sort 排序
 45     *
 46     * @return 聚合结果
 47     */
 48    public Object aggregateGroupSort() {
 49        // 设置聚合条件,按岁数分组,然后统计每组用户工资最大值和用户数,按每组用户工资最大值升序排序
 50        AggregationOperation group = Aggregation.group("age")
 51                .max("salary").as("ageSalary")
 52                .count().as("ageCount");
 53        AggregationOperation sort = Aggregation.sort(Sort.by("ageSalary").ascending());
 54        // 将操作加入到聚合对象中
 55        Aggregation aggregation = Aggregation.newAggregation(group, sort);
 56        // 执行聚合查询
 57        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
 58        for (Map result : results.getMappedResults()) {
 59            log.info("{}", result);
 60        }
 61        return results.getMappedResults();
 62    }
 63
 64    /**
 65     * 使用 $group 和 $limit 聚合,先使用 $group 进行分组,然后再使用 $limit 限制一定数目文档
 66     *
 67     * @return 聚合结果
 68     */
 69    public Object aggregateGroupLimit() {
 70        // 设置聚合条件,先按岁数分组,然后求每组用户的工资总数、最大值、最小值、平均值,限制只能显示五条
 71        AggregationOperation group = Aggregation.group("age")
 72                .sum("salary").as("sumSalary")
 73                .max("salary").as("maxSalary")
 74                .min("salary").as("minSalary")
 75                .avg("salary").as("avgSalary");
 76        AggregationOperation limit = Aggregation.limit(5L);
 77        // 将操作加入到聚合对象中
 78        Aggregation aggregation = Aggregation.newAggregation(group, limit);
 79        // 执行聚合查询
 80        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
 81        for (Map result : results.getMappedResults()) {
 82            log.info("{}", result);
 83        }
 84        return results.getMappedResults();
 85    }
 86
 87    /**
 88     * 使用 $group 和 $skip 聚合,先使用 $group 进行分组,然后再使用 $skip 跳过一定数目文档
 89     *
 90     * @return 聚合结果
 91     */
 92    public Object aggregateGroupSkip() {
 93        // 设置聚合条件,先按岁数分组,然后求每组用户的工资总数、最大值、最小值、平均值,跳过前 2 条
 94        AggregationOperation group = Aggregation.group("age")
 95                .sum("salary").as("sumSalary")
 96                .max("salary").as("maxSalary")
 97                .min("salary").as("minSalary")
 98                .avg("salary").as("avgSalary");
 99        AggregationOperation limit = Aggregation.skip(2L);
100        // 将操作加入到聚合对象中
101        Aggregation aggregation = Aggregation.newAggregation(group, limit);
102        // 执行聚合查询
103        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
104        for (Map result : results.getMappedResults()) {
105            log.info("{}", result);
106        }
107        return results.getMappedResults();
108    }
109
110    /**
111     * 使用 $group 和 $project 聚合,先使用 $group 进行分组,然后再使用 $project 限制显示的字段
112     *
113     * @return 聚合结果
114     */
115    public Object aggregateGroupProject() {
116        // 设置聚合条件,按岁数分组,然后求每组用户工资最大值、最小值,然后使用 $project 限制值显示 salaryMax 字段
117        AggregationOperation group = Aggregation.group("age")
118                .max("salary").as("maxSalary")
119                .min("salary").as("minSalary");
120        AggregationOperation project = Aggregation.project("maxSalary");
121        // 将操作加入到聚合对象中
122        Aggregation aggregation = Aggregation.newAggregation(group, project);
123        // 执行聚合查询
124        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
125        for (Map result : results.getMappedResults()) {
126            log.info("{}", result);
127        }
128        return results.getMappedResults();
129    }
130
131    /**
132     * 使用 $group 和 $unwind 聚合,先使用 $project 进行分组,然后再使用 $unwind 拆分文档中的数组为一条新文档记录
133     *
134     * @return 聚合结果
135     */
136    public Object aggregateProjectUnwind() {
137        // 设置聚合条件,设置显示`name`、`age`、`title`字段,然后将结果中的多条文档按 title 字段进行拆分
138        AggregationOperation project = Aggregation.project("name", "age", "title");
139        AggregationOperation unwind = Aggregation.unwind("title");
140        // 将操作加入到聚合对象中
141        Aggregation aggregation = Aggregation.newAggregation(project, unwind);
142        // 执行聚合查询
143        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
144        for (Map result : results.getMappedResults()) {
145            log.info("{}", result);
146        }
147        return results.getMappedResults();
148    }
149
150}

聚合管道操作符:

  • $project: 可以从文档中选择想要的字段,和不想要的字段(指定的字段可以是来自输入文档或新计算字段的现有字段 ,也可以通过管道表达式进行一些复杂的操作,例如数学操作,日期操作,字符串操作,逻辑操作。
  • $match: 用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
  • $limit: 用来限制MongoDB聚合管道返回的文档数。
  • $skip: 在聚合管道中跳过指定数量的文档,并返回余下的文档。
  • $unwind: 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  • $group: 将集合中的文档分组,可用于统计结果。
  • $sort: 将输入文档排序后输出。

9、MongoDB 索引操作

(1)、创建索引

  1import com.mongodb.client.model.Filters;
  2import com.mongodb.client.model.IndexOptions;
  3import com.mongodb.client.model.Indexes;
  4import lombok.extern.slf4j.Slf4j;
  5import org.springframework.data.mongodb.core.MongoTemplate;
  6import org.springframework.stereotype.Service;
  7import javax.annotation.Resource;
  8
  9@Slf4j
 10@Service
 11public class CreateIndexService {
 12
 13    /** 设置集合名称 */
 14    private static final String COLLECTION_NAME = "users";
 15
 16    @Resource
 17    private MongoTemplate mongoTemplate;
 18
 19    /**
 20     * 创建升序索引
 21     *
 22     * @return 索引信息
 23     */
 24    public Object createAscendingIndex() {
 25        // 设置字段名称
 26        String field = "name";
 27        // 创建索引
 28        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field));
 29    }
 30
 31    /**
 32     * 创建降序索引
 33     *
 34     * @return 索引信息
 35     */
 36    public Object createDescendingIndex() {
 37        // 设置字段名称
 38        String field = "name";
 39        // 创建索引
 40        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.descending(field));
 41    }
 42
 43    /**
 44     * 创建升序复合索引
 45     *
 46     * @return 索引信息
 47     */
 48    public Object createCompositeIndex() {
 49        // 设置字段名称
 50        String field1 = "name";
 51        String field2 = "age";
 52        // 创建索引
 53        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field1, field2));
 54    }
 55
 56    /**
 57     * 创建文字索引
 58     *
 59     * @return 索引信息
 60     */
 61    public Object createTextIndex() {
 62        // 设置字段名称
 63        String field = "name";
 64        // 创建索引
 65        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.text(field));
 66    }
 67
 68    /**
 69     * 创建哈希索引
 70     *
 71     * @return 索引信息
 72     */
 73    public Object createHashIndex() {
 74        // 设置字段名称
 75        String field = "name";
 76        // 创建索引
 77        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.hashed(field));
 78    }
 79
 80    /**
 81     * 创建升序唯一索引
 82     *
 83     * @return 索引信息
 84     */
 85    public Object createUniqueIndex() {
 86        // 设置字段名称
 87        String indexName = "name";
 88        // 配置索引选项
 89        IndexOptions options = new IndexOptions();
 90        // 设置为唯一索引
 91        options.unique(true);
 92        // 创建索引
 93        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(indexName), options);
 94    }
 95
 96    /**
 97     * 创建局部索引
 98     *
 99     * @return 索引信息
100     */
101    public Object createPartialIndex() {
102        // 设置字段名称
103        String field = "name";
104        // 配置索引选项
105        IndexOptions options = new IndexOptions();
106        // 设置过滤条件
107        options.partialFilterExpression(Filters.exists("name", true));
108        // 创建索引
109        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field), options);
110    }
111
112}

(2)、查询索引

 1import com.mongodb.client.ListIndexesIterable;
 2import lombok.extern.slf4j.Slf4j;
 3import org.bson.Document;
 4import org.springframework.data.mongodb.core.MongoTemplate;
 5import org.springframework.stereotype.Service;
 6import javax.annotation.Resource;
 7import java.util.ArrayList;
 8import java.util.List;
 9
10/**
11 * 查询索引操作
12 *
13 * @author mydlq
14 */
15@Slf4j
16@Service
17public class QueryIndexService {
18
19    /** 设置集合名称 */
20    private static final String COLLECTION_NAME = "users";
21
22    @Resource
23    private MongoTemplate mongoTemplate;
24
25    /**
26     * 获取当前【集合】对应的【所有索引】的【名称列表】
27     *
28     * @return 当前【集合】所有【索引名称列表】
29     */
30    public Object getIndexAll() {
31        // 获取集合中所有列表
32        ListIndexesIterable<Document> indexList = mongoTemplate.getCollection(COLLECTION_NAME).listIndexes();
33        // 创建字符串集合
34        List<Document> list = new ArrayList<>();
35        // 获取集合中全部索引信息
36        for (Document document : indexList) {
37            log.info("索引列表:{}",document);
38            list.add(document);
39        }
40        return list;
41    }
42
43}

(3)、删除索引

 1import lombok.extern.slf4j.Slf4j;
 2import org.springframework.data.mongodb.core.MongoTemplate;
 3import org.springframework.stereotype.Service;
 4import javax.annotation.Resource;
 5
 6@Slf4j
 7@Service
 8public class RemoveIndexService {
 9
10    @Resource
11    private MongoTemplate mongoTemplate;
12
13    /** 设置集合名称 */
14    private static final String COLLECTION_NAME = "users";
15
16    /**
17     * 根据索引名称移除索引
18     */
19    public void removeIndex() {
20        // 设置索引名称
21        String indexName = "name_1";
22        // 删除集合中某个索引
23        mongoTemplate.getCollection(COLLECTION_NAME).dropIndex(indexName);
24    }
25
26    /**
27     * 移除全部索引
28     */
29    public void removeIndexAll() {
30        // 删除集合中全部索引
31        mongoTemplate.getCollection(COLLECTION_NAME).dropIndexes();
32    }
33
34}

10、MongoDB RunCommand 命令操作

(1)、RunCommand 命令

 1import org.bson.Document;
 2import org.bson.conversions.Bson;
 3import org.springframework.data.mongodb.core.MongoTemplate;
 4import org.springframework.stereotype.Service;
 5import javax.annotation.Resource;
 6
 7@Service
 8public class RunCommandService {
 9
10    @Resource
11    private MongoTemplate mongoTemplate;
12
13    /**
14     * 执行 mongoDB 自定义命令,详情可以查看:https://docs.mongodb.com/manual/reference/command/
15     *
16     * @return 执行命令返回结果的 Json 结果
17     * @description 执行自定义 mongoDB 命令
18     */
19    public Object runCommand() {
20        // 自定义命令
21        String jsonCommand = "{\"buildInfo\":1}";
22        // 将 JSON 字符串解析成 MongoDB 命令
23        Bson bson = Document.parse(jsonCommand);
24        // 执行自定义命令
25        return mongoTemplate.getDb().runCommand(bson);
26    }
27
28}

五、SpringBoot 引入 MongoDB 中的事务

注意:单节点 mongodb 不支持事务,需要搭建 MongoDB 复制集。

1、配置事务管理器

 1import org.springframework.context.annotation.Bean;
 2import org.springframework.context.annotation.Configuration;
 3import org.springframework.data.mongodb.MongoDatabaseFactory;
 4import org.springframework.data.mongodb.MongoTransactionManager;
 5
 6/**
 7 * 配置事务管理器
 8 *
 9 * @author mydlq
10 */
11@Configuration
12public class TransactionConfig {
13
14    @Bean
15    MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
16        return new MongoTransactionManager(dbFactory);
17    }
18
19}

2、创建事务测试服务

 1import mydlq.club.example.entity.Status;
 2import mydlq.club.example.entity.User;
 3import org.springframework.data.mongodb.core.MongoTemplate;
 4import org.springframework.stereotype.Service;
 5import org.springframework.transaction.annotation.Transactional;
 6import javax.annotation.Resource;
 7import java.util.Date;
 8
 9@Service
10public class TransactionExample {
11
12    /** 设置集合名称 */
13    private static final String COLLECTION_NAME = "users";
14
15    @Resource
16    private MongoTemplate mongoTemplate;
17
18    @Transactional(rollbackFor = Exception.class)
19    public Object transactionTest(){
20        // 设置两个用户信息
21        User user1 = new User()
22                .setId("11")
23                .setAge(22)
24                .setSex("男")
25                .setRemake("无")
26                .setSalary(1500)
27                .setName("shiyi")
28                .setBirthday(new Date())
29                .setStatus(new Status().setHeight(180).setWeight(150));
30        // 插入数据
31        User newUser1 = mongoTemplate.insert(user1, COLLECTION_NAME);
32        // 抛出异常,观察数据是否进行回滚
33        int error = 1/0;
34        return newUser1;
35    }
36
37}

如果对你有帮助,别忘了点颗星嘞~

---END---


  !版权声明:本博客内容均为原创,每篇博文作为知识积累,写博不易,转载请注明出处。