SpringBoot 整合 Spring Data Mongodb 操作 MongoDB 詳解

zhaozhangxiao發表於2021-08-30

引用:www.mydlq.club/article/85/

一、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 相關依賴元件:

<?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.0.RELEASE</version>
    </parent>

    <groupId>mydlq.club</groupId>
    <artifactId>springboot-mongodb-template-example</artifactId>
    <version>0.0.1</version>
    <name>springboot-mongodb-template-example</name>
    <description>Demo project for Spring Boot MongoDB</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- SpringBoot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- SpringBoot MongoDB -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

xml

依賴說明:

  • 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 的配置引數,內容如下:

spring:
  data:
    mongodb:
      host: 127.0.0.1
      port: 27017
      database: test
      username: admin
      password: 123456

yaml

引數介紹:

  • 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

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.springframework.data.mongodb.core.mapping.MongoId;
import java.util.Date;

@Data
@ToString
@Accessors(chain = true)
public class User {

    /**
     * 使用 @MongoID 能更清晰的指定 _id 主鍵
     */
    @MongoId
    private String id;
    private String name;
    private String sex;
    private Integer salary;
    private Integer age;
    @JsonFormat( pattern ="yyyy-MM-dd", timezone ="GMT+8")
    private Date birthday;
    private String remake;
    private Status status;

}

java

使用 Lombok 中的 @Accessors(chain = true) 註解,能讓我們方便使用鏈式方法建立實體物件。

Status.java

import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;

@Data
@ToString
@Accessors(chain = true)
public class Status {

    private Integer weight;
    private Integer height;

}

java

4、SpringBoot 啟動類

建立 SpringBoot 啟動類,方便測試:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@EnableSwagger2
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

java

5、MongoDB 集合操作

(1)、建立集合

示例程式碼如下:

import org.springframework.data.mongodb.core.CollectionOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.validation.Validator;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class CreateCollectionService {

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 建立【集合】
     * 
     * 建立一個大小沒有限制的集合(預設集合建立方式) 
     * 
     * @return 建立集合的結果
     */
    public Object createCollection() {
        // 設定集合名稱
        String collectionName = "users1";
        // 建立集合並返回集合資訊
        mongoTemplate.createCollection(collectionName);
        // 檢測新的集合是否存在,返回建立結果
        return mongoTemplate.collectionExists(collectionName) ? "建立檢視成功" : "建立檢視失敗";
    }

    /**
     * 建立【固定大小集合】
     * 
     * 建立集合並設定 `capped=true` 建立 `固定大小集合`,可以配置引數 `size` 限制文件大小,可以配置引數 `max` 限制集合文件數量。
     *
     * @return 建立集合的結果
     */
    public Object createCollectionFixedSize() {
        // 設定集合名稱
        String collectionName = "users2";
        // 設定集合引數
        long size = 1024L;
        long max = 5L;
        // 建立固定大小集合
        CollectionOptions collectionOptions = CollectionOptions.empty()
                // 建立固定集合。固定集合是指有著固定大小的集合,當達到最大值時,它會自動覆蓋最早的文件。
                .capped()
                // 固定集合指定一個最大值,以千位元組計(KB),如果 capped 為 true,也需要指定該欄位。
                .size(size)
                // 指定固定集合中包含文件的最大數量。
                .maxDocuments(max);
        // 執行建立集合
        mongoTemplate.createCollection(collectionName, collectionOptions);
        // 檢測新的集合是否存在,返回建立結果
        return mongoTemplate.collectionExists(collectionName) ? "建立檢視成功" : "建立檢視失敗";
    }

    /**
     * 建立【驗證文件資料】的集合
     *
     * 建立集合並在文件"插入"與"更新"時進行資料效驗,如果符合建立集合設定的條件就進允許更新與插入,否則則按照設定的設定的策略進行處理。
     *
     * * 效驗級別:
     *   - off:關閉資料校驗。
     *   - strict:(預設值) 對所有的文件"插入"與"更新"操作有效。
     *   - moderate:僅對"插入"和滿足校驗規則的"文件"做"更新"操作有效。對已存在的不符合校驗規則的"文件"無效。 
     * * 執行策略:
     *   - error:(預設值) 文件必須滿足校驗規則,才能被寫入。
     *   - warn:對於"文件"不符合校驗規則的 MongoDB 允許寫入,但會記錄一條告警到 mongod.log 中去。日誌內容記錄報錯資訊以及該"文件"的完整記錄。
     * 
     * @return 建立集合結果
     */
    public Object createCollectionValidation() {
        // 設定集合名稱
        String collectionName = "users3";
        // 設定驗證條件,只允許歲數大於20的使用者資訊插入
        CriteriaDefinition criteria = Criteria.where("age").gt(20);
        // 設定集合選項驗證物件
        CollectionOptions collectionOptions = CollectionOptions.empty()
                .validator(Validator.criteria(criteria))
                // 設定效驗級別
                .strictValidation()
                // 設定效驗不通過後執行的動作
                .failOnValidationError();
        // 執行建立集合
        mongoTemplate.createCollection(collectionName, collectionOptions);
        // 檢測新的集合是否存在,返回建立結果
        return mongoTemplate.collectionExists(collectionName) ? "建立集合成功" : "建立集合失敗";
    }

}

