MongoDB 详细用法与 Java 集成完整指南

目录

  1. MongoDB 基础概念
  2. MongoDB 安装与配置
  3. MongoDB Shell 基本操作
  4. Java 环境准备
  5. Java MongoDB 驱动集成
  6. 连接配置
  7. 基本 CRUD 操作
  8. 高级查询操作
  9. 索引操作
  10. 聚合管道
  11. 事务处理
  12. Spring Boot 集成
  13. 最佳实践

1. MongoDB 基础概念

1.1 核心概念对比

SQL术语MongoDB术语说明
databasedatabase数据库
tablecollection集合(表)
rowdocument文档(行)
columnfield字段(列)
indexindex索引
primary key_id主键

1.2 文档结构

{"_id": ObjectId("507f1f77bcf86cd799439011"),"name": "John Doe","age": 30,"email": "john@example.com","address": {"street": "123 Main St","city": "New York","zipcode": "10001"},"tags": ["developer", "mongodb", "java"],"createdAt": ISODate("2023-01-01T00:00:00Z")
}

2. MongoDB 安装与配置

2.1 Windows 安装

# 1. 下载 MongoDB Community Server
# https://www.mongodb.com/try/download/community# 2. 安装后启动服务
net start MongoDB# 3. 连接到 MongoDB
mongo

2.2 Linux 安装 (Ubuntu)

# 1. 导入公钥
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -# 2. 添加仓库
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list# 3. 更新包列表并安装
sudo apt-get update
sudo apt-get install -y mongodb-org# 4. 启动服务
sudo systemctl start mongod
sudo systemctl enable mongod# 5. 验证安装
mongosh

2.3 Docker 安装

# 拉取 MongoDB 镜像
docker pull mongo:latest# 运行 MongoDB 容器
docker run -d \--name mongodb \-p 27017:27017 \-e MONGO_INITDB_ROOT_USERNAME=admin \-e MONGO_INITDB_ROOT_PASSWORD=password \-v mongodb_data:/data/db \mongo:latest# 连接到容器
docker exec -it mongodb mongosh -u admin -p password

3. MongoDB Shell 基本操作

3.1 数据库操作

// 显示所有数据库
show dbs// 使用/创建数据库
use myapp// 显示当前数据库
db// 删除数据库
db.dropDatabase()

3.2 集合操作

// 显示所有集合
show collections// 创建集合
db.createCollection("users")// 删除集合
db.users.drop()

3.3 文档操作

// 插入单个文档
db.users.insertOne({name: "Alice",age: 25,email: "alice@example.com"
})// 插入多个文档
db.users.insertMany([{ name: "Bob", age: 30, email: "bob@example.com" },{ name: "Charlie", age: 35, email: "charlie@example.com" }
])// 查询所有文档
db.users.find()// 条件查询
db.users.find({ age: { $gte: 30 } })// 更新文档
db.users.updateOne({ name: "Alice" },{ $set: { age: 26 } }
)// 删除文档
db.users.deleteOne({ name: "Bob" })

4. Java 环境准备

4.1 系统要求

  • Java 8 或更高版本
  • Maven 3.3+ 或 Gradle 4.0+
  • MongoDB 4.0 或更高版本

4.2 Maven 项目结构

my-mongodb-app/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── Main.java
│   │   │           ├── config/
│   │   │           ├── model/
│   │   │           ├── dao/
│   │   │           └── service/
│   │   └── resources/
│   │       └── application.properties
│   └── test/
└── target/

5. Java MongoDB 驱动集成

5.1 Maven 依赖配置

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>mongodb-java-example</artifactId><version>1.0.0</version><packaging>jar</packaging><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- MongoDB Java Driver --><dependency><groupId>org.mongodb</groupId><artifactId>mongodb-driver-sync</artifactId><version>4.11.1</version></dependency><!-- 可选: 异步驱动 --><dependency><groupId>org.mongodb</groupId><artifactId>mongodb-driver-reactivestreams</artifactId><version>4.11.1</version></dependency><!-- JSON 处理 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version></dependency><!-- 日志 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>2.0.7</version></dependency><!-- 测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.11.0</version><configuration><source>11</source><target>11</target></configuration></plugin></plugins></build>
</project>

5.2 Gradle 依赖配置

plugins {id 'java'id 'application'
}group = 'com.example'
version = '1.0.0'
sourceCompatibility = '11'repositories {mavenCentral()
}dependencies {// MongoDB Java Driverimplementation 'org.mongodb:mongodb-driver-sync:4.11.1'implementation 'org.mongodb:mongodb-driver-reactivestreams:4.11.1'// JSON 处理implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'// 日志implementation 'org.slf4j:slf4j-simple:2.0.7'// 测试testImplementation 'junit:junit:4.13.2'
}application {mainClass = 'com.example.Main'
}

6. 连接配置

6.1 基本连接配置

package com.example.config;import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerAddress;
import com.mongodb.MongoCredential;
import java.util.Arrays;public class MongoDBConfig {private static final String DATABASE_NAME = "myapp";private static final String CONNECTION_STRING = "mongodb://localhost:27017";private static MongoClient mongoClient;private static MongoDatabase database;// 简单连接方式public static MongoDatabase getDatabase() {if (database == null) {mongoClient = MongoClients.create(CONNECTION_STRING);database = mongoClient.getDatabase(DATABASE_NAME);}return database;}// 详细连接配置public static MongoDatabase getDatabaseWithOptions() {if (database == null) {// 创建连接字符串ConnectionString connectionString = new ConnectionString("mongodb://username:password@localhost:27017/myapp?authSource=admin");// 或者使用 MongoClientSettings 进行详细配置MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(connectionString).retryWrites(true).build();mongoClient = MongoClients.create(settings);database = mongoClient.getDatabase(DATABASE_NAME);}return database;}// 集群连接配置public static MongoDatabase getClusterDatabase() {if (database == null) {// 服务器地址列表ServerAddress seed1 = new ServerAddress("server1.example.com", 27017);ServerAddress seed2 = new ServerAddress("server2.example.com", 27017);ServerAddress seed3 = new ServerAddress("server3.example.com", 27017);// 认证信息MongoCredential credential = MongoCredential.createCredential("username", "admin", "password".toCharArray());// 客户端设置MongoClientSettings settings = MongoClientSettings.builder().applyToClusterSettings(builder -> builder.hosts(Arrays.asList(seed1, seed2, seed3))).credential(credential).build();mongoClient = MongoClients.create(settings);database = mongoClient.getDatabase(DATABASE_NAME);}return database;}// 关闭连接public static void close() {if (mongoClient != null) {mongoClient.close();}}
}

6.2 连接池配置

