Spring Boot 整合 MongoDB 学习笔记 (新手入门)

Spring Boot 整合 MongoDB 学习笔记 (新手入门)

目录

  1. 引言
  2. 环境准备
  3. [步骤 1: 添加 Maven/Gradle 依赖](#步骤 1: 添加 Maven/Gradle 依赖)
  4. [步骤 2: 配置 MongoDB 连接](#步骤 2: 配置 MongoDB 连接)
  5. [步骤 3: 创建实体类 (Domain Model)](#步骤 3: 创建实体类 (Domain Model))
  6. [步骤 4: 创建 Repository 接口](#步骤 4: 创建 Repository 接口)
  7. [步骤 5: 实现基础 CRUD 操作](#步骤 5: 实现基础 CRUD 操作)
  8. [步骤 6: 进阶查询 - 使用 MongoTemplate](#步骤 6: 进阶查询 - 使用 MongoTemplate)
    • [什么是 MongoTemplate?](#什么是 MongoTemplate?)
    • [使用 QueryCriteria](#使用 Query 和 Criteria)
      • [什么是 Query?](#什么是 Query?)
      • [什么是 Criteria?](#什么是 Criteria?)
      • [常用 Criteria 方法](#常用 Criteria 方法)
      • 代码示例
    • [使用 Aggregation](#使用 Aggregation)
  9. [MongoDB 操作与 SQL (MySQL) 对比](#MongoDB 操作与 SQL (MySQL) 对比)
  10. 重点内容总结
  11. 结语

1. 引言

本笔记旨在帮助初学者理解如何在 Spring Boot 项目中集成和使用 MongoDB 数据库。我们将从最基础的配置开始,逐步深入到常用的增删改查 (CRUD) 操作,以及更复杂的查询方式,如使用 Query, CriteriaAggregationSpring Data MongoDB 极大地简化了 Java 应用与 MongoDB 的交互。


2. 环境准备

  • JDK: 确保已安装 Java 开发工具包 (推荐 JDK 8 或更高版本)。
  • Maven 或 Gradle: Spring Boot 项目构建工具。
  • IDE: 如 IntelliJ IDEA, Eclipse, VS Code 等。
  • MongoDB: 需要一个正在运行的 MongoDB 实例 (可以是本地安装,也可以是 Docker 容器,或者是云服务如 MongoDB Atlas)。

3. 步骤 1: 添加 Maven/Gradle 依赖

要在 Spring Boot 项目中使用 MongoDB,首先需要添加 spring-boot-starter-data-mongodb 依赖。

Maven (pom.xml):

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
    <!-- 通常不需要指定版本,Spring Boot会管理 -->
</dependency>

Gradle (build.gradle):

groovy 复制代码
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
    // 其他依赖...
}

注释: 这个 Starter 会自动引入 Spring Data MongoDB 以及所需的 MongoDB Java 驱动程序。


4. 步骤 2: 配置 MongoDB 连接

src/main/resources 目录下的 application.propertiesapplication.yml 文件中配置 MongoDB 的连接信息。

application.properties 格式:

properties 复制代码
# MongoDB 连接 URI (推荐方式,包含了所有信息)
# 格式: mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[database][?options]]
spring.data.mongodb.uri=mongodb://localhost:27017/mydatabase

# 或者分开配置 (如果不用URI)
# spring.data.mongodb.host=localhost
# spring.data.mongodb.port=27017
# spring.data.mongodb.database=mydatabase
# 如果有认证
# spring.data.mongodb.username=your_username
# spring.data.mongodb.password=your_password
# spring.data.mongodb.authentication-database=admin # 通常是 admin 或你的数据库名

application.yml 格式:

yaml 复制代码
spring:
  data:
    mongodb:
      # URI 方式 (推荐)
      uri: mongodb://localhost:27017/mydatabase
      # 分开配置方式
      # host: localhost
      # port: 27017
      # database: mydatabase
      # username: your_username
      # password: your_password
      # authentication-database: admin

重点:

  • spring.data.mongodb.uri 是最常用且推荐的配置方式,简洁明了。
  • mydatabase 是你要连接的数据库名称,如果不存在,MongoDB 通常会在第一次写入数据时自动创建。
  • 确保主机名 (localhost) 和端口 (27017 是默认端口) 正确。
  • 如果 MongoDB 设置了用户认证,务必提供 usernamepassword

5. 步骤 3: 创建实体类 (Domain Model)

实体类是 Java 对象,用于映射 MongoDB 中的文档 (Document)。

java 复制代码
package com.example.yourproject.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field; // 可选,用于指定字段名

import java.util.Date;

/**
 * 用户实体类,映射到 MongoDB 中的 "users" 集合。
 */
@Document(collection = "users") // 指定映射的 MongoDB 集合名称,如果省略,默认为类名的小写形式 (user)
public class User {

    @Id // 标记这个字段作为文档的主键 (_id)
    private String id; // MongoDB 的 _id 通常是 ObjectId 类型,但映射为 String 更方便

    @Field("user_name") // 可选:如果 Java 字段名与 MongoDB 字段名不同,用 @Field 指定
    private String name;

    private int age;
    private String email;

    @Field("created_at") // 示例:指定字段名
    private Date createdAt;

    // Standard Constructors, Getters, Setters, toString() ...

    public User() {
        this.createdAt = new Date(); // 可以在构造函数中设置默认值
    }

    public User(String name, int age, String email) {
        this(); // 调用默认构造函数设置 createdAt
        this.name = name;
        this.age = age;
        this.email = email;
    }

    // --- Getters and Setters ---
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public Date getCreatedAt() { return createdAt; }
    public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }

    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                ", createdAt=" + createdAt +
                '}';
    }
}

重点:

  • @Document: 标记这是一个映射到 MongoDB 文档的类。collection 属性指定了集合名称。
  • @Id: 标记主键字段,对应 MongoDB 中的 _id。Spring Data MongoDB 会自动处理 String 类型和 MongoDB ObjectId 之间的转换。如果字段名为 id@Id 注解甚至可以省略(但不推荐省略以保证清晰)。
  • @Field: 当 Java 字段名和 MongoDB 文档中的字段名不一致时使用。如果一致,则可以省略。

6. 步骤 4: 创建 Repository 接口

Spring Data MongoDB 提供了一个 MongoRepository 接口,它内置了许多标准的 CRUD 操作方法。我们只需要定义一个接口继承它即可。

java 复制代码
package com.example.yourproject.repository;

import com.example.yourproject.model.User;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * User 数据访问层接口
 * 继承 MongoRepository<实体类类型, 主键类型>
 */
@Repository // 标记这是一个 Spring管理的 Repository Bean
public interface UserRepository extends MongoRepository<User, String> {

    // Spring Data MongoDB 会根据方法名自动生成查询实现!
    // 例如:根据 name 查找用户
    List<User> findByName(String name);

    // 例如:根据 email 查找单个用户 (假设 email 是唯一的)
    User findByEmail(String email);

    // 例如:查找年龄大于某个值的用户
    List<User> findByAgeGreaterThan(int age);

    // 更多查询方法可以参照 Spring Data JPA 的命名规范
    // https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#repositories.query-methods.query-creation
}

重点:

  • 继承 MongoRepository<User, String>,其中 User 是实体类,String 是主键 id 的类型。
  • @Repository 注解使得 Spring Boot 能自动扫描并创建这个 Bean。
  • 最强大的功能之一 :通过定义符合特定命名规范的方法(如 findByName, findByAgeGreaterThan),Spring Data MongoDB 会自动为你实现这些查询,无需编写任何具体代码!这被称为方法名衍生查询 (Query Methods)

7. 步骤 5: 实现基础 CRUD 操作

现在可以在你的 Service 或 Controller 中注入 UserRepository,并调用其方法进行 CRUD 操作。

java 复制代码
package com.example.yourproject.service;

import com.example.yourproject.model.User;
import com.example.yourproject.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class UserService {

    @Autowired // 自动注入 UserRepository 的实例
    private UserRepository userRepository;

    /**
     * 创建或更新用户
     * 如果 user 对象有 id 且数据库中存在该 id,则执行更新操作。
     * 如果 user 对象没有 id 或 id 在数据库中不存在,则执行插入操作。
     */
    public User saveOrUpdateUser(User user) {
        // save() 方法兼具插入和更新功能 (upsert)
        User savedUser = userRepository.save(user);
        System.out.println("Saved/Updated User: " + savedUser);
        return savedUser;
    }

    /**
     * 根据 ID 查找用户
     */
    public Optional<User> findUserById(String id) {
        // findById 返回一个 Optional<User>,可以更好地处理空结果
        Optional<User> userOptional = userRepository.findById(id);
        if (userOptional.isPresent()) {
            System.out.println("Found User by ID " + id + ": " + userOptional.get());
        } else {
            System.out.println("User with ID " + id + " not found.");
        }
        return userOptional;
    }

    /**
     * 查找所有用户
     */
    public List<User> findAllUsers() {
        List<User> users = userRepository.findAll();
        System.out.println("Found all users: Count = " + users.size());
        return users;
    }

    /**
     * 使用方法名衍生查询:根据姓名查找用户
     */
    public List<User> findUsersByName(String name) {
        List<User> users = userRepository.findByName(name);
        System.out.println("Found users by name '" + name + "': " + users);
        return users;
    }

    /**
     * 根据 ID 删除用户
     */
    public void deleteUserById(String id) {
        // 先检查是否存在 (可选,但更安全)
        if (userRepository.existsById(id)) {
            userRepository.deleteById(id);
            System.out.println("Deleted User with ID: " + id);
        } else {
            System.out.println("User with ID " + id + " not found, cannot delete.");
        }
    }

    /**
     * 删除指定用户对象
     */
    public void deleteUser(User user) {
        // 需要 user 对象有有效的 id
        userRepository.delete(user);
        System.out.println("Deleted User: " + user);
    }

    /**
     * 删除所有用户 (谨慎使用!)
     */
    public void deleteAllUsers() {
        userRepository.deleteAll();
        System.out.println("Deleted all users.");
    }
}

重点:

  • @Autowired 用于依赖注入 UserRepository
  • save(entity): 核心方法,既能插入新文档(如果实体没有 ID 或 ID 不存在),也能更新现有文档(如果实体有 ID 且数据库中存在)。
  • findById(id): 返回 Optional<T>,推荐使用 isPresent() 判断和 get() 获取。
  • findAll(): 返回所有文档的列表。
  • deleteById(id) / delete(entity) / deleteAll(): 执行删除操作。
  • existsById(id): 检查文档是否存在。
  • MongoRepository 提供的默认方法和自定义的方法名衍生查询,覆盖了大部分常见的简单查询场景。

8. 步骤 6: 进阶查询 - 使用 MongoTemplate

MongoRepository 提供的方法名衍生查询或 @Query 注解(此处未详细介绍,但也可用于定义 JPQL 或原生查询)无法满足复杂的查询需求时,可以使用 MongoTemplateMongoTemplate 提供了更底层、更灵活的 MongoDB 操作方式,包括复杂的查询、更新和聚合操作。

什么是 MongoTemplate?

MongoTemplate 是 Spring Data MongoDB 提供的核心类,它封装了 MongoDB Java 驱动的操作,提供了方便的 API 来执行各种数据库操作。你需要在使用它的类中注入它:

java 复制代码
import org.springframework.data.mongodb.core.MongoTemplate;

@Service
public class AdvancedUserService {

    @Autowired
    private MongoTemplate mongoTemplate; // 注入 MongoTemplate

    // ... 方法将在这里实现 ...
}

使用 QueryCriteria

对于复杂的查询条件,我们通常使用 QueryCriteria 对象来构建。

什么是 Query?

Query 对象封装了 MongoDB 查询的所有方面,包括查询条件 (Criteria)、字段投影 (选择返回哪些字段)、排序 (Sort) 和分页 (limit, skip)。

什么是 Criteria?

Criteria 对象用于构建查询条件,类似于 SQL 中的 WHERE 子句。它提供了一系列方法 (如 is, gt, lt, regex, in, and, or 等) 来定义文档需要匹配的规则。

常用 Criteria 方法
Criteria 方法 含义 MongoDB 操作符 SQL (MySQL) 类似
where("field").is(value) 字段等于特定值 $eq field = value
where("field").ne(value) 字段不等于特定值 $ne field != value
where("field").lt(value) 字段小于特定值 $lt field < value
where("field").lte(value) 字段小于等于特定值 $lte field <= value
where("field").gt(value) 字段大于特定值 $gt field > value
where("field").gte(value) 字段大于等于特定值 $gte field >= value
where("field").in(list) 字段值在列表/数组中 $in field IN (...)
where("field").nin(list) 字段值不在列表/数组中 $nin field NOT IN (...)
where("field").exists(true/false) 字段存在/不存在 $exists IS NOT NULL / IS NULL (概念类似)
where("field").regex(pattern) 字段匹配正则表达式 $regex field REGEXP 'pattern'
where("field").regex(pattern, "i") 正则表达式 (忽略大小写) $options: 'i' (取决于具体实现)
and(criteria) 链式添加 AND 条件 (隐式AND) AND
new Criteria().orOperator(c1, c2, ...) 创建 OR 条件组合 $or OR
new Criteria().andOperator(c1, c2, ...) 创建 AND 条件组合 $and AND
代码示例 (Query & Criteria)
java 复制代码
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.domain.Sort; // 用于排序
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.yourproject.model.User;
import java.util.List;

@Service
public class AdvancedUserService {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 查找年龄大于指定值,并且按姓名升序排序的用户
     * @param minAge 最小年龄
     * @return 用户列表
     */
    public List<User> findUsersOlderThanAndSortByName(int minAge) {
        // 1. 创建查询条件 (Criteria)
        Criteria ageCriteria = Criteria.where("age").gt(minAge); // 年龄大于 minAge

        // 2. 创建 Query 对象,并应用 Criteria
        Query query = new Query(ageCriteria);

        // 3. 添加排序 (Sort)
        query.with(Sort.by(Sort.Direction.ASC, "user_name")); // 按 user_name 升序排序

        // 4. (可选) 添加分页
        // query.limit(10); // 限制返回最多 10 条
        // query.skip(20); // 跳过前 20 条 (用于分页)

        // 5. (可选) 添加字段投影 (只返回需要的字段)
        // query.fields().include("user_name", "email").exclude("_id"); // 只包含 name 和 email, 排除 _id

        // 6. 执行查询
        // find() 方法需要 Query 对象和结果映射的实体类类型
        List<User> users = mongoTemplate.find(query, User.class);
        // 如果查询的是特定集合,也可以指定集合名称: mongoTemplate.find(query, User.class, "users");

        System.out.println("Found users older than " + minAge + " (sorted by name): " + users);
        return users;
    }

    /**
     * 查找姓名包含 "John" (不区分大小写) 或者 邮箱以 ".com" 结尾的用户
     * @return 用户列表
     */
    public List<User> findUsersByNameRegexOrEmailSuffix() {
        // 条件1: 姓名包含 "John" (忽略大小写)
        Criteria nameCriteria = Criteria.where("user_name").regex("John", "i"); // "i" 表示忽略大小写

        // 条件2: 邮箱以 .com 结尾
        Criteria emailCriteria = Criteria.where("email").regex("\\.com$", ""); // $ 表示结尾, "." 需要转义

        // 组合 OR 条件
        Criteria orCriteria = new Criteria().orOperator(nameCriteria, emailCriteria);

        // 创建 Query
        Query query = new Query(orCriteria);

        // 执行查询
        List<User> users = mongoTemplate.find(query, User.class);
        System.out.println("Found users with name regex 'John' (i) or email ending in '.com': " + users);
        return users;
    }
}

注释:

  • Criteria.where("fieldName") 开始定义一个字段的条件。
  • 可以链式调用 .is(), .gt(), .lt(), .regex() 等方法。
  • new Criteria().orOperator(criteria1, criteria2) 用于组合 OR 条件。默认情况下,链式调用或多个 Criteria 放入 QueryAND 关系。
  • Query 对象可以设置排序 (.with(Sort.by(...)))、分页 (limit(), skip()) 和字段投影 (fields().include()/exclude())。
  • mongoTemplate.find(query, EntityClass.class) 执行查询。

使用 Aggregation

MongoDB 的聚合框架 (Aggregation Framework) 是一个强大的数据处理管道,用于对集合中的文档进行多阶段处理,例如分组、计算、转换等,非常适合数据分析和报表生成。

什么是 Aggregation?

在 Spring Data MongoDB 中,Aggregation API 用于构建和执行 MongoDB 的聚合管道。管道由一系列阶段 (Stages) 组成,每个阶段对输入的文档进行处理,并将结果传递给下一个阶段。

常用聚合阶段 (Stages)
Spring Data 方法 MongoDB 阶段 描述 SQL (MySQL) 类似
match(criteria) $match 过滤文档,类似于 find 的条件 WHERE / HAVING (概念上)
group(fields...) $group 按指定字段分组,并进行聚合运算 (sum, avg等) GROUP BY
project(fields...) $project 重塑文档结构 (选择、重命名、添加计算字段) SELECT field1, field2, calculation
sort(sort) $sort 按指定字段排序 ORDER BY
limit(n) $limit 限制输出的文档数量 LIMIT n
skip(n) $skip 跳过指定数量的文档 OFFSET n
unwind("field") $unwind 将数组字段的每个元素拆分成独立的文档 (无直接对应,类似 JOIN 或规范化)
lookup(...) $lookup 执行类似 SQL 的左外连接 (Left Outer Join) LEFT JOIN
count("fieldName") $count 计算输入文档的数量,并输出到指定字段 SELECT COUNT(*)...
addFields(...) $addFields 向文档添加新字段 (无直接对应)
sortByCount("field") $sortByCount 按字段值的频率分组和排序 (组合了 $group$sort) SELECT field, COUNT(*) GROUP BY field ORDER BY COUNT(*) DESC
代码示例 (Aggregation)

假设我们想按年龄分组,统计每个年龄段的用户数量,并按年龄排序。

java 复制代码
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.aggregation.SortOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.domain.Sort;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.yourproject.model.User; // 假设有 User 类
import java.util.List;

// 定义一个类来接收聚合结果 (字段名需要匹配 $project 或 $group 的输出)
class AgeGroupResult {
    private int age; // 对应 $group 的 _id.age
    private long count; // 对应 $group 的 count

    // Getters and Setters
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public long getCount() { return count; }
    public void setCount(long count) { this.count = count; }

    @Override
    public String toString() {
        return "AgeGroupResult{" + "age=" + age + ", count=" + count + '}';
    }
}


@Service
public class AggregationService {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 按年龄分组统计用户数量,只统计年龄大于 18 的用户,并按年龄排序
     * @return 每个年龄及其对应的用户数量列表
     */
    public List<AgeGroupResult> groupUsersByAge() {

        // 1. $match 阶段: 过滤年龄大于 18 的用户 (可选)
        MatchOperation matchStage = Aggregation.match(Criteria.where("age").gt(18));

        // 2. $group 阶段: 按 age 字段分组,并计算每个分组的数量 (count)
        //    将分组的键 (age) 放入 _id 字段中
        GroupOperation groupStage = Aggregation.group("age") // 按 "age" 字段分组
                                              .count().as("count"); // 计算数量,并将结果命名为 "count"

        // 3. $project 阶段: 重塑输出,将 _id (即 age) 映射到 age 字段,并包含 count 字段
        //    默认的 _id 是分组依据,我们想让它叫 "age"
        ProjectionOperation projectStage = Aggregation.project("count") // 选择 "count" 字段
                                                     .and("_id").as("age") // 将分组产生的 "_id" (即年龄) 重命名为 "age"
                                                     .andExclude("_id"); // 排除掉原始的 "_id" 字段

        // 4. $sort 阶段: 按 age 字段升序排序
        SortOperation sortStage = Aggregation.sort(Sort.Direction.ASC, "age");

        // 5. 构建聚合管道 (按顺序添加阶段)
        Aggregation aggregation = Aggregation.newAggregation(
                matchStage,    // 先过滤
                groupStage,    // 再分组
                projectStage,  // 然后重塑输出
                sortStage      // 最后排序
        );

        // 6. 执行聚合查询
        // aggregate() 方法需要 Aggregation 对象、输入集合的名称、输出结果映射的类类型
        AggregationResults<AgeGroupResult> results = mongoTemplate.aggregate(
                aggregation,
                "users", // 指定要聚合的集合名称 ("users" 对应 @Document(collection = "users"))
                AgeGroupResult.class // 指定结果映射的类
        );

        // 7. 获取映射后的结果列表
        List<AgeGroupResult> mappedResults = results.getMappedResults();

        System.out.println("Aggregation Results (Users grouped by age > 18): " + mappedResults);
        return mappedResults;
    }
}

重点:

  • 聚合是按顺序执行的多个阶段,每个阶段的输出是下一个阶段的输入。
  • Aggregation.newAggregation(...) 用于构建整个管道。
  • match(), group(), project(), sort() 等静态方法创建对应的聚合阶段。
  • group("field") 指定分组依据的字段。.count().as("fieldName"), .sum("field").as("total"), .avg("field").as("average") 等用于在分组内进行计算。
  • project() 非常重要,用于调整输出文档的结构,使其匹配你的结果类 (AgeGroupResult)。and("_id").as("newName") 常用于重命名分组产生的 _id
  • 需要创建一个结果类 (如 AgeGroupResult)来映射聚合操作的输出。字段名必须与 $project$group 阶段最后输出的字段名匹配。
  • mongoTemplate.aggregate(aggregation, inputCollectionName, OutputClass.class) 执行聚合。

9. MongoDB 操作与 SQL (MySQL) 对比

下表简要对比了 MongoDB (概念/Shell语法) 和 Spring Data MongoDB (Java API) 与 SQL (以 MySQL 为例) 的常用操作:

操作类别 MongoDB (概念 / Shell 示例) Spring Data MongoDB (MongoRepository / MongoTemplate) SQL (MySQL 示例)
数据库/集合 use mydatabase / db.createCollection("users") 配置 spring.data.mongodb.database / @Document(collection="users") (自动创建) CREATE DATABASE mydatabase; / USE mydatabase; CREATE TABLE users (...);
插入数据 db.users.insertOne({name:"A", age:30}) userRepository.save(new User("A", 30)) INSERT INTO users (name, age) VALUES ('A', 30);
查询所有数据 db.users.find({}) userRepository.findAll() / mongoTemplate.findAll(User.class) SELECT * FROM users;
条件查询 db.users.find({age: {$gt: 25}}) userRepository.findByAgeGreaterThan(25) / mongoTemplate.find(Query.query(Criteria.where("age").gt(25)), User.class) SELECT * FROM users WHERE age > 25;
AND 条件 db.users.find({name:"A", age:30}) mongoTemplate.find(Query.query(Criteria.where("name").is("A").and("age").is(30)), User.class) / userRepository.findByNameAndAge("A", 30) (衍生查询) SELECT * FROM users WHERE name = 'A' AND age = 30;
OR 条件 db.users.find({$or: [{name:"A"}, {age:30}]}) mongoTemplate.find(Query.query(new Criteria().orOperator(Criteria.where("name").is("A"), Criteria.where("age").is(30))), User.class) SELECT * FROM users WHERE name = 'A' OR age = 30;
更新数据 db.users.updateOne({name:"A"}, {$set:{age:31}}) User u = userRepository.findByName("A"); if(u!=null){ u.setAge(31); userRepository.save(u); } (更灵活更新用 mongoTemplate.updateFirst/updateMulti) UPDATE users SET age = 31 WHERE name = 'A';
删除数据 db.users.deleteOne({name:"A"}) User u = userRepository.findByName("A"); if(u!=null){ userRepository.delete(u); } / userRepository.deleteById(id) DELETE FROM users WHERE name = 'A';
排序 db.users.find().sort({age: 1}) userRepository.findAll(Sort.by("age")) / query.with(Sort.by(Sort.Direction.ASC, "age")) SELECT * FROM users ORDER BY age ASC;
限制数量/分页 db.users.find().limit(10).skip(20) Pageable p = PageRequest.of(2, 10); userRepository.findAll(p) / query.limit(10).skip(20) SELECT * FROM users LIMIT 10 OFFSET 20;
分组统计 db.users.aggregate([{$group:{_id:"$age", count:{$sum:1}}}]) (见上方 Aggregation 示例) SELECT age, COUNT(*) FROM users GROUP BY age;
选择特定字段 db.users.find({}, {name: 1, email: 1, _id: 0}) query.fields().include("name", "email").excludeId() SELECT name, email FROM users;

关键差异:

  • Schema: MongoDB 是 Schema-less (或 Schema-flexible),集合中的文档可以有不同的结构。MySQL 是 Schema-based,表结构需要预先定义。
  • 数据模型: MongoDB 是面向文档的 (BSON/JSON 格式),支持嵌套文档和数组。MySQL 是关系型的,数据存储在行和列组成的表中。
  • 查询语言: MongoDB 使用基于 JSON 的查询语言。MySQL 使用 SQL。
  • 事务: MongoDB 从 4.0 版本开始支持多文档 ACID 事务,但使用场景和复杂性与关系型数据库有所不同。传统上关系型数据库的事务支持更成熟和广泛。
  • Join : MongoDB 通过 $lookup (聚合) 实现类似 Join 的功能,但通常鼓励通过嵌入文档引用来设计数据模型以避免复杂的 Join。MySQL 的 Join 是核心功能。

10. 重点内容总结

  1. 核心依赖 : spring-boot-starter-data-mongodb 是整合的关键。
  2. 配置 : 通过 application.propertiesapplication.yml 配置数据库连接,spring.data.mongodb.uri 是首选方式。
  3. 实体映射 : 使用 @Document 标记类,@Id 标记主键。@Field 用于字段名映射。
  4. 基础 CRUD : 继承 MongoRepository<Entity, IdType> 接口,可以获得大量开箱即用的 CRUD 方法和强大的方法名衍生查询功能,极大简化开发。
  5. save() 方法 : 同时处理插入更新操作 (Upsert)。
  6. MongoTemplate: 当需要更复杂、灵活的查询、更新或聚合操作时使用。它是执行底层 MongoDB 命令的主要入口。
  7. QueryCriteria : 使用 MongoTemplate 进行查询时,用 Criteria 构建查询条件 (类似 SQL WHERE),用 Query 封装条件、排序、分页和投影。
  8. Aggregation : 用于执行多阶段的数据处理管道(分组、计算、转换),非常适合数据分析和报表。需要定义阶段 (match, group, project, sort 等) 并按顺序组合。通常需要创建结果类来映射聚合输出。
  9. MongoDB vs SQL: 理解两者在数据模型、查询方式、事务处理和 Join 上的核心差异很重要。Spring Data MongoDB 在一定程度上抽象了这些差异,但底层概念仍然不同。

11. 结语

恭喜你!通过这篇笔记,你应该对如何在 Spring Boot 中使用 MongoDB 有了基本的了解。从简单的配置、实体映射、MongoRepository 的便捷 CRUD,到 MongoTemplate 提供的更强大查询能力 (Query, Criteria) 和数据处理能力 (Aggregation),你已经掌握了核心的使用方法。

下一步建议:

  • 动手实践:创建自己的 Spring Boot 项目,连接 MongoDB,尝试笔记中的所有示例。
  • 深入学习 QueryCriteria 的更多操作符。
  • 探索更复杂的 Aggregation 管道应用。
  • 了解 MongoDB 的索引 (@Indexed 注解) 对查询性能的重要性。
  • 研究 MongoDB 的事务 (如果你的应用场景需要)。
  • 了解 GridFS (如果需要存储大文件)。

希望这篇笔记对你的学习之旅有所帮助!

相关推荐
技术宝哥1 小时前
解决 Spring Boot 启动报错:数据源配置引发的启动失败
spring boot·后端·mybatis
struggle20251 小时前
Trinity三位一体开源程序是可解释的 AI 分析工具和 3D 可视化
数据库·人工智能·学习·3d·开源·自动化
码农周1 小时前
Spring Boot 启动后自动执行 Service 方法终极指南
java·spring boot·后端
路在脚下@2 小时前
Spring Boot项目中结合MyBatis实现MySQL的自动主从切换
spring boot·mysql·mybatis
创码小奇客2 小时前
MongoDB 增删改查:从青铜到王者的全攻略
java·mongodb·trae
blackA_2 小时前
Java学习——day29(并发控制高级工具与设计模式)
java·学习·设计模式
日月星辰Ace2 小时前
@SpringBootTest @DirtiesContext
java·spring boot
meng半颗糖3 小时前
mongodb 安装配置
数据库·mongodb·database
面包圈蘸可乐3 小时前
论文学习:《EVlncRNA-net:一种双通道深度学习方法,用于对实验验证的lncRNA进行准确预测》
深度学习·学习·生物信息