java

(2)、查詢集合

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class QueryCollectionService {

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 獲取【集合名稱】列表
     *
     * @return 集合名稱列表
     */
    public Object getCollectionNames() {
        // 執行獲取集合名稱列表
        return mongoTemplate.getCollectionNames();
    }

    /**
     * 檢測集合【是否存在】
     *
     * @return 集合是否存在
     */
    public boolean collectionExists() {
        // 設定集合名稱
        String collectionName = "users";
        // 檢測新的集合是否存在,返回檢測結果
        return mongoTemplate.collectionExists(collectionName);
    }

}

java

(3)、刪除集合

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class RemoveCollectionService {

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 刪除【集合】
     *
     * @return 建立集合結果
     */
    public Object dropCollection() {
        // 設定集合名稱
        String collectionName = "users3";
        // 執行刪除集合
        mongoTemplate.getCollection(collectionName).drop();
        // 檢測新的集合是否存在,返回刪除結果
        return !mongoTemplate.collectionExists(collectionName) ? "刪除集合成功" : "刪除集合失敗";
    }

}

java

6、MongoDB 檢視操作

import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Service
public class ViewService {

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 建立檢視
     *
     * @return 建立檢視結果
     */
    public Object createView() {
        // 設定檢視名
        String newViewName = "usersView";
        // 設定獲取資料的集合名稱
        String collectionName = "users";
        // 定義檢視的管道,可是設定檢視顯示的內容多個篩選條件
        List<Bson> pipeline = new ArrayList<>();
        // 設定條件,用於篩選集合中的文件資料,只有符合條件的才會對映到檢視中
        pipeline.add(Document.parse("{\"$match\":{\"sex\":\"女\"}}"));
        // 執行建立檢視
        mongoTemplate.getDb().createView(newViewName, collectionName, pipeline);
        // 檢測新的集合是否存在,返回建立結果
        return mongoTemplate.collectionExists(newViewName) ? "建立檢視成功" : "建立檢視失敗";
    }

    /**
     * 刪除檢視
     *
     * @return 刪除檢視結果
     */
    public Object dropView() {
        // 設定待刪除的檢視名稱
        String viewName = "usersView";
        // 檢測檢視是否存在
        if (mongoTemplate.collectionExists(viewName)) {
            // 刪除檢視
            mongoTemplate.getDb().getCollection(viewName).drop();
            return "刪除檢視成功";
        }
        // 檢測新的集合是否存在,返回建立結果
        return !mongoTemplate.collectionExists(viewName) ? "刪除檢視成功" : "刪除檢視失敗";
    }

}

java

7、MongoDB 文件操作

(1)、文件插入

