环境准备
在开始之前,请确保你已经准备好了以下环境:

- Java 开发环境: JDK 8 或更高版本。
- MongoDB 驱动: 将 MongoDB Java 驱动添加到你的项目中。
- Maven (
pom.xml):<dependency> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-sync</artifactId> <version>4.11.1</version> <!-- 请使用最新版本 --> </dependency> - Gradle (
build.gradle):implementation 'org.mongodb:mongodb-driver-sync:4.11.1' // 请使用最新版本
- Maven (
- 一个正在运行的 MongoDB 实例。
基础连接和操作
我们需要连接到 MongoDB 服务器,MongoDB Java 驱动推荐使用 MongoClient 来管理连接。
MongoClient 和 MongoDatabase
MongoClient 是连接到 MongoDB 的主要入口,它通常在整个应用程序的生命周期中是单例的。
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
public class MongoConnectionExample {
public static void main(String[] args) {
// 连接到 MongoDB 服务器,默认为 localhost:27017
String uri = "mongodb://localhost:27017";
try (MongoClient mongoClient = MongoClients.create(uri)) {
// 连接到指定的数据库,如果数据库不存在,MongoDB 会在第一次插入数据时自动创建
MongoDatabase database = mongoClient.getDatabase("myTestDB");
System.out.println("成功连接到数据库: " + database.getName());
// 获取一个集合 (Collection),类似于关系型数据库中的表
// 如果集合不存在,它也将在第一次插入数据时被创建
// database.getCollection("users");
} catch (Exception e) {
System.err.println("连接 MongoDB 失败: " + e.getMessage());
}
}
}
注意: MongoClient 实现了 AutoCloseable 接口,因此推荐使用 try-with-resources 语句来自动管理资源,确保连接被正确关闭。
核心查询操作
查询操作主要通过 collection.find() 方法完成,该方法返回一个 FindIterable<Document> 对象,你可以通过链式调用来添加查询条件、排序、限制等。

1 查询所有文档
find() 方法不带任何参数会返回集合中的所有文档。
import com.mongodb.client.*;
import org.bson.Document;
public class FindAllExample {
public static void main(String[] args) {
String uri = "mongodb://localhost:27017";
try (MongoClient mongoClient = MongoClients.create(uri)) {
MongoDatabase database = mongoClient.getDatabase("myTestDB");
MongoCollection<Document> collection = database.getCollection("users");
// 查询所有文档
// .find() 返回一个 FindIterable
// .forEach() 是一个便捷方法,用于迭代结果集
collection.find().forEach(document -> System.out.println(document.toJson()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
2 精确查询
使用 Filters 类(或 Document)来构建查询条件。
示例数据:
假设 users 集合中有如下文档:
{ "name": "Alice", "age": 30, "city": "New York" }
{ "name": "Bob", "age": 25, "city": "London" }
{ "name": "Charlie", "age": 35, "city": "New York" }
查询 city 为 "New York" 的所有用户:
import com.mongodb.client.*;
import org.bson.Document;
import static com.mongodb.client.model.Filters.*;
public class FindOneExample {
public static void main(String[] args) {
String uri = "mongodb://localhost:27017";
try (MongoClient mongoClient = MongoClients.create(uri)) {
MongoDatabase database = mongoClient.getDatabase("myTestDB");
MongoCollection<Document> collection = database.getCollection("users");
// 使用 Filters.eq 进行精确匹配
// .find() 返回 FindIterable,我们可以用 .first() 来获取第一个匹配的文档
Document user = collection.find(eq("city", "New York")).first();
if (user != null) {
System.out.println("找到用户: " + user.toJson());
} else {
System.out.println("未找到符合条件的用户。");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3 查询多个文档
如果你想获取所有匹配的文档,可以使用 forEach 或 into 方法。
// 使用 forEach 遍历
collection.find(eq("city", "New York")).forEach(doc -> System.out.println(doc.toJson()));
// 使用 into 将结果存入 List
List<Document> usersInNY = collection.find(eq("city", "New York")).into(new ArrayList<>());
System.out.println("找到 " + usersInNY.size() + " 个用户。");
4 复合查询
使用 Filters 类中的 and, or, gt (greater than), lt (less than) 等方法组合查询条件。
查询 city 为 "New York" 并且 age 大于 28 的用户:
import static com.mongodb.client.model.Filters.*;
// ...
// 复合查询
collection.find(and(
eq("city", "New York"),
gt("age", 28)
)).forEach(doc -> System.out.println(doc.toJson()));
查询 city 为 "London" 或者 age 小于 30 的用户:
// ...
// or 查询
collection.find(or(
eq("city", "London"),
lt("age", 30)
)).forEach(doc -> System.out.println(doc.toJson()));
5 投影
只返回文档中的特定字段,而不是整个文档。
查询 name 和 city,但不返回 _id:
// .projection() 用于指定返回的字段
// 1 表示包含,0 表示排除
// _id 默认是包含的,如果想排除,需要明确指定为 0
collection.find(eq("city", "New York"))
.projection(fields(include("name", "city"), excludeId())) // 或者 new Document("name", 1).append("city", 1)
.forEach(doc -> System.out.println(doc.toJson()));
输出可能如下:
{ "name": "Alice", "city": "New York" }
{ "name": "Charlie", "city": "New York" }
6 排序和分页
使用 .sort() 和 .limit() / .skip() 方法。
查询所有用户,按 age 降序排列,并跳过前 1 个,只取接下来的 2 个:
// .sort() 接收一个 Document,键为字段名,值为 1 (升序) 或 -1 (降序)
collection.find()
.sort(new Document("age", -1)) // 按 age 降序
.skip(1) // 跳过 1 个
.limit(2) // 只取 2 个
.forEach(doc -> System.out.println(doc.toJson()));
使用 POJO (Plain Old Java Object)
直接操作 Document 虽然灵活,但在大型项目中不够类型安全,推荐使用 POJO。
1 创建 POJO 类
// User.java
import org.bson.types.ObjectId;
import java.util.Objects;
public class User {
private ObjectId id;
private String name;
private int age;
private String city;
// Getters and Setters
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 int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", city='" + city + '\'' +
'}';
}
}
2 进行类型安全的查询
使用 collection.find(query, User.class)。
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
import org.bson.Document;
import org.bson.types.ObjectId;
public class PojoQueryExample {
public static void main(String[] args) {
String uri = "mongodb://localhost:27017";
try (MongoClient mongoClient = MongoClients.create(uri)) {
MongoDatabase database = mongoClient.getDatabase("myTestDB");
MongoCollection<User> collection = database.getCollection("users", User.class);
// 查询 city 为 "New York" 的所有用户,结果自动映射到 User 对象
collection.find(Filters.eq("city", "New York"))
.forEach(user -> System.out.println(user));
// 查询单个文档
User user = collection.find(Filters.eq("name", "Alice")).first();
System.out.println("查找到的 Alice: " + user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意: 要让 MongoDB 驱动能将 Document 转换为你的 POJO,POJO 必须有无参构造函数,并且字段名与文档中的键名一致(或者使用 @BsonProperty 注解来映射)。
更新和删除
1 更新
使用 updateOne (更新单个匹配的文档) 或 updateMany (更新所有匹配的文档)。
// ...
MongoCollection<Document> collection = database.getCollection("users");
// 将 name 为 "Bob" 的用户的 age 改为 26
UpdateResult updateResult = collection.updateOne(
eq("name", "Bob"),
new Document("$set", new Document("age", 26))
);
System.out.println("匹配的文档数: " + updateResult.getMatchedCount());
System.out.println("修改的文档数: " + updateResult.getModifiedCount());
$set: 如果字段不存在,则创建它;如果存在,则更新它。
$inc: 增加一个字段的数值。
// 将 Alice 的 age 增加 1
collection.updateOne(
eq("name", "Alice"),
new Document("$inc", new Document("age", 1))
);
2 删除
使用 deleteOne (删除单个匹配的文档) 或 deleteMany (删除所有匹配的文档)。
// ...
MongoCollection<Document> collection = database.getCollection("users");
// 删除所有 city 为 "London" 的用户
DeleteResult deleteResult = collection.deleteMany(eq("city", "London"));
System.out.println("删除的文档数: " + getDeletedCount());
// 删除 name 为 "Charlie" 的单个用户
collection.deleteOne(eq("name", "Charlie"));
异步操作 (推荐用于高性能应用)
现代驱动支持异步操作,可以避免阻塞线程,提高应用吞吐量,你需要使用 mongodb-driver-reactivestreams 依赖。
1 添加依赖
<!-- Maven -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-reactivestreams</artifactId>
<version>4.11.1</version> <!-- 使用与同步驱动一致的版本 -->
</dependency>
2 异步查询示例
异步操作返回 Publisher,你需要使用 Reactive Streams 的 API(如 subscribe)或与 Project Reactor/RxJava 等库集成。
import com.mongodb.client.result.*;
import com.mongodb.reactivestreams.client.*;
import org.bson.Document;
import static com.mongodb.client.model.Filters.*;
public class AsyncQueryExample {
public static void main(String[] args) {
String uri = "mongodb://localhost:27017";
// 创建异步客户端
MongoClient mongoClient = MongoClients.create(uri);
MongoDatabase database = mongoClient.getDatabase("myTestDB");
MongoCollection<Document> collection = database.getCollection("users");
// 异步查询
Publisher<Document> findPublisher = collection.find(eq("city", "New York"));
// 订阅发布者以处理结果
MongoCollection publisher = collection; // 为了编译通过,实际中需要转换
collection.find(eq("city", "New York")).subscribe(
// onNext: 当有文档到达时
document -> System.out.println("收到文档: " + document.toJson()),
// onError: 当发生错误时
throwable -> System.err.println("查询出错: " + throwable.getMessage()),
// onComplete: 当所有文档处理完成时
() -> System.out.println("查询完成。")
);
// 异步更新
collection.updateOne(eq("name", "Alice"), new Document("$set", new Document("age", 31))
.subscribe(
result -> System.out.println("更新成功,修改了 " + result.getModifiedCount() + " 个文档"),
throwable -> System.err.println("更新出错: " + throwable.getMessage())
);
// 注意:在主线程中,应用可能会在异步操作完成前就退出。
// 在实际应用中,你需要一个更健壮的生命周期管理机制。
// 这里为了演示,我们让主线程等待一下
try {
Thread.sleep(2000); // 简单等待,不推荐在生产环境中使用
} catch (InterruptedException e) {
e.printStackTrace();
}
mongoClient.close();
}
}
| 操作 | 同步 API (mongodb-driver-sync) |
异步 API (mongodb-driver-reactivestreams) |
|---|---|---|
| 连接 | MongoClients.create() |
MongoClients.create() |
| 获取集合 | database.getCollection("name", Pojo.class) |
database.getCollection("name", Pojo.class) |
| 查询 | collection.find(filter).forEach(...) |
collection.find(filter).subscribe(...) |
| 更新 | collection.updateOne(filter, update) |
collection.updateOne(filter, update).subscribe(...) |
| 删除 | collection.deleteOne(filter) |
collection.deleteOne(filter).subscribe(...) |
| 结果处理 | 阻塞式迭代 (forEach, first(), into) |
响应式订阅 (onNext, onError, onComplete) |
对于大多数新项目,推荐使用 POJO 进行类型安全的操作,如果你的应用需要处理高并发、低延迟的请求,异步操作是更好的选择,对于简单的脚本或小型应用,同步 API 已经足够强大和易用。