package com.example.config;import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.connection.ConnectionPoolSettings;
import java.util.concurrent.TimeUnit;public class ConnectionPoolConfig {public static MongoClient createMongoClientWithPool() {ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/myapp");// 连接池设置ConnectionPoolSettings poolSettings = ConnectionPoolSettings.builder().maxSize(20)                    // 最大连接数.minSize(5)                     // 最小连接数.maxWaitTime(2, TimeUnit.MINUTES) // 最大等待时间.maxConnectionLifeTime(30, TimeUnit.MINUTES) // 连接最大生存时间.maxConnectionIdleTime(10, TimeUnit.MINUTES) // 连接最大空闲时间.build();MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(connectionString).applyToConnectionPoolSettings(builder -> builder.applySettings(poolSettings)).build();return MongoClients.create(settings);}
}

7. 基本 CRUD 操作

7.1 实体类定义

package com.example.model;import org.bson.types.ObjectId;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.LocalDateTime;
import java.util.List;public class User {@JsonProperty("_id")private ObjectId id;private String name;private String email;private Integer age;private Address address;private List<String> tags;private LocalDateTime createdAt;private LocalDateTime updatedAt;// 构造函数public User() {this.createdAt = LocalDateTime.now();}public User(String name, String email, Integer age) {this();this.name = name;this.email = email;this.age = age;}// Getter 和 Setter 方法public ObjectId getId() { return id; }public void setId(ObjectId id) { this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public Integer getAge() { return age; }public void setAge(Integer age) { this.age = age; }public Address getAddress() { return address; }public void setAddress(Address address) { this.address = address; }public List<String> getTags() { return tags; }public void setTags(List<String> tags) { this.tags = tags; }public LocalDateTime getCreatedAt() { return createdAt; }public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }public LocalDateTime getUpdatedAt() { return updatedAt; }public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", email='" + email + '\'' +", age=" + age +", address=" + address +", tags=" + tags +", createdAt=" + createdAt +", updatedAt=" + updatedAt +'}';}
}// 地址类
class Address {private String street;private String city;private String zipcode;private String country;// 构造函数public Address() {}public Address(String street, String city, String zipcode, String country) {this.street = street;this.city = city;this.zipcode = zipcode;this.country = country;}// Getter 和 Setter 方法public String getStreet() { return street; }public void setStreet(String street) { this.street = street; }public String getCity() { return city; }public void setCity(String city) { this.city = city; }public String getZipcode() { return zipcode; }public void setZipcode(String zipcode) { this.zipcode = zipcode; }public String getCountry() { return country; }public void setCountry(String country) { this.country = country; }@Overridepublic String toString() {return "Address{" +"street='" + street + '\'' +", city='" + city + '\'' +", zipcode='" + zipcode + '\'' +", country='" + country + '\'' +'}';}
}

7.2 DAO 层实现

package com.example.dao;import com.example.config.MongoDBConfig;
import com.example.model.User;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import com.mongodb.client.model.Sorts;
import com.mongodb.client.model.Projections;
import com.mongodb.client.result.InsertOneResult;
import com.mongodb.client.result.UpdateResult;
import com.mongodb.client.result.DeleteResult;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;public class UserDAO {private final MongoCollection<Document> collection;public UserDAO() {MongoDatabase database = MongoDBConfig.getDatabase();this.collection = database.getCollection("users");}// 创建用户 - 插入单个文档public ObjectId createUser(User user) {try {Document doc = userToDocument(user);InsertOneResult result = collection.insertOne(doc);return result.getInsertedId().asObjectId().getValue();} catch (Exception e) {throw new RuntimeException("Error creating user: " + e.getMessage(), e);}}// 批量创建用户public List<ObjectId> createUsers(List<User> users) {try {List<Document> documents = new ArrayList<>();for (User user : users) {documents.add(userToDocument(user));}collection.insertMany(documents);List<ObjectId> insertedIds = new ArrayList<>();for (Document doc : documents) {insertedIds.add(doc.getObjectId("_id"));}return insertedIds;} catch (Exception e) {throw new RuntimeException("Error creating users: " + e.getMessage(), e);}}// 根据 ID 查询用户public User findById(ObjectId id) {try {Document doc = collection.find(Filters.eq("_id", id)).first();return doc != null ? documentToUser(doc) : null;} catch (Exception e) {throw new RuntimeException("Error finding user by id: " + e.getMessage(), e);}}// 根据邮箱查询用户public User findByEmail(String email) {try {Document doc = collection.find(Filters.eq("email", email)).first();return doc != null ? documentToUser(doc) : null;} catch (Exception e) {throw new RuntimeException("Error finding user by email: " + e.getMessage(), e);}}// 查询所有用户public List<User> findAll() {try {List<User> users = new ArrayList<>();for (Document doc : collection.find()) {users.add(documentToUser(doc));}return users;} catch (Exception e) {throw new RuntimeException("Error finding all users: " + e.getMessage(), e);}}// 条件查询 - 年龄范围public List<User> findByAgeRange(int minAge, int maxAge) {try {List<User> users = new ArrayList<>();Bson filter = Filters.and(Filters.gte("age", minAge),Filters.lte("age", maxAge));for (Document doc : collection.find(filter)) {users.add(documentToUser(doc));}return users;} catch (Exception e) {throw new RuntimeException("Error finding users by age range: " + e.getMessage(), e);}}// 模糊查询 - 姓名包含关键词public List<User> findByNameContaining(String keyword) {try {List<User> users = new ArrayList<>();Bson filter = Filters.regex("name", ".*" + keyword + ".*", "i");for (Document doc : collection.find(filter)) {users.add(documentToUser(doc));}return users;} catch (Exception e) {throw new RuntimeException("Error finding users by name: " + e.getMessage(), e);}}// 分页查询public List<User> findWithPagination(int page, int pageSize) {try {List<User> users = new ArrayList<>();int skip = (page - 1) * pageSize;for (Document doc : collection.find().sort(Sorts.descending("createdAt")).skip(skip).limit(pageSize)) {users.add(documentToUser(doc));}return users;} catch (Exception e) {throw new RuntimeException("Error finding users with pagination: " + e.getMessage(), e);}}// 只查询特定字段public List<User> findNamesAndEmails() {try {List<User> users = new ArrayList<>();Bson projection = Projections.fields(Projections.include("name", "email"),Projections.exclude("_id"));for (Document doc : collection.find().projection(projection)) {User user = new User();user.setName(doc.getString("name"));user.setEmail(doc.getString("email"));users.add(user);}return users;} catch (Exception e) {throw new RuntimeException("Error finding names and emails: " + e.getMessage(), e);}}// 更新用户public boolean updateUser(ObjectId id, User user) {try {user.setUpdatedAt(LocalDateTime.now());Bson filter = Filters.eq("_id", id);Bson update = Updates.combine(Updates.set("name", user.getName()),Updates.set("email", user.getEmail()),Updates.set("age", user.getAge()),Updates.set("updatedAt", user.getUpdatedAt()));UpdateResult result = collection.updateOne(filter, update);return result.getModifiedCount() > 0;} catch (Exception e) {throw new RuntimeException("Error updating user: " + e.getMessage(), e);}}// 部分更新 - 只更新年龄public boolean updateAge(ObjectId id, int newAge) {try {Bson filter = Filters.eq("_id", id);Bson update = Updates.combine(Updates.set("age", newAge),Updates.set("updatedAt", LocalDateTime.now()));UpdateResult result = collection.updateOne(filter, update);return result.getModifiedCount() > 0;} catch (Exception e) {throw new RuntimeException("Error updating user age: " + e.getMessage(), e);}}// 批量更新public long updateUsersInCity(String city, String newCountry) {try {Bson filter = Filters.eq("address.city", city);Bson update = Updates.combine(Updates.set("address.country", newCountry),Updates.set("updatedAt", LocalDateTime.now()));UpdateResult result = collection.updateMany(filter, update);return result.getModifiedCount();} catch (Exception e) {throw new RuntimeException("Error updating users in city: " + e.getMessage(), e);}}// 删除用户public boolean deleteUser(ObjectId id) {try {DeleteResult result = collection.deleteOne(Filters.eq("_id", id));return result.getDeletedCount() > 0;} catch (Exception e) {throw new RuntimeException("Error deleting user: " + e.getMessage(), e);}}// 根据条件删除多个用户public long deleteUsersByAge(int maxAge) {try {Bson filter = Filters.lte("age", maxAge);DeleteResult result = collection.deleteMany(filter);return result.getDeletedCount();} catch (Exception e) {throw new RuntimeException("Error deleting users by age: " + e.getMessage(), e);}}// 计数操作public long countUsers() {try {return collection.countDocuments();} catch (Exception e) {throw new RuntimeException("Error counting users: " + e.getMessage(), e);}}public long countUsersByAge(int minAge) {try {return collection.countDocuments(Filters.gte("age", minAge));} catch (Exception e) {throw new RuntimeException("Error counting users by age: " + e.getMessage(), e);}}// 辅助方法 - User 转 Documentprivate Document userToDocument(User user) {Document doc = new Document();if (user.getId() != null) {doc.put("_id", user.getId());}doc.put("name", user.getName());doc.put("email", user.getEmail());doc.put("age", user.getAge());if (user.getAddress() != null) {Document addressDoc = new Document().append("street", user.getAddress().getStreet()).append("city", user.getAddress().getCity()).append("zipcode", user.getAddress().getZipcode()).append("country", user.getAddress().getCountry());doc.put("address", addressDoc);}if (user.getTags() != null) {doc.put("tags", user.getTags());}doc.put("createdAt", user.getCreatedAt());doc.put("updatedAt", user.getUpdatedAt());return doc;}// 辅助方法 - Document 转 Userprivate User documentToUser(Document doc) {User user = new User();user.setId(doc.getObjectId("_id"));user.setName(doc.getString("name"));user.setEmail(doc.getString("email"));user.setAge(doc.getInteger("age"));Document addressDoc = doc.get("address", Document.class);if (addressDoc != null) {Address address = new Address(addressDoc.getString("street"),addressDoc.getString("city"),addressDoc.getString("zipcode"),addressDoc.getString("country"));user.setAddress(address);}@SuppressWarnings("unchecked")List<String> tags = doc.get("tags", List.class);user.setTags(tags);// 注意:这里需要处理日期类型转换user.setCreatedAt((LocalDateTime) doc.get("createdAt"));user.setUpdatedAt((LocalDateTime) doc.get("updatedAt"));return user;}
}

7.3 Service 层实现

package com.example.service;import com.example.dao.UserDAO;
import com.example.model.User;
import org.bson.types.ObjectId;import java.util.List;public class UserService {private final UserDAO userDAO;public UserService() {this.userDAO = new UserDAO();}// 创建用户public ObjectId createUser(String name, String email, Integer age) {// 业务逻辑验证if (name == null || name.trim().isEmpty()) {throw new IllegalArgumentException("Name cannot be empty");}if (email == null || !isValidEmail(email)) {throw new IllegalArgumentException("Invalid email format");}if (age != null && (age < 0 || age > 150)) {throw new IllegalArgumentException("Age must be between 0 and 150");}// 检查邮箱是否已存在User existingUser = userDAO.findByEmail(email);if (existingUser != null) {throw new IllegalArgumentException("Email already exists");}User user = new User(name, email, age);return userDAO.createUser(user);}// 获取用户public User getUserById(String id) {try {ObjectId objectId = new ObjectId(id);return userDAO.findById(objectId);} catch (IllegalArgumentException e) {throw new IllegalArgumentException("Invalid user ID format");}}public User getUserByEmail(String email) {return userDAO.findByEmail(email);}public List<User> getAllUsers() {return userDAO.findAll();}public List<User> getUsersByAgeRange(int minAge, int maxAge) {if (minAge < 0 || maxAge < 0 || minAge > maxAge) {throw new IllegalArgumentException("Invalid age range");}return userDAO.findByAgeRange(minAge, maxAge);}public List<User> searchUsersByName(String keyword) {if (keyword == null || keyword.trim().isEmpty()) {throw new IllegalArgumentException("Search keyword cannot be empty");}return userDAO.findByNameContaining(keyword.trim());}public List<User> getUsersWithPagination(int page, int pageSize) {if (page < 1 || pageSize < 1) {throw new IllegalArgumentException("Page and pageSize must be positive");}return userDAO.findWithPagination(page, pageSize);}// 更新用户public boolean updateUser(String id, String name, String email, Integer age) {try {ObjectId objectId = new ObjectId(id);// 验证输入if (name != null && name.trim().isEmpty()) {throw new IllegalArgumentException("Name cannot be empty");}if (email != null && !isValidEmail(email)) {throw new IllegalArgumentException("Invalid email format");}if (age != null && (age < 0 || age > 150)) {throw new IllegalArgumentException("Age must be between 0 and 150");}// 检查用户是否存在User existingUser = userDAO.findById(objectId);if (existingUser == null) {throw new IllegalArgumentException("User not found");}// 如果更新邮箱,检查新邮箱是否已被其他用户使用if (email != null && !email.equals(existingUser.getEmail())) {User userWithEmail = userDAO.findByEmail(email);if (userWithEmail != null && !userWithEmail.getId().equals(objectId)) {throw new IllegalArgumentException("Email already exists");}}// 更新用户信息if (name != null) existingUser.setName(name);if (email != null) existingUser.setEmail(email);if (age != null) existingUser.setAge(age);return userDAO.updateUser(objectId, existingUser);} catch (IllegalArgumentException e) {throw new IllegalArgumentException("Invalid user ID format");}}public boolean updateUserAge(String id, int newAge) {try {ObjectId objectId = new ObjectId(id);if (newAge < 0 || newAge > 150) {throw new IllegalArgumentException("Age must be between 0 and 150");}return userDAO.updateAge(objectId, newAge);} catch (IllegalArgumentException e) {throw new IllegalArgumentException("Invalid user ID format");}}// 删除用户public boolean deleteUser(String id) {try {ObjectId objectId = new ObjectId(id);// 检查用户是否存在User existingUser = userDAO.findById(objectId);if (existingUser == null) {throw new IllegalArgumentException("User not found");}return userDAO.deleteUser(objectId);} catch (IllegalArgumentException e) {throw new IllegalArgumentException("Invalid user ID format");}}// 统计操作public long getUserCount() {return userDAO.countUsers();}public long getAdultUserCount() {return userDAO.countUsersByAge(18);}// 批量操作public List<ObjectId> createUsers(List<User> users) {// 验证所有用户数据for (User user : users) {if (user.getName() == null || user.getName().trim().isEmpty()) {throw new IllegalArgumentException("All users must have a name");}if (user.getEmail() == null || !isValidEmail(user.getEmail())) {throw new IllegalArgumentException("All users must have a valid email");}}return userDAO.createUsers(users);}public long bulkDeleteUsersByAge(int maxAge) {if (maxAge < 0) {throw new IllegalArgumentException("Age must be non-negative");}return userDAO.deleteUsersByAge(maxAge);}// 邮箱格式验证private boolean isValidEmail(String email) {return email != null && email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");}
}

8. 高级查询操作

8.1 复杂查询实现

package com.example.dao;import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.*;
import org.bson.Document;
import org.bson.conversions.Bson;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;public class AdvancedQueryDAO {private final MongoCollection<Document> collection;public AdvancedQueryDAO(MongoCollection<Document> collection) {this.collection = collection;}// 复合条件查询public List<Document> findUsersWithComplexConditions() {List<Document> results = new ArrayList<>();// 年龄在20-40之间,且名字包含"John"或邮箱以"gmail"结尾Bson ageFilter = Filters.and(Filters.gte("age", 20),Filters.lte("age", 40));Bson nameOrEmailFilter = Filters.or(Filters.regex("name", ".*John.*", "i"),Filters.regex("email", ".*@gmail\\.com$", "i"));Bson complexFilter = Filters.and(ageFilter, nameOrEmailFilter);for (Document doc : collection.find(complexFilter)) {results.add(doc);}return results;}// 数组查询public List<Document> findUsersByTags(String... tags) {List<Document> results = new ArrayList<>();// 包含所有指定标签的用户Bson filter = Filters.all("tags", Arrays.asList(tags));for (Document doc : collection.find(filter)) {results.add(doc);}return results;}public List<Document> findUsersByAnyTag(String... tags) {List<Document> results = new ArrayList<>();// 包含任意一个指定标签的用户Bson filter = Filters.in("tags", Arrays.asList(tags));for (Document doc : collection.find(filter)) {results.add(doc);}return results;}// 嵌套文档查询public List<Document> findUsersByCity(String city) {List<Document> results = new ArrayList<>();Bson filter = Filters.eq("address.city", city);for (Document doc : collection.find(filter)) {results.add(doc);}return results;}// 存在性查询public List<Document> findUsersWithAddress() {List<Document> results = new ArrayList<>();Bson filter = Filters.exists("address");for (Document doc : collection.find(filter)) {results.add(doc);}return results;}public List<Document> findUsersWithoutTags() {List<Document> results = new ArrayList<>();Bson filter = Filters.or(Filters.exists("tags", false),Filters.size("tags", 0));for (Document doc : collection.find(filter)) {results.add(doc);}return results;}// 正则表达式查询public List<Document> findUsersByEmailDomain(String domain) {List<Document> results = new ArrayList<>();Pattern pattern = Pattern.compile(".*@" + Pattern.quote(domain) + "$", Pattern.CASE_INSENSITIVE);Bson filter = Filters.regex("email", pattern);for (Document doc : collection.find(filter)) {results.add(doc);}return results;}// 类型查询public List<Document> findUsersWithStringAge() {List<Document> results = new ArrayList<>();Bson filter = Filters.type("age", "string");for (Document doc : collection.find(filter)) {results.add(doc);}return results;}// 地理位置查询(需要创建地理索引)public List<Document> findUsersNearLocation(double longitude, double latitude, double maxDistance) {List<Document> results = new ArrayList<>();Bson filter = Filters.near("location", longitude, latitude, maxDistance, null);for (Document doc : collection.find(filter)) {results.add(doc);}return results;}// 排序和限制public List<Document> findTopUsersByAge(int limit) {List<Document> results = new ArrayList<>();for (Document doc : collection.find().sort(Sorts.descending("age")).limit(limit)) {results.add(doc);}return results;}// 多字段排序public List<Document> findUsersOrderedByAgeAndName() {List<Document> results = new ArrayList<>();Bson sort = Sorts.orderBy(Sorts.ascending("age"),Sorts.ascending("name"));for (Document doc : collection.find().sort(sort)) {results.add(doc);}return results;}
}

9. 索引操作

9.1 索引管理类

package com.example.index;import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import org.bson.Document;import java.util.concurrent.TimeUnit;public class IndexManager {private final MongoCollection<Document> collection;public IndexManager(MongoCollection<Document> collection) {this.collection = collection;}// 创建单字段索引public void createSingleFieldIndex() {// 在 email 字段上创建升序索引collection.createIndex(Indexes.ascending("email"));System.out.println("Created ascending index on email field");// 在 age 字段上创建降序索引collection.createIndex(Indexes.descending("age"));System.out.println("Created descending index on age field");}// 创建唯一索引public void createUniqueIndex() {IndexOptions indexOptions = new IndexOptions().unique(true);collection.createIndex(Indexes.ascending("email"), indexOptions);System.out.println("Created unique index on email field");}// 创建复合索引public void createCompoundIndex() {collection.createIndex(Indexes.compoundIndex(Indexes.ascending("age"),Indexes.descending("createdAt")));System.out.println("Created compound index on age (asc) and createdAt (desc)");}// 创建文本索引public void createTextIndex() {collection.createIndex(Indexes.compoundIndex(Indexes.text("name"),Indexes.text("email")));System.out.println("Created text index on name and email fields");}// 创建部分索引public void createPartialIndex() {IndexOptions indexOptions = new IndexOptions().partialFilterExpression(new Document("age", new Document("$gte", 18)));collection.createIndex(Indexes.ascending("email"), indexOptions);System.out.println("Created partial index on email for users >= 18 years old");}// 创建 TTL 索引(生存时间索引)public void createTTLIndex() {IndexOptions indexOptions = new IndexOptions().expireAfter(30L, TimeUnit.DAYS);collection.createIndex(Indexes.ascending("createdAt"), indexOptions);System.out.println("Created TTL index on createdAt field (30 days)");}// 创建稀疏索引public void createSparseIndex() {IndexOptions indexOptions = new IndexOptions().sparse(true);collection.createIndex(Indexes.ascending("phoneNumber"), indexOptions);System.out.println("Created sparse index on phoneNumber field");}// 创建地理空间索引public void createGeospatialIndex() {collection.createIndex(Indexes.geo2dsphere("location"));System.out.println("Created 2dsphere index on location field");}// 创建哈希索引public void createHashedIndex() {collection.createIndex(Indexes.hashed("userId"));System.out.println("Created hashed index on userId field");}// 列出所有索引public void listAllIndexes() {System.out.println("Existing indexes:");for (Document index : collection.listIndexes()) {System.out.println(index.toJson());}}// 删除索引public void dropIndexes() {// 删除特定索引collection.dropIndex("email_1");System.out.println("Dropped index on email field");// 删除所有索引(除了 _id 索引)// collection.dropIndexes();}// 获取索引统计信息public void getIndexStats() {// 这需要通过聚合管道来获取System.out.println("Index statistics would be retrieved through aggregation pipeline");}
}

10. 聚合管道

10.1 聚合操作实现

package com.example.aggregation;import com.mongodb.client.MongoCollection;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Sorts;
import org.bson.Document;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class AggregationOperations {private final MongoCollection<Document> collection;public AggregationOperations(MongoCollection<Document> collection) {this.collection = collection;}// 基本统计聚合public Document getUserStatistics() {List<Document> pipeline = Arrays.asList(new Document("$group", new Document("_id", null).append("totalUsers", new Document("$sum", 1)).append("averageAge", new Document("$avg", "$age")).append("minAge", new Document("$min", "$age")).append("maxAge", new Document("$max", "$age")).append("totalAge", new Document("$sum", "$age"))));AggregateIterable<Document> result = collection.aggregate(pipeline);return result.first();}// 按年龄分组统计public List<Document> getUsersByAgeGroup() {List<Document> results = new ArrayList<>();List<Document> pipeline = Arrays.asList(new Document("$group", new Document("_id", new Document("$switch", new Document("branches", Arrays.asList(new Document("case", new Document("$lt", Arrays.asList("$age", 18))).append("then", "未成年"),new Document("case", new Document("$lt", Arrays.asList("$age", 35))).append("then", "青年"),new Document("case", new Document("$lt", Arrays.asList("$age", 60))).append("then", "中年"))).append("default", "老年"))).append("count", new Document("$sum", 1)).append("averageAge", new Document("$avg", "$age"))),new Document("$sort", new Document("count", -1)));for (Document doc : collection.aggregate(pipeline)) {results.add(doc);}return results;}// 按城市分组统计public List<Document> getUsersByCity() {List<Document> results = new ArrayList<>();List<Document> pipeline = Arrays.asList(new Document("$match", new Document("address.city", new Document("$exists", true))),new Document("$group", new Document("_id", "$address.city").append("userCount", new Document("$sum", 1)).append("averageAge", new Document("$avg", "$age")).append("users", new Document("$push", new Document("name", "$name").append("email", "$email")))),new Document("$sort", new Document("userCount", -1)));for (Document doc : collection.aggregate(pipeline)) {results.add(doc);}return results;}// 投影操作 - 重构输出格式public List<Document> getUserProfiles() {List<Document> results = new ArrayList<>();List<Document> pipeline = Arrays.asList(new Document("$project", new Document("_id", 0).append("fullName", "$name").append("contactInfo", new Document("email", "$email").append("phone", "$phoneNumber")).append("demographics", new Document("age", "$age").append("ageGroup", new Document("$switch", new Document("branches", Arrays.asList(new Document("case", new Document("$lt", Arrays.asList("$age", 25))).append("then", "Young"),new Document("case", new Document("$lt", Arrays.asList("$age", 50))).append("then", "Middle-aged"))).append("default", "Senior")))).append("location", "$address.city").append("isActive", new Document("$cond", Arrays.asList(new Document("$ne", Arrays.asList("$lastLoginDate", null)),true,false)))));for (Document doc : collection.aggregate(pipeline)) {results.add(doc);}return results;}// 查找操作 - 关联其他集合public List<Document> getUsersWithOrderInfo(MongoCollection<Document> ordersCollection) {List<Document> results = new ArrayList<>();List<Document> pipeline = Arrays.asList(new Document("$lookup", new Document("from", "orders").append("localField", "_id").append("foreignField", "userId").append("as", "orders")),new Document("$addFields", new Document("orderCount", new Document("$size", "$orders")).append("totalOrderValue", new Document("$sum", "$orders.amount"))),new Document("$match", new Document("orderCount", new Document("$gt", 0))),new Document("$sort", new Document("totalOrderValue", -1)));for (Document doc : collection.aggregate(pipeline)) {results.add(doc);}return results;}// 解构数组操作public List<Document> getUserTagAnalysis() {List<Document> results = new ArrayList<>();List<Document> pipeline = Arrays.asList(new Document("$match", new Document("tags", new Document("$exists", true))),new Document("$unwind", "$tags"),new Document("$group", new Document("_id", "$tags").append("userCount", new Document("$sum", 1)).append("users", new Document("$push", "$name"))),new Document("$sort", new Document("userCount", -1)),new Document("$limit", 10));for (Document doc : collection.aggregate(pipeline)) {results.add(doc);}return results;}// 时间序列分析public List<Document> getUserRegistrationTrend() {List<Document> results = new ArrayList<>();List<Document> pipeline = Arrays.asList(new Document("$group", new Document("_id", new Document("year", new Document("$year", "$createdAt")).append("month", new Document("$month", "$createdAt"))).append("registrations", new Document("$sum", 1)).append("averageAge", new Document("$avg", "$age"))),new Document("$sort", new Document("_id.year", 1).append("_id.month", 1)),new Document("$project", new Document("_id", 0).append("period", new Document("$concat", Arrays.asList(new Document("$toString", "$_id.year"),"-",new Document("$toString", "$_id.month")))).append("registrations", 1).append("averageAge", new Document("$round", Arrays.asList("$averageAge", 1)))));for (Document doc : collection.aggregate(pipeline)) {results.add(doc);}return results;}// 复杂的多阶段聚合public List<Document> getAdvancedUserAnalytics() {List<Document> results = new ArrayList<>();List<Document> pipeline = Arrays.asList(// 阶段 1: 匹配活跃用户new Document("$match", new Document("isActive", true)),// 阶段 2: 添加计算字段new Document("$addFields", new Document("ageGroup", new Document("$switch", new Document("branches", Arrays.asList(new Document("case", new Document("$lt", Arrays.asList("$age", 25))).append("then", "18-24"),new Document("case", new Document("$lt", Arrays.asList("$age", 35))).append("then", "25-34"),new Document("case", new Document("$lt", Arrays.asList("$age", 50))).append("then", "35-49"))).append("default", "50+"))).append("emailDomain", new Document("$arrayElemAt", Arrays.asList(new Document("$split", Arrays.asList("$email", "@")), 1)))),// 阶段 3: 按年龄组和邮箱域名分组new Document("$group", new Document("_id", new Document("ageGroup", "$ageGroup").append("emailDomain", "$emailDomain")).append("userCount", new Document("$sum", 1)).append("names", new Document("$push", "$name"))),// 阶段 4: 重新分组以获得每个年龄组的信息new Document("$group", new Document("_id", "$_id.ageGroup").append("totalUsers", new Document("$sum", "$userCount")).append("domains", new Document("$push", new Document("domain", "$_id.emailDomain").append("count", "$userCount")))),// 阶段 5: 排序new Document("$sort", new Document("totalUsers", -1)),// 阶段 6: 投影最终结果new Document("$project", new Document("_id", 0).append("ageGroup", "$_id").append("totalUsers", 1).append("topDomains", new Document("$slice", Arrays.asList(new Document("$sortArray", new Document("input", "$domains").append("sortBy", new Document("count", -1))), 3)))));for (Document doc : collection.aggregate(pipeline)) {results.add(doc);}return results;}
}

11. 事务处理

11.1 事务操作实现

package com.example.transaction;import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import org.bson.Document;
import org.bson.types.ObjectId;public class TransactionManager {private final MongoClient mongoClient;private final MongoDatabase database;public TransactionManager(MongoClient mongoClient, MongoDatabase database) {this.mongoClient = mongoClient;this.database = database;}// 简单事务示例:转账操作public boolean transferMoney(ObjectId fromUserId, ObjectId toUserId, double amount) {ClientSession session = mongoClient.startSession();try {return session.withTransaction(() -> {MongoCollection<Document> accounts = database.getCollection("accounts");// 检查转出账户余额Document fromAccount = accounts.find(session, Filters.eq("_id", fromUserId)).first();if (fromAccount == null) {throw new RuntimeException("转出账户不存在");}double fromBalance = fromAccount.getDouble("balance");if (fromBalance < amount) {throw new RuntimeException("余额不足");}// 检查转入账户是否存在Document toAccount = accounts.find(session, Filters.eq("_id", toUserId)).first();if (toAccount == null) {throw new RuntimeException("转入账户不存在");}// 执行转账accounts.updateOne(session, Filters.eq("_id", fromUserId),Updates.inc("balance", -amount));accounts.updateOne(session,Filters.eq("_id", toUserId),Updates.inc("balance", amount));// 记录交易日志MongoCollection<Document> transactions = database.getCollection("transactions");Document transaction = new Document().append("fromUserId", fromUserId).append("toUserId", toUserId).append("amount", amount).append("timestamp", System.currentTimeMillis()).append("status", "completed");transactions.insertOne(session, transaction);return true;});} catch (Exception e) {System.err.println("转账失败: " + e.getMessage());return false;} finally {session.close();}}// 复杂事务示例:创建订单public ObjectId createOrderWithInventoryUpdate(ObjectId userId, String productId, int quantity) {ClientSession session = mongoClient.startSession();try {return session.withTransaction(() -> {MongoCollection<Document> users = database.getCollection("users");MongoCollection<Document> products = database.getCollection("products");MongoCollection<Document> orders = database.getCollection("orders");MongoCollection<Document> inventory = database.getCollection("inventory");// 1. 验证用户存在Document user = users.find(session, Filters.eq("_id", userId)).first();if (user == null) {throw new RuntimeException("用户不存在");}// 2. 验证产品存在并获取价格Document product = products.find(session, Filters.eq("productId", productId)).first();if (product == null) {throw new RuntimeException("产品不存在");}double price = product.getDouble("price");// 3. 检查库存并更新Document inventoryDoc = inventory.find(session, Filters.eq("productId", productId)).first();if (inventoryDoc == null) {throw new RuntimeException("库存记录不存在");}int currentStock = inventoryDoc.getInteger("quantity");if (currentStock < quantity) {throw new RuntimeException("库存不足");}// 更新库存inventory.updateOne(session,Filters.eq("productId", productId),Updates.inc("quantity", -quantity));// 4. 创建订单ObjectId orderId = new ObjectId();Document order = new Document().append("_id", orderId).append("userId", userId).append("productId", productId).append("quantity", quantity).append("unitPrice", price).append("totalAmount", price * quantity).append("status", "pending").append("createdAt", System.currentTimeMillis());orders.insertOne(session, order);// 5. 更新用户订单历史users.updateOne(session,Filters.eq("_id", userId),Updates.push("orderHistory", orderId));return orderId;});} catch (Exception e) {System.err.println("创建订单失败: " + e.getMessage());return null;} finally {session.close();}}// 回调式事务处理public boolean performMultiCollectionOperation() {ClientSession session = mongoClient.startSession();try {session.withTransaction(() -> {MongoCollection<Document> collection1 = database.getCollection("collection1");MongoCollection<Document> collection2 = database.getCollection("collection2");// 在事务中执行多个操作collection1.insertOne(session, new Document("field1", "value1"));collection2.updateOne(session, Filters.eq("_id", "someId"),Updates.set("field2", "value2"));// 如果这里抛出异常,整个事务会回滚// throw new RuntimeException("模拟失败");return "success";});return true;} catch (Exception e) {System.err.println("事务执行失败: " + e.getMessage());return false;} finally {session.close();}}// 手动事务控制public boolean manualTransactionControl() {ClientSession session = mongoClient.startSession();try {session.startTransaction();MongoCollection<Document> users = database.getCollection("users");MongoCollection<Document> logs = database.getCollection("logs");try {// 执行业务操作users.insertOne(session, new Document("name", "New User"));logs.insertOne(session, new Document("action", "user_created"));// 手动提交事务session.commitTransaction();return true;} catch (Exception e) {// 手动回滚事务session.abortTransaction();System.err.println("事务回滚: " + e.getMessage());return false;}} finally {session.close();}}
}

12. Spring Boot 集成

12.1 Spring Boot 配置

// pom.xml 添加依赖
/*
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
*/// application.yml
/*
spring:data:mongodb:uri: mongodb://localhost:27017/myapp# 或者分别配置host: localhostport: 27017database: myappusername: adminpassword: passwordauthentication-database: adminserver:port: 8080logging:level:org.springframework.data.mongodb: DEBUG
*/package com.example.config;import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;@Configuration
@EnableMongoRepositories(basePackages = "com.example.repository")
public class MongoConfig extends AbstractMongoClientConfiguration {@Overrideprotected String getDatabaseName() {return "myapp";}// 自定义配置/*@Overridepublic MongoClient mongoClient() {ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/myapp");MongoClientSettings mongoClientSettings = MongoClientSettings.builder().applyConnectionString(connectionString).build();return MongoClients.create(mongoClientSettings);}*/
}

12.2 Spring Data MongoDB 实体类

package com.example.entity;import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.index.Indexed;import java.time.LocalDateTime;
import java.util.List;@Document(collection = "users")
public class User {@Idprivate String id;@Field("full_name")private String name;@Indexed(unique = true)private String email;private Integer age;private Address address;private List<String> tags;@CreatedDateprivate LocalDateTime createdAt;@LastModifiedDateprivate LocalDateTime updatedAt;// 构造函数public User() {}public User(String name, String email, Integer age) {this.name = name;this.email = email;this.age = age;}// Getter 和 Setter 方法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 String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public Integer getAge() { return age; }public void setAge(Integer age) { this.age = age; }public Address getAddress() { return address; }public void setAddress(Address address) { this.address = address; }public List<String> getTags() { return tags; }public void setTags(List<String> tags) { this.tags = tags; }public LocalDateTime getCreatedAt() { return createdAt; }public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }public LocalDateTime getUpdatedAt() { return updatedAt; }public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
}@Document
class Address {private String street;private String city;private String zipcode;private String country;// 构造函数和 Getter/Setter 方法public Address() {}public Address(String street, String city, String zipcode, String country) {this.street = street;this.city = city;this.zipcode = zipcode;this.country = country;}// Getter 和 Setter 方法省略...
}

12.3 Spring Data MongoDB Repository

package com.example.repository;import com.example.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.mongodb.repository.Aggregation;
import org.springframework.stereotype.Repository;import java.util.List;
import java.util.Optional;@Repository
public interface UserRepository extends MongoRepository<User, String> {// 基本查询方法(Spring Data 自动实现)Optional<User> findByEmail(String email);List<User> findByName(String name);List<User> findByAgeGreaterThan(Integer age);List<User> findByAgeBetween(Integer minAge, Integer maxAge);List<User> findByNameContainingIgnoreCase(String keyword);List<User> findByAddressCity(String city);List<User> findByTagsContaining(String tag);// 分页查询Page<User> findByAgeGreaterThan(Integer age, Pageable pageable);// 排序查询List<User> findByOrderByAgeDesc();List<User> findByAgeBetweenOrderByNameAsc(Integer minAge, Integer maxAge);// 自定义查询@Query("{ 'age' : { $gte: ?0, $lte: ?1 } }")List<User> findUsersInAgeRange(Integer minAge, Integer maxAge);@Query("{ 'email' : { $regex: ?0, $options: 'i' } }")List<User> findByEmailPattern(String pattern);@Query(value = "{ 'age' : { $gte: ?0 } }", fields = "{ 'name' : 1, 'email' : 1 }")List<User> findUserNamesAndEmailsByMinAge(Integer minAge);// 删除查询Long deleteByAge(Integer age);Long deleteByAgeGreaterThan(Integer age);// 聚合查询@Aggregation(pipeline = {"{ $group: { _id: null, totalUsers: { $sum: 1 }, averageAge: { $avg: '$age' } } }"})UserStatistics getUserStatistics();@Aggregation(pipeline = {"{ $group: { _id: '$address.city', count: { $sum: 1 } } }","{ $sort: { count: -1 } }"})List<CityUserCount> getUserCountByCity();// 统计接口interface UserStatistics {Integer getTotalUsers();Double getAverageAge();}interface CityUserCount {String getId(); // city nameInteger getCount();}
}

12.4 Service 层(Spring Boot)

package com.example.service;import com.example.entity.User;
import com.example.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;
import java.util.Optional;@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;// 创建用户public User createUser(User user) {// 业务逻辑验证validateUser(user);// 检查邮箱是否已存在Optional<User> existingUser = userRepository.findByEmail(user.getEmail());if (existingUser.isPresent()) {throw new IllegalArgumentException("Email already exists");}return userRepository.save(user);}// 批量创建用户public List<User> createUsers(List<User> users) {// 验证所有用户users.forEach(this::validateUser);return userRepository.saveAll(users);}// 获取用户public Optional<User> getUserById(String id) {return userRepository.findById(id);}public Optional<User> getUserByEmail(String email) {return userRepository.findByEmail(email);}public List<User> getAllUsers() {return userRepository.findAll();}// 分页查询public Page<User> getUsersWithPagination(int page, int size, String sortBy, String sortDir) {Sort sort = sortDir.equalsIgnoreCase("desc") ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();Pageable pageable = PageRequest.of(page, size, sort);return userRepository.findAll(pageable);}// 条件查询public List<User> getUsersByAgeRange(Integer minAge, Integer maxAge) {return userRepository.findByAgeBetween(minAge, maxAge);}public List<User> searchUsersByName(String keyword) {return userRepository.findByNameContainingIgnoreCase(keyword);}public List<User> getUsersByCity(String city) {return userRepository.findByAddressCity(city);}public List<User> getUsersByTag(String tag) {return userRepository.findByTagsContaining(tag);}// 更新用户public User updateUser(String id, User updatedUser) {return userRepository.findById(id).map(existingUser -> {existingUser.setName(updatedUser.getName());existingUser.setEmail(updatedUser.getEmail());existingUser.setAge(updatedUser.getAge());existingUser.setAddress(updatedUser.getAddress());existingUser.setTags(updatedUser.getTags());return userRepository.save(existingUser);}).orElseThrow(() -> new IllegalArgumentException("User not found with id: " + id));}// 删除用户public boolean deleteUser(String id) {return userRepository.findById(id).map(user -> {userRepository.delete(user);return true;}).orElse(false);}public void deleteAllUsers() {userRepository.deleteAll();}// 统计操作public long getUserCount() {return userRepository.count();}public UserRepository.UserStatistics getUserStatistics() {return userRepository.getUserStatistics();}public List<UserRepository.CityUserCount> getUserCountByCity() {return userRepository.getUserCountByCity();}// 业务逻辑验证private void validateUser(User user) {if (user.getName() == null || user.getName().trim().isEmpty()) {throw new IllegalArgumentException("Name cannot be empty");}if (user.getEmail() == null || !isValidEmail(user.getEmail())) {throw new IllegalArgumentException("Invalid email format");}if (user.getAge() != null && (user.getAge() < 0 || user.getAge() > 150)) {throw new IllegalArgumentException("Age must be between 0 and 150");}}private boolean isValidEmail(String email) {return email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");}
}

