MongoDB 詳細用法與 Java 集成完整指南

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;專…