import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.Status;
import mydlq.club.example.entity.User;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class InsertService {

    /** 設定集合名稱 */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 插入【一條】文件資料,如果文件資訊已經【存在就丟擲異常】
     *
     * @return 插入的文件資訊
     */
    public Object insert() {
        // 設定使用者資訊
        User user = new User()
                .setId("10")
                .setAge(22)
                .setSex("男")
                .setRemake("無")
                .setSalary(1500)
                .setName("zhangsan")
                .setBirthday(new Date())
                .setStatus(new Status().setHeight(180).setWeight(150));
        // 插入一條使用者資料,如果文件資訊已經存在就丟擲異常
        User newUser = mongoTemplate.insert(user, COLLECTION_NAME);
        // 輸出儲存結果
        log.info("儲存的使用者資訊為:{}", newUser);
        return newUser;
    }

    /**
     * 插入【多條】文件資料,如果文件資訊已經【存在就丟擲異常】
     *
     * @return 插入的多個文件資訊
     *
     */
    public Object insertMany(){
        // 設定兩個使用者資訊
        User user1 = new User()
                .setId("11")
                .setAge(22)
                .setSex("男")
                .setRemake("無")
                .setSalary(1500)
                .setName("shiyi")
                .setBirthday(new Date())
                .setStatus(new Status().setHeight(180).setWeight(150));
        User user2 = new User()
                .setId("12")
                .setAge(22)
                .setSex("男")
                .setRemake("無")
                .setSalary(1500)
                .setName("shier")
                .setBirthday(new Date())
                .setStatus(new Status().setHeight(180).setWeight(150));
        // 使使用者資訊加入結合
        List<User> userList = new ArrayList<>();
        userList.add(user1);
        userList.add(user2);
        // 插入一條使用者資料,如果某個文件資訊已經存在就丟擲異常
        Collection<User> newUserList = mongoTemplate.insert(userList, COLLECTION_NAME);
        // 輸出儲存結果
        for (User user : newUserList) {
            log.info("儲存的使用者資訊為:{}", user);
        }
        return newUserList;
    }

}

java

(2)、文件儲存

import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.Status;
import mydlq.club.example.entity.User;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;

@Slf4j
@Service
public class SaveService {

    /** 設定集合名稱 */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 儲存【一條】使用者資訊,如果文件資訊已經【存在就執行更新】
     *
     * @return 儲存的文件資訊
     */
    public Object save() {
        // 設定使用者資訊
        User user = new User()
                .setId("13")
                .setAge(22)
                .setSex("男")
                .setRemake("無")
                .setSalary(2800)
                .setName("kuiba")
                .setBirthday(new Date())
                .setStatus(new Status().setHeight(169).setWeight(150));
        // 儲存使用者資訊,如果文件資訊已經存在就執行更新
        User newUser = mongoTemplate.save(user, COLLECTION_NAME);
        // 輸出儲存結果
        log.info("儲存的使用者資訊為:{}", newUser);
        return newUser;
    }

}

java

(3)、文件查詢

import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.User;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Service
public class QueryService {