12.5 Controller 层

package com.example.controller;import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import javax.validation.Valid;
import java.util.List;
import java.util.Optional;@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "*")
public class UserController {@Autowiredprivate UserService userService;// 创建用户@PostMappingpublic ResponseEntity<User> createUser(@Valid @RequestBody User user) {try {User createdUser = userService.createUser(user);return new ResponseEntity<>(createdUser, HttpStatus.CREATED);} catch (IllegalArgumentException e) {return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);}}// 批量创建用户@PostMapping("/batch")public ResponseEntity<List<User>> createUsers(@Valid @RequestBody List<User> users) {try {List<User> createdUsers = userService.createUsers(users);return new ResponseEntity<>(createdUsers, HttpStatus.CREATED);} catch (IllegalArgumentException e) {return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);}}// 获取所有用户@GetMappingpublic ResponseEntity<List<User>> getAllUsers() {List<User> users = userService.getAllUsers();return new ResponseEntity<>(users, HttpStatus.OK);}// 分页获取用户@GetMapping("/page")public ResponseEntity<Page<User>> getUsersWithPagination(@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size,@RequestParam(defaultValue = "id") String sortBy,@RequestParam(defaultValue = "asc") String sortDir) {Page<User> users = userService.getUsersWithPagination(page, size, sortBy, sortDir);return new ResponseEntity<>(users, HttpStatus.OK);}// 根据ID获取用户@GetMapping("/{id}")public ResponseEntity<User> getUserById(@PathVariable String id) {Optional<User> user = userService.getUserById(id);return user.map(u -> new ResponseEntity<>(u, HttpStatus.OK)).orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));}// 根据邮箱获取用户@GetMapping("/email/{email}")public ResponseEntity<User> getUserByEmail(@PathVariable String email) {Optional<User> user = userService.getUserByEmail(email);return user.map(u -> new ResponseEntity<>(u, HttpStatus.OK)).orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));}// 条件查询@GetMapping("/age-range")public ResponseEntity<List<User>> getUsersByAgeRange(@RequestParam Integer minAge,@RequestParam Integer maxAge) {List<User> users = userService.getUsersByAgeRange(minAge, maxAge);return new ResponseEntity<>(users, HttpStatus.OK);}@GetMapping("/search")public ResponseEntity<List<User>> searchUsers(@RequestParam String keyword) {List<User> users = userService.searchUsersByName(keyword);return new ResponseEntity<>(users, HttpStatus.OK);}@GetMapping("/city/{city}")public ResponseEntity<List<User>> getUsersByCity(@PathVariable String city) {List<User> users = userService.getUsersByCity(city);return new ResponseEntity<>(users, HttpStatus.OK);}@GetMapping("/tag/{tag}")public ResponseEntity<List<User>> getUsersByTag(@PathVariable String tag) {List<User> users = userService.getUsersByTag(tag);return new ResponseEntity<>(users, HttpStatus.OK);}// 更新用户@PutMapping("/{id}")public ResponseEntity<User> updateUser(@PathVariable String id, @Valid @RequestBody User user) {try {User updatedUser = userService.updateUser(id, user);return new ResponseEntity<>(updatedUser, HttpStatus.OK);} catch (IllegalArgumentException e) {return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);}}// 删除用户@DeleteMapping("/{id}")public ResponseEntity<Void> deleteUser(@PathVariable String id) {boolean deleted = userService.deleteUser(id);return deleted ? new ResponseEntity<>(HttpStatus.NO_CONTENT) : new ResponseEntity<>(HttpStatus.NOT_FOUND);}// 统计信息@GetMapping("/count")public ResponseEntity<Long> getUserCount() {long count = userService.getUserCount();return new ResponseEntity<>(count, HttpStatus.OK);}@GetMapping("/statistics")public ResponseEntity<UserService.UserRepository.UserStatistics> getUserStatistics() {UserService.UserRepository.UserStatistics stats = userService.getUserStatistics();return new ResponseEntity<>(stats, HttpStatus.OK);}@GetMapping("/city-stats")public ResponseEntity<List<UserService.UserRepository.CityUserCount>> getCityStats() {List<UserService.UserRepository.CityUserCount> stats = userService.getUserCountByCity();return new ResponseEntity<>(stats, HttpStatus.OK);}
}