    /**
     * 設定集合名稱
     */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 查詢集合中的【全部】文件資料
     *
     * @return 全部文件列表
     */
    public Object findAll() {
        // 執行查詢集合中全部文件資訊
        List<User> documentList = mongoTemplate.findAll(User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 根據【文件ID】查詢集合中文件資料
     *
     * @return 文件資訊
     */
    public Object findById() {
        // 設定查詢的文件 ID
        String id = "1";
        // 根據文件ID查詢集合中文件資料,並轉換為對應 Java 物件
        User user = mongoTemplate.findById(id, User.class, COLLECTION_NAME);
        // 輸出結果
        log.info("使用者資訊:{}", user);
        return user;
    }

    /**
     * 根據【條件】查詢集合中【符合條件】的文件,只取【第一條】資料
     *
     * @return 符合條件的第一條文件
     */
    public Object findOne() {
        // 設定查詢條件引數
        int age = 22;
        // 建立條件物件
        Criteria criteria = Criteria.where("age").is(age);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 查詢一條文件,如果查詢結果中有多條文件,那麼就取第一條
        User user = mongoTemplate.findOne(query, User.class, COLLECTION_NAME);
        // 輸出結果
        log.info("使用者資訊:{}", user);
        return user;
    }

    /**
     * 根據【條件】查詢集合中【符合條件】的文件,獲取其【文件列表】
     *
     * @return 符合條件的文件列表
     */
    public Object findByCondition() {
        // 設定查詢條件引數
        String sex = "女";
        // 建立條件物件
        Criteria criteria = Criteria.where("sex").is(sex);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 查詢並返回結果
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 根據【條件】查詢集合中【符合條件】的文件,獲取其【文件列表】並【排序】
     *
     * @return 符合條件的文件列表
     */
    public Object findByConditionAndSort() {
        // 設定查詢條件引數
        String sex = "男";
        String sort = "age";
        // 建立條件物件
        Criteria criteria = Criteria.where("sex").is(sex);
        // 建立查詢物件,然後將條件物件新增到其中,然後根據指定欄位進行排序
        Query query = new Query(criteria).with(Sort.by(sort));
        // 執行查詢
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 根據【單個條件】查詢集合中的文件資料,並【按指定欄位進行排序】與【限制指定數目】
     *
     * @return 符合條件的文件列表
     */
    public Object findByConditionAndSortLimit() {
        // 設定查詢條件引數
        String sex = "男";
        String sort = "age";
        int limit = 2;
        // 建立條件物件
        Criteria criteria = Criteria.where("sex").is(sex);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria).with(Sort.by(sort)).limit(limit);
        // 執行查詢
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 根據【單個條件】查詢集合中的文件資料,並【按指定欄位進行排序】與【並跳過指定數目】
     *
     * @return 符合條件的文件列表
     */
    public Object findByConditionAndSortSkip() {
        // 設定查詢條件引數
        String sex = "男";
        String sort = "age";
        int skip = 1;
        // 建立條件物件
        Criteria criteria = Criteria.where("sex").is(sex);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria).with(Sort.by(sort)).skip(skip);
        // 查詢並返回結果
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 查詢【存在指定欄位名稱】的文件資料
     *
     * @return 符合條件的文件列表
     */
    public Object findByExistsField() {
        // 設定查詢條件引數
        String field = "sex";
        // 建立條件
        Criteria criteria = Criteria.where(field).exists(true);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 查詢並返回結果
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 根據【AND】關聯多個查詢條件,查詢集合中的文件資料
     *
     * @return 符合條件的文件列表
     */
    public Object findByAndCondition() {
        // 設定查詢條件引數
        String sex = "男";
        Integer age = 22;
        // 建立條件
        Criteria criteriaSex = Criteria.where("sex").is(sex);
        Criteria criteriaAge = Criteria.where("age").is(age);
        // 建立條件物件,將上面條件進行 AND 關聯
        Criteria criteria = new Criteria().andOperator(criteriaSex, criteriaAge);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 查詢並返回結果
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 根據【OR】關聯多個查詢條件,查詢集合中的文件資料
     *
     * @return 符合條件的文件列表
     */
    public Object findByOrCondition() {
        // 設定查詢條件引數
        String sex = "男";
        int age = 22;
        // 建立條件
        Criteria criteriaSex = Criteria.where("sex").is(sex);
        Criteria criteriaAge = Criteria.where("age").is(age);
        // 建立條件物件,將上面條件進行 OR 關聯
        Criteria criteria = new Criteria().orOperator(criteriaSex, criteriaAge);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 查詢並返回結果
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 根據【IN】關聯多個查詢條件,查詢集合中的文件資料
     *
     * @return 符合條件的文件列表
     */
    public Object findByInCondition() {
        // 設定查詢條件引數
        Integer[] ages = {20, 22, 25};
        // 建立條件
        List<Integer> ageList = Arrays.asList(ages);
        // 建立條件物件
        Criteria criteria = Criteria.where("age").in(ageList);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 查詢並返回結果
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 根據【邏輯運算子】查詢集合中的文件資料
     *
     * @return 符合條件的文件列表
     */
    public Object findByOperator() {
        // 設定查詢條件引數
        int min = 25;
        int max = 35;
        // 建立條件物件
        Criteria criteria = Criteria.where("age").gt(min).lte(max);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 查詢並返回結果
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 根據【正規表示式】查詢集合中的文件資料
     *
     * @return 符合條件的文件列表
     */
    public Object findByRegex() {
        // 設定查詢條件引數
        String regex = "^zh*";
        // 建立條件物件
        Criteria criteria = Criteria.where("name").regex(regex);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 查詢並返回結果
        List<User> documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
        // 輸出結果
        for (User user : documentList) {
            log.info("使用者資訊:{}", user);
        }
        return documentList;
    }

    /**
     * 統計集合中符合【查詢條件】的文件【數量】
     *
     * @return 符合條件的文件列表
     */
    public Object countNumber() {
        // 設定查詢條件引數
        int age = 22;
        // 建立條件物件
        Criteria criteria = Criteria.where("age").is(age);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 查詢並返回結果
        long count = mongoTemplate.count(query, User.class, COLLECTION_NAME);
        // 輸出結果
        log.info("符合條件的文件數量:{}", count);
        return count;
    }

}

java

(4)、文件更新

import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.User;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Slf4j
@Service
public class UpdateService {

    /**
     * 設定集合名稱
     */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 更新集合中【匹配】查詢到的第一條文件資料,如果沒有找到就【建立並插入一個新文件】
     *
     * @return 執行更新的結果
     */
    public Object update() {
        // 建立條件物件
        Criteria criteria = Criteria.where("age").is(30);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 建立更新物件,並設定更新的內容
        Update update = new Update().set("age", 33).set("name", "zhangsansan");
        // 執行更新,如果沒有找到匹配查詢的文件,則建立並插入一個新文件
        UpdateResult result = mongoTemplate.upsert(query, update, User.class, COLLECTION_NAME);
        // 輸出結果資訊
        String resultInfo = "匹配到" + result.getMatchedCount() + "條資料,對第一條資料進行了更改";
        log.info("更新結果:{}", resultInfo);
        return resultInfo;
    }

    /**
     * 更新集合中【匹配】查詢到的【文件資料集合】中的【第一條資料】
     *
     * @return 執行更新的結果
     */
    public Object updateFirst() {
        // 建立條件物件
        Criteria criteria = Criteria.where("name").is("zhangsan");
        // 建立查詢物件,然後將條件物件新增到其中,並設定排序
        Query query = new Query(criteria).with(Sort.by("age").ascending());
        // 建立更新物件,並設定更新的內容
        Update update = new Update().set("age", 30).set("name", "zhangsansan");
        // 執行更新
        UpdateResult result = mongoTemplate.updateFirst(query, update, User.class, COLLECTION_NAME);
        // 輸出結果資訊
        String resultInfo = "共匹配到" + result.getMatchedCount() + "條資料,修改了" + result.getModifiedCount() + "條資料";
        log.info("更新結果:{}", resultInfo);
        return resultInfo;
    }

    /**
     * 更新【匹配查詢】到的【文件資料集合】中的【所有資料】
     *
     * @return 執行更新的結果
     */
    public Object updateMany() {
        // 建立條件物件
        Criteria criteria = Criteria.where("age").gt(28);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 設定更新欄位和更新的內容
        Update update = new Update().set("age", 29).set("salary", "1999");
        // 執行更新
        UpdateResult result = mongoTemplate.updateMulti(query, update, User.class, COLLECTION_NAME);
        // 輸出結果資訊
        String resultInfo = "總共匹配到" + result.getMatchedCount() + "條資料,修改了" + result.getModifiedCount() + "條資料";
        log.info("更新結果:{}", resultInfo);
        return resultInfo;
    }

}

java

(5)、文件刪除

import com.mongodb.client.result.DeleteResult;
import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.User;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;

@Slf4j
@Service
public class RemoveService {

    /**
     * 設定集合名稱
     */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 刪除集合中【符合條件】的【一個]或[多個】文件
     *
     * @return 刪除使用者資訊的結果
     */
    public Object remove() {
        // 設定查詢條件引數
        int age = 30;
        String sex = "男";
        // 建立條件物件
        Criteria criteria = Criteria.where("age").is(age).and("sex").is(sex);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 執行刪除查詢到的匹配的全部文件資訊
        DeleteResult result = mongoTemplate.remove(query, COLLECTION_NAME);
        // 輸出結果資訊
        String resultInfo = "成功刪除 " + result.getDeletedCount() + " 條文件資訊";
        log.info(resultInfo);
        return resultInfo;
    }

    /**
     * 刪除【符合條件】的【單個文件】,並返回刪除的文件。
     *
     * @return 刪除的使用者資訊
     */
    public Object findAndRemove() {
        // 設定查詢條件引數
        String name = "zhangsansan";
        // 建立條件物件
        Criteria criteria = Criteria.where("name").is(name);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 執行刪除查詢到的匹配的第一條文件,並返回刪除的文件資訊
        User result = mongoTemplate.findAndRemove(query, User.class, COLLECTION_NAME);
        // 輸出結果資訊
        String resultInfo = "成功刪除文件資訊,文件內容為:" + result;
        log.info(resultInfo);
        return result;
    }

    /**
     * 刪除【符合條件】的【全部文件】,並返回刪除的文件。
     *
     * @return 刪除的全部使用者資訊
     */
    public Object findAllAndRemove() {
        // 設定查詢條件引數
        int age = 22;
        // 建立條件物件
        Criteria criteria = Criteria.where("age").is(age);
        // 建立查詢物件,然後將條件物件新增到其中
        Query query = new Query(criteria);
        // 執行刪除查詢到的匹配的全部文件,並返回刪除的全部文件資訊
        List<User> resultList = mongoTemplate.findAllAndRemove(query, User.class, COLLECTION_NAME);
        // 輸出結果資訊
        String resultInfo = "成功刪除文件資訊,文件內容為:" + resultList;
        log.info(resultInfo);
        return resultList;
    }

}

java

8、MongoDB 聚合操作

(1)、聚合表示式

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;

/**
 * 聚合表示式 $group
 *
 * @author mydlq
 */
@Slf4j
@Service
public class AggregateGroupService {

    /**
     * 設定集合名稱
     */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 使用管道操作符 $group 結合 $count 方法進行聚合統計
     *
     * @return 聚合結果
     */
    public Object aggregationGroupCount() {
        // 使用管道操作符 $group 進行分組,然後統計各個組的文件數量
        AggregationOperation group = Aggregation.group("age").count().as("numCount");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(group);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用管道操作符 $group 結合表示式操作符 $max 進行聚合統計
     *
     * @return 聚合結果
     */
    public Object aggregationGroupMax() {
        // 使用管道操作符 $group 進行分組,然後統計各個組文件某欄位最大值
        AggregationOperation group = Aggregation.group("sex").max("salary").as("salaryMax");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(group);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用管道操作符 $group 結合表示式操作符 $min 進行聚合統計
     *
     * @return 聚合結果
     */
    public Object aggregationGroupMin() {
        // 使用管道操作符 $group 進行分組,然後統計各個組文件某欄位最小值
        AggregationOperation group = Aggregation.group("sex").min("salary").as("salaryMin");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(group);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用管道操作符 $group 結合表示式操作符 $sum 進行聚合統計
     *
     * @return 聚合結果
     */
    public Object aggregationGroupSum() {
        // 使用管道操作符 $group 進行分組,然後統計各個組文件某欄位值合計
        AggregationOperation group = Aggregation.group("sex").sum("salary").as("salarySum");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(group);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用管道操作符 $group 結合表示式操作符 $avg 進行聚合統計
     *
     * @return 聚合結果
     */
    public Object aggregationGroupAvg() {
        // 使用管道操作符 $group 進行分組,然後統計各個組文件某欄位值平均值
        AggregationOperation group = Aggregation.group("sex").avg("salary").as("salaryAvg");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(group);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用管道操作符 $group 結合表示式操作符 $first 獲取每個組的包含某欄位的文件的第一條資料
     *
     * @return 聚合結果
     */
    public Object aggregationGroupFirst() {
        // 先對資料進行排序,然後使用管道操作符 $group 進行分組,最後統計各個組文件某欄位值第一個值
        AggregationOperation sort = Aggregation.sort(Sort.by("salary").ascending());
        AggregationOperation group = Aggregation.group("sex").first("salary").as("salaryFirst");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(sort, group);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用管道操作符 $group 結合表示式操作符 $last 獲取每個組的包含某欄位的文件的最後一條資料
     *
     * @return 聚合結果
     */
    public Object aggregationGroupLast() {
        // 先對資料進行排序,然後使用管道操作符 $group 進行分組,最後統計各個組文件某欄位值第最後一個值
        AggregationOperation sort = Aggregation.sort(Sort.by("salary").ascending());
        AggregationOperation group = Aggregation.group("sex").last("salary").as("salaryLast");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(sort, group);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用管道操作符 $group 結合表示式操作符 $push 獲取某欄位列表
     *
     * @return 聚合結果
     */
    public Object aggregationGroupPush() {
        // 先對資料進行排序,然後使用管道操作符 $group 進行分組,然後以陣列形式列出某欄位的全部值
        AggregationOperation push = Aggregation.group("sex").push("salary").as("salaryFirst");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(push);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

}

java

(2)、聚合管道操作符

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;

@Slf4j
@Service
public class AggregatePipelineService {

    /**
     * 設定集合名稱
     */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 使用 $group 和 $match 聚合,先使用 $match 過濾文件,然後再使用 $group 進行分組
     *
     * @return 聚合結果
     */
    public Object aggregateGroupMatch() {
        // 設定聚合條件,先使用 $match 過濾歲數大於 25 的使用者,然後按性別分組,統計每組使用者工資最高值
        AggregationOperation match = Aggregation.match(Criteria.where("age").lt(25));
        AggregationOperation group = Aggregation.group("sex").max("salary").as("sexSalary");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(match, group);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用 $group 和 $sort 聚合,先使用 $group 進行分組,然後再使用 $sort 排序
     *
     * @return 聚合結果
     */
    public Object aggregateGroupSort() {
        // 設定聚合條件,按歲數分組,然後統計每組使用者工資最大值和使用者數,按每組使用者工資最大值升序排序
        AggregationOperation group = Aggregation.group("age")
                .max("salary").as("ageSalary")
                .count().as("ageCount");
        AggregationOperation sort = Aggregation.sort(Sort.by("ageSalary").ascending());
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(group, sort);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用 $group 和 $limit 聚合,先使用 $group 進行分組,然後再使用 $limit 限制一定數目文件
     *
     * @return 聚合結果
     */
    public Object aggregateGroupLimit() {
        // 設定聚合條件,先按歲數分組,然後求每組使用者的工資總數、最大值、最小值、平均值,限制只能顯示五條
        AggregationOperation group = Aggregation.group("age")
                .sum("salary").as("sumSalary")
                .max("salary").as("maxSalary")
                .min("salary").as("minSalary")
                .avg("salary").as("avgSalary");
        AggregationOperation limit = Aggregation.limit(5L);
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(group, limit);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用 $group 和 $skip 聚合,先使用 $group 進行分組,然後再使用 $skip 跳過一定數目文件
     *
     * @return 聚合結果
     */
    public Object aggregateGroupSkip() {
        // 設定聚合條件,先按歲數分組,然後求每組使用者的工資總數、最大值、最小值、平均值,跳過前 2 條
        AggregationOperation group = Aggregation.group("age")
                .sum("salary").as("sumSalary")
                .max("salary").as("maxSalary")
                .min("salary").as("minSalary")
                .avg("salary").as("avgSalary");
        AggregationOperation limit = Aggregation.skip(2L);
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(group, limit);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用 $group 和 $project 聚合,先使用 $group 進行分組,然後再使用 $project 限制顯示的欄位
     *
     * @return 聚合結果
     */
    public Object aggregateGroupProject() {
        // 設定聚合條件,按歲數分組,然後求每組使用者工資最大值、最小值,然後使用 $project 限制值顯示 salaryMax 欄位
        AggregationOperation group = Aggregation.group("age")
                .max("salary").as("maxSalary")
                .min("salary").as("minSalary");
        AggregationOperation project = Aggregation.project("maxSalary");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(group, project);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

    /**
     * 使用 $group 和 $unwind 聚合,先使用 $project 進行分組,然後再使用 $unwind 拆分文件中的陣列為一條新文件記錄
     *
     * @return 聚合結果
     */
    public Object aggregateProjectUnwind() {
        // 設定聚合條件,設定顯示`name`、`age`、`title`欄位,然後將結果中的多條文件按 title 欄位進行拆分
        AggregationOperation project = Aggregation.project("name", "age", "title");
        AggregationOperation unwind = Aggregation.unwind("title");
        // 將操作加入到聚合物件中
        Aggregation aggregation = Aggregation.newAggregation(project, unwind);
        // 執行聚合查詢
        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
        for (Map result : results.getMappedResults()) {
            log.info("{}", result);
        }
        return results.getMappedResults();
    }

}

java

聚合管道操作符:

  • $project: 可以從文件中選擇想要的欄位,和不想要的欄位(指定的欄位可以是來自輸入文件或新計算欄位的現有欄位 ,也可以通過管道表示式進行一些複雜的操作,例如數學操作,日期操作,字串操作,邏輯操作。
  • $match: 用於過濾資料,只輸出符合條件的文件。$match使用MongoDB的標準查詢操作。
  • $limit: 用來限制MongoDB聚合管道返回的文件數。
  • $skip: 在聚合管道中跳過指定數量的文件,並返回餘下的文件。
  • $unwind: 將文件中的某一個陣列型別欄位拆分成多條,每條包含陣列中的一個值。
  • $group: 將集合中的文件分組,可用於統計結果。
  • $sort: 將輸入文件排序後輸出。

9、MongoDB 索引操作

(1)、建立索引

import com.mongodb.client.model.Filters;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Slf4j
@Service
public class CreateIndexService {

    /** 設定集合名稱 */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 建立升序索引
     *
     * @return 索引資訊
     */
    public Object createAscendingIndex() {
        // 設定欄位名稱
        String field = "name";
        // 建立索引
        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field));
    }

    /**
     * 建立降序索引
     *
     * @return 索引資訊
     */
    public Object createDescendingIndex() {
        // 設定欄位名稱
        String field = "name";
        // 建立索引
        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.descending(field));
    }

    /**
     * 建立升序複合索引
     *
     * @return 索引資訊
     */
    public Object createCompositeIndex() {
        // 設定欄位名稱
        String field1 = "name";
        String field2 = "age";
        // 建立索引
        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field1, field2));
    }

    /**
     * 建立文字索引
     *
     * @return 索引資訊
     */
    public Object createTextIndex() {
        // 設定欄位名稱
        String field = "name";
        // 建立索引
        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.text(field));
    }

    /**
     * 建立雜湊索引
     *
     * @return 索引資訊
     */
    public Object createHashIndex() {
        // 設定欄位名稱
        String field = "name";
        // 建立索引
        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.hashed(field));
    }

    /**
     * 建立升序唯一索引
     *
     * @return 索引資訊
     */
    public Object createUniqueIndex() {
        // 設定欄位名稱
        String indexName = "name";
        // 配置索引選項
        IndexOptions options = new IndexOptions();
        // 設定為唯一索引
        options.unique(true);
        // 建立索引
        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(indexName), options);
    }

    /**
     * 建立區域性索引
     *
     * @return 索引資訊
     */
    public Object createPartialIndex() {
        // 設定欄位名稱
        String field = "name";
        // 配置索引選項
        IndexOptions options = new IndexOptions();
        // 設定過濾條件
        options.partialFilterExpression(Filters.exists("name", true));
        // 建立索引
        return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field), options);
    }

}

java

(2)、查詢索引

import com.mongodb.client.ListIndexesIterable;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 查詢索引操作
 *
 * @author mydlq
 */
@Slf4j
@Service
public class QueryIndexService {

    /** 設定集合名稱 */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 獲取當前【集合】對應的【所有索引】的【名稱列表】
     *
     * @return 當前【集合】所有【索引名稱列表】
     */
    public Object getIndexAll() {
        // 獲取集合中所有列表
        ListIndexesIterable<Document> indexList = mongoTemplate.getCollection(COLLECTION_NAME).listIndexes();
        // 建立字串集合
        List<Document> list = new ArrayList<>();
        // 獲取集合中全部索引資訊
        for (Document document : indexList) {
            log.info("索引列表:{}",document);
            list.add(document);
        }
        return list;
    }

}

java

(3)、刪除索引

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Slf4j
@Service
public class RemoveIndexService {

    @Resource
    private MongoTemplate mongoTemplate;

    /** 設定集合名稱 */
    private static final String COLLECTION_NAME = "users";

    /**
     * 根據索引名稱移除索引
     */
    public void removeIndex() {
        // 設定索引名稱
        String indexName = "name_1";
        // 刪除集合中某個索引
        mongoTemplate.getCollection(COLLECTION_NAME).dropIndex(indexName);
    }

    /**
     * 移除全部索引
     */
    public void removeIndexAll() {
        // 刪除集合中全部索引
        mongoTemplate.getCollection(COLLECTION_NAME).dropIndexes();
    }

}

java

10、MongoDB RunCommand 命令操作

(1)、RunCommand 命令

import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class RunCommandService {

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 執行 mongoDB 自定義命令,詳情可以檢視:https://docs.mongodb.com/manual/reference/command/
     *
     * @return 執行命令返回結果的 Json 結果
     * @description 執行自定義 mongoDB 命令
     */
    public Object runCommand() {
        // 自定義命令
        String jsonCommand = "{\"buildInfo\":1}";
        // 將 JSON 字串解析成 MongoDB 命令
        Bson bson = Document.parse(jsonCommand);
        // 執行自定義命令
        return mongoTemplate.getDb().runCommand(bson);
    }

}

java

五、SpringBoot 引入 MongoDB 中的事務

注意:單節點 mongodb 不支援事務,需要搭建 MongoDB 複製集。

1、配置事務管理器

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.MongoTransactionManager;

/**
 * 配置事務管理器
 *
 * @author mydlq
 */
@Configuration
public class TransactionConfig {

    @Bean
    MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }

}

java

2、建立事務測試服務

import mydlq.club.example.entity.Status;
import mydlq.club.example.entity.User;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;

@Service
public class TransactionExample {

    /** 設定集合名稱 */
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    @Transactional(rollbackFor = Exception.class)
    public Object transactionTest(){
        // 設定兩個使用者資訊
        User user1 = new User()
                .setId("11")
                .setAge(22)
                .setSex("男")
                .setRemake("無")
                .setSalary(1500)
                .setName("shiyi")
                .setBirthday(new Date())
                .setStatus(new Status().setHeight(180).setWeight(150));
        // 插入資料
        User newUser1 = mongoTemplate.insert(user1, COLLECTION_NAME);
        // 丟擲異常,觀察資料是否進行回滾
        int error = 1/0;
        return newUser1;
    }

}

java

如果對你有幫助,別忘了點顆星嘞~

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章