13. 最佳实践

13.1 性能优化

package com.example.optimization;import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import org.bson.Document;public class PerformanceOptimization {private final MongoCollection<Document> collection;public PerformanceOptimization(MongoCollection<Document> collection) {this.collection = collection;}// 1. 创建合适的索引public void createOptimizedIndexes() {// 单字段索引collection.createIndex(Indexes.ascending("email"));collection.createIndex(Indexes.ascending("age"));// 复合索引 - 注意字段顺序collection.createIndex(Indexes.compoundIndex(Indexes.ascending("age"),      // 选择性高的字段放前面Indexes.ascending("city"),Indexes.descending("createdAt")));// 文本索引collection.createIndex(Indexes.text("name"));// 部分索引 - 只索引满足条件的文档IndexOptions partialOptions = new IndexOptions().partialFilterExpression(new Document("age", new Document("$gte", 18)));collection.createIndex(Indexes.ascending("email"), partialOptions);}// 2. 查询优化示例public void optimizedQueries() {// 使用投影减少网络传输collection.find().projection(new Document("name", 1).append("email", 1)).forEach(doc -> System.out.println(doc.toJson()));// 使用 limit 限制结果集collection.find().limit(10).forEach(doc -> System.out.println(doc.toJson()));// 使用 hint 强制使用特定索引collection.find(new Document("age", new Document("$gte", 18))).hint(new Document("age", 1)).forEach(doc -> System.out.println(doc.toJson()));}// 3. 批量操作优化public void optimizedBulkOperations() {// 使用批量写入而不是多次单独写入// ... 批量操作代码}
}

13.2 错误处理和日志

package com.example.exception;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;@ControllerAdvice
public class GlobalExceptionHandler {private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);@ExceptionHandler(IllegalArgumentException.class)public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException e) {logger.warn("Invalid argument: {}", e.getMessage());return new ResponseEntity<>(new ErrorResponse("INVALID_ARGUMENT", e.getMessage()),HttpStatus.BAD_REQUEST);}@ExceptionHandler(RuntimeException.class)public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException e) {logger.error("Runtime exception occurred", e);return new ResponseEntity<>(new ErrorResponse("INTERNAL_ERROR", "An internal error occurred"),HttpStatus.INTERNAL_SERVER_ERROR);}public static class ErrorResponse {private String code;private String message;public ErrorResponse(String code, String message) {this.code = code;this.message = message;}// Getter 方法public String getCode() { return code; }public String getMessage() { return message; }}
}

13.3 主应用程序类

package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;@SpringBootApplication
@EnableMongoAuditing
public class MongoDBApplication {public static void main(String[] args) {SpringApplication.run(MongoDBApplication.class, args);System.out.println("MongoDB Spring Boot Application Started!");}
}

13.4 测试类示例

package com.example;import com.example.entity.User;
import com.example.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
@TestPropertySource(properties = {"spring.data.mongodb.database=test_db"
})
public class UserServiceTest {@Autowiredprivate UserService userService;@Testpublic void testCreateUser() {User user = new User("Test User", "test@example.com", 25);User createdUser = userService.createUser(user);assertNotNull(createdUser.getId());assertEquals("Test User", createdUser.getName());assertEquals("test@example.com", createdUser.getEmail());assertEquals(25, createdUser.getAge());}@Testpublic void testFindUserByEmail() {// 先创建一个用户User user = new User("Find Test", "findtest@example.com", 30);userService.createUser(user);// 然后查找var foundUser = userService.getUserByEmail("findtest@example.com");assertTrue(foundUser.isPresent());assertEquals("Find Test", foundUser.get().getName());}
}

这个完整指南涵盖了 MongoDB 与 Java 集成的所有重要方面,从基础安装配置到高级的聚合操作和 Spring Boot 集成。每个部分都包含详细的代码示例和解释,可以作为开发过程中的参考手册。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/91488.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/91488.shtml
英文地址,请注明出处:http://en.pswp.cn/web/91488.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Flutter3.8x】flutter从入门到实战基础教程(四):自定义实现一个自增的StatefulWidget组件

fluttet中实现一个自定义的StatefulWidget组件&#xff0c;可以在数据变化后&#xff0c;把最新的页面效果展示给客户 实现效果实现代码 pages文件夹下新加一个counter_page.dart文件 class CounterPage extends StatefulWidget {const CounterPage({super.key});overrideState…

[AI8051U入门第十三步]W5500实现MQTT通信

前言 学习目标: 1、学习MQTT协议 2、了解MQTT数据帧格式 3、自己编写MQTT程序 4、调试MQTT程序一、MQTT协议介绍 MQTT(Message Queuing Telemetry Transport) 是一种轻量级的 发布/订阅(Pub/Sub) 消息传输协议,专为 低带宽、高延迟或不可靠网络 环境设计,广泛应用于 物…

四、基于SpringBoot,MVC后端开发笔记

整合第三方技术&#xff1a; 1、整合Junit (1)名称&#xff1a;SpringBootTest (2)类型&#xff1b;测试类注解 (3)位置&#xff1a;测试类定义上方 (4)作用&#xff1a;设置Junit加载的SpringBoot启动类 (5)相关属性&#xff1a;classes&#xff1a;设置SpringBoot启动类 2、整…

深入讲讲异步FIFO

一、异步 FIFO 的基本概念1.1 定义与核心作用异步 FIFO&#xff08;Asynchronous FIFO&#xff09;是一种读写时钟完全独立的先进先出&#xff08;First-In-First-Out&#xff09;数据缓冲器&#xff0c;主要用于跨时钟域数据传输场景。在数字系统中&#xff0c;当两个模块工作…

linux81 shell通配符:[list],‘‘ ``““

shell 文件处理工具 grep 别名显示颜色 grep --colorauto ‘root’ passwd alias grep‘grep --colorauto’ vim /etc/bashrc alias grep‘grep --colorauto’ source /etc/bashrc [rootsamba tmp]# grep --colorauto root 2.txt root:x:0:0:root:/root:/bin/bash operator:x:1…

CMake、CMakeLists.txt 基础语法

前言 代码变成可执行文件&#xff0c;叫做编译&#xff08;compile&#xff09;&#xff1b;先编译这个&#xff0c;还是先编译那个&#xff08;即编译的安排&#xff09;&#xff0c;叫做构建&#xff08;build&#xff09;。CMake是最常用的构建工具&#xff0c;诞生于1977年…

《文明5》错误代码0xc0000142修复方法

只要是错误代码为0xc0000142&#xff1f;不管是哪种错误&#xff0c;都是一样的。 修复方法有很多&#xff0c;我先推荐个人认为比较好用的修复方法 方式一&#xff1a;第三方软件修复&#xff1a; 地址在这里获取&#xff1a;修复软件点这里 添加图片注释&#xff0c;不超过 …

【Java面试题】缓存穿透

什么是缓存穿透 缓存穿透是指当秒杀请求在Redis中未命中缓存时&#xff0c;系统会转而查询数据库。若数据库中也不存在该数据&#xff0c;大量此类请求将直接冲击数据库&#xff0c;造成数据库负载激增。解决方案 缓存空值 当我们查询数据库发现数据库当中也不存在该数据时&…

SpringBoot与Rust实战指南

基于Spring Boot和Rust的实用 以下是基于Spring Boot和Rust的实用示例,涵盖常见开发场景,分为Spring Boot(Java)和Rust两部分: Spring Boot 示例 RESTful API 开发 @RestController @RequestMapping("/api") public class UserController {@GetMapping("…

【世纪龙科技】汽车整车维护仿真教学软件-智构整车维护实训

在职业院校汽车专业实训教学中&#xff0c;"设备损耗大、操作风险高、场景覆盖有限"三大痛点长期制约着教学质量提升——传统实训车间里&#xff0c;学生接触实车的机会受限于车辆台套数与维护周期&#xff0c;复杂工位流程难以反复演练&#xff1b;高危操作环节&…

CMake set_source_files_properties使用解析

set_source_files_properties() 是 CMake 中用于精细化控制源文件属性的多功能命令。除了设置编译标志外&#xff0c;它还有许多其他重要用途。以下是全面的用法解析&#xff1a;一、核心功能分类 1. 编译控制 编译器选项&#xff1a;COMPILE_FLAGS / COMPILE_OPTIONSset_sourc…

雷达微多普勒特征代表运动中“事物”的运动部件。

雷达微多普勒特征代表运动中“事物”的运动部件。 即使一个人在椅子上来回摇晃&#xff0c;肉眼看来这个动作也很简单。但对雷达来说&#xff0c;这是微动作的丰富混合&#xff1a;移动膝盖和腿、摆动手臂&#xff0c;甚至是倾斜的椅子。所有这些都会产生独特但复杂的微多普勒特…

FreeRTOS硬件中断发生时的现场

在FreeRTOS中&#xff0c;当硬件中断发生时&#xff0c;当前正在运行的任务会立即被挂起&#xff0c;处理器会跳转到中断相关的中断服务程序中&#xff0c;在中断服务程序执行期间&#xff0c;遵循以下规则&#xff1a;1、中断独占CPU&#xff0c;ISR拥有最高的执行优先级&…

kotlin语法和特性分析

核心设计哲学&#xff1a; 简洁 (Concise): 减少样板代码&#xff08;如 getter/setter、类型推导&#xff09;&#xff0c;让代码表达更直接。安全 (Safe): 从语言层面设计来避免常见错误&#xff08;尤其是空指针异常&#xff09;。互操作性 (Interoperable): 与 Java 无缝集…

二进制数本身没有默认的有符号或无符号解释

文章目录1. ​**​硬件层面&#xff1a;CPU 不区分有符号/无符号​**​2. ​**​解释权在程序员手中​**​3. ​**​默认倾向性&#xff08;非绝对规则&#xff09;​**​4. ​**​如何避免混淆&#xff1f;​**​5. ​**​经典示例​**​总结1. **解释为无符号数&#xff08;U…

(AI) Server (Hardware) Architecture

Overview by Atlas T800 Just found a good product demo. from Huawei for its Atlas T800, here 计算产品3D展示 First turn off all modules and we can delve into how this server is organized. Core This is an AI server with 910B as its main feature, which is …

【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博评论数据可视化分析-用户评论词云图实现

大家好&#xff0c;我是java1234_小锋老师&#xff0c;最近写了一套【NLP舆情分析】基于python微博舆情分析可视化系统(flaskpandasecharts)视频教程&#xff0c;持续更新中&#xff0c;计划月底更新完&#xff0c;感谢支持。今天讲解微博评论数据可视化分析-用户评论词云图实现…

【Linux学习|黑马笔记|Day1】Linux初识、安装VMware Workstation、安装CentOS7、远程连接、虚拟机快照

Linux DAY1 前言 因为之前MySQL学到安装Linux版本的MySQL了&#xff0c;需要安装虚拟机等等&#xff0c;所以我打算先学完Linux的全部课程&#xff0c;期间继续学MySQL 文章目录Linux DAY1一.1&#xff09;操作系统概述2&#xff09;Linux初识3&#xff09;虚拟机4.1&#xff…

编程与数学 03-002 计算机网络 13_无线网络技术

编程与数学 03-002 计算机网络 13_无线网络技术一、无线网络的基本概念&#xff08;一&#xff09;无线通信的频段与标准&#xff08;二&#xff09;无线网络的优势与挑战二、无线局域网&#xff08;WLAN&#xff09;&#xff08;一&#xff09;802.11标准系列&#xff08;二&a…

肖特基二极管MBR0540T1G 安森美ON 低电压 高频率 集成电路IC 芯片

MBR0540T1G ON Semiconductor&#xff1a;超低VF肖特基二极管&#xff0c;重新定义电源效率&#xff01;&#x1f525; 一、产品简介 MBR0540T1G 是安森美&#xff08;ON Semiconductor&#xff09;推出的0.5A/40V肖特基势垒二极管&#xff0c;采用专利沟槽结构&#xff0c;专…