Java操作MongoDB完整API使用的实战指南
作者:WL_Aurora
一、前言
在之前的文章中,我们掌握了MongoDB的Shell命令行操作和文档关系建模。但在实际企业开发中,90%的场景是通过编程语言驱动来操作数据库。Java作为后端开发的主流语言,其MongoDB官方驱动(mongo-java-driver)提供了完整的CRUD、聚合、索引管理等功能。
本文将基于 MongoDB Java Driver 3.12.7,从零搭建Maven工程,完整演示连接数据库、操作集合、文档CRUD、条件查询、投影排序等核心API。所有代码均经过实测,可直接复制到项目中使用。
二、环境搭建
2.1 创建Maven工程
在 pom.xml 中添加依赖:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.7</version>
</dependency>版本说明:3.12.x 是MongoDB 3.x/4.x的兼容版本,生产环境稳定可靠。若使用MongoDB 4.4+,可升级至 4.x 驱动。
2.2 连接MongoDB
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoCollection;
import org.bson.Document;
public class MongoDBConnectionDemo {
public static void main(String[] args) {
// 方式一:简单连接(本地无认证)
MongoClient mongoClient = MongoClients.create("mongodb://127.0.0.1:27017");
// 方式二:带认证连接(生产环境必用)
// MongoClient mongoClient = MongoClients.create(
// "mongodb://username:password@host:27017/?authSource=admin"
// );
// 获取数据库(不存在则自动创建,首次写入时持久化)
MongoDatabase database = mongoClient.getDatabase("test");
// 获取集合(不存在则自动创建,首次写入时持久化)
MongoCollection<Document> collection = database.getCollection("teachers");
// 测试连接:获取第一个文档并打印JSON
Document firstDoc = collection.find().first();
if (firstDoc != null) {
System.out.println("连接成功,首个文档:" + firstDoc.toJson());
} else {
System.out.println("集合为空,连接成功");
}
// 关闭客户端(释放连接池资源)
mongoClient.close();
}
}
重要提示:MongoClients.create() 内部自带连接池管理,默认最大连接数100,无需手动维护连接池。务必在应用关闭时调用 mongoClient.close()。
三、集合操作API
集合是MongoDB中存储文档的容器,类似于MySQL中的表。Java驱动提供了丰富的集合管理API。
3.1 创建普通集合
import com.mongodb.client.MongoDatabase;
/**
* 创建普通集合(无大小限制,无校验规则)
* @param database MongoDatabase实例
* @param name 集合名称
*/
public void createCollection(MongoDatabase database, String name) {
database.createCollection(name);
System.out.println("集合 '" + name + "' 创建成功");
}
3.2 创建固定大小集合(Capped Collection)
固定大小集合适用于日志、缓存等场景,达到上限后自动覆盖最旧数据。
import com.mongodb.client.model.CreateCollectionOptions;
/**
* 创建固定大小的集合(Capped Collection)
* @param database MongoDatabase实例
* @param name 集合名称
* @param sizeBytes 集合最大大小(字节)
*/
public void createCappedCollection(MongoDatabase database, String name, long sizeBytes) {
CreateCollectionOptions options = new CreateCollectionOptions()
.capped(true)
.sizeInBytes(sizeBytes);
database.createCollection(name, options);
System.out.println("固定大小集合 '" + name + "' 创建成功,大小限制:" + sizeBytes + " bytes");
}
Capped Collection特性:
- 插入顺序与查询顺序一致(天然按时间排序)
- 达到size上限后自动删除最旧文档
- 不支持删除单个文档,只能整体删除集合
- 不支持分片
3.3 创建带校验规则的集合(Schema Validation)
MongoDB 3.2+支持在集合层面设置文档校验规则,确保插入的文档必须包含指定字段。
import com.mongodb.client.model.CreateCollectionOptions;
import com.mongodb.client.model.ValidationOptions;
import com.mongodb.client.model.Filters;
/**
* 创建带校验规则的集合
* 要求插入的文档必须包含 field1 或 field2 中的至少一个字段
* @param database MongoDatabase实例
* @param name 集合名称
* @param field1 必须存在的字段1
* @param field2 必须存在的字段2
*/
public void createCollectionWithValidation(
MongoDatabase database,
String name,
String field1,
String field2) {
// 设置校验规则:文档必须包含 field1 或 field2
ValidationOptions validationOptions = new ValidationOptions()
.validator(Filters.or(
Filters.exists(field1),
Filters.exists(field2)
))
.validationLevel(ValidationLevel.STRICT) // 严格校验:所有写入都校验
.validationAction(ValidationAction.ERROR); // 校验失败时抛出错误
CreateCollectionOptions options = new CreateCollectionOptions()
.validationOptions(validationOptions);
database.createCollection(name, options);
System.out.println("带校验集合 '" + name + "' 创建成功,要求包含字段:" + field1 + " 或 " + field2);
}
| 参数 | 可选值 | 说明 |
|---|---|---|
validationLevel | OFF / STRICT / MODERATE | 校验严格程度 |
validationAction | ERROR / WARN | 校验失败时的行为 |
3.4 获取与删除集合
import com.mongodb.client.MongoCollection;
import org.bson.Document;
/**
* 获取集合引用
*/
public MongoCollection<Document> getCollection(MongoDatabase database, String name) {
return database.getCollection(name);
}
/**
* 删除集合(危险操作!数据不可恢复)
*/
public void dropCollection(MongoDatabase database, String collectionName) {
MongoCollection<Document> collection = database.getCollection(collectionName);
collection.drop();
System.out.println("集合 '" + collectionName + "' 已删除");
}
四、文档CRUD操作
Document是MongoDB的核心数据单元,Java中对应 org.bson.Document 类。Document本质是一个 Map<String, Object>,BSON类型与Java类型的映射关系如下:
| BSON类型 | Java类型 | 示例 |
|---|---|---|
| String | String | "name": "张三" |
| Integer | Integer | "age": 20 |
| Double | Double | "score": 92.5 |
| Boolean | Boolean | "isVip": true |
| Date | Date | "createTime": new Date() |
| ObjectId | ObjectId | "_id": new ObjectId() |
| Array | List | "tags": Arrays.asList("A", "B") |
| Embedded Document | Document | "address": new Document("city", "北京") |
4.1 插入单个文档
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import java.util.Map;
/**
* 插入单个文档
* @param collection 集合引用
* @param data 键值对数据
*/
public void insertOne(MongoCollection<Document> collection, Map<String, Object> data) {
Document doc = new Document();
for (Map.Entry<String, Object> entry : data.entrySet()) {
doc.append(entry.getKey(), entry.getValue());
}
collection.insertOne(doc);
System.out.println("单条文档插入成功,_id: " + doc.getObjectId("_id"));
}
// 使用示例
public static void main(String[] args) {
MongoCollection<Document> students = database.getCollection("students");
Map<String, Object> studentData = Map.of(
"name", "张三",
"age", 20,
"major", "计算机科学",
"score", 88.5,
"address", new Document("province", "山西").append("city", "太原")
);
insertOne(students, studentData);
}
4.2 插入多个文档
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import java.util.Arrays;
import java.util.List;
/**
* 批量插入文档(性能最优方案)
* @param collection 集合引用
* @param documents 文档列表
*/
public void insertMany(MongoCollection<Document> collection, List<Document> documents) {
collection.insertMany(documents);
System.out.println("批量插入成功,共 " + documents.size() + " 条文档");
}
// 使用示例
public static void main(String[] args) {
MongoCollection<Document> students = database.getCollection("students");
List<Document> docs = Arrays.asList(
new Document("name", "李四").append("age", 21).append("score", 92.0),
new Document("name", "王五").append("age", 19).append("score", 85.0),
new Document("name", "赵六").append("age", 22).append("score", 90.0)
);
insertMany(students, docs);
}
性能提示:insertMany 将网络往返次数从N次降到1次,批量插入时务必使用此方法。
4.3 修改单个文档
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import org.bson.conversions.Bson;
/**
* 修改单个文档(updateOne)
* @param collection 集合引用
* @param filterField 查询条件字段
* @param filterValue 查询条件值
* @param updateField 更新字段
* @param updateValue 更新值
*/
public void updateOne(
MongoCollection<Document> collection,
String filterField, Object filterValue,
String updateField, Object updateValue) {
// 构建查询条件:Filters.eq 表示等于匹配
Bson filter = Filters.eq(filterField, filterValue);
// 构建更新操作:$set 修改字段值
Bson update = Updates.set(updateField, updateValue);
UpdateResult result = collection.updateOne(filter, update);
System.out.println("匹配文档数:" + result.getMatchedCount() +
",修改文档数:" + result.getModifiedCount());
}
// 使用示例:将name="张三"的score改为95
demo.updateOne(students, "name", "张三", "score", 95.0);
4.4 修改多个文档(批量更新)
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
/**
* 批量更新:给所有订单数量=100的订单增加100
*/
public void updateManyDemo(MongoCollection<Document> collection) {
// 查询条件:order_nums = 100
Bson filter = Filters.eq("order_nums", 100);
// 更新操作:$inc 自增100
Bson update = Updates.inc("order_nums", 100);
UpdateResult result = collection.updateMany(filter, update);
System.out.println("批量更新完成,修改文档数:" + result.getModifiedCount());
}
| 更新操作符 | Java API | 作用 |
|---|---|---|
$set | Updates.set(field, value) | 设置字段值 |
$unset | Updates.unset(field) | 删除字段 |
$inc | Updates.inc(field, n) | 数值自增n |
$mul | Updates.mul(field, n) | 数值自乘n |
$rename | Updates.rename(oldName, newName) | 重命名字段 |
$push | Updates.push(field, value) | 数组追加元素 |
$addToSet | Updates.addToSet(field, value) | 数组去重追加 |
$pull | Updates.pull(field, value) | 数组删除元素 |
4.5 删除文档
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
import org.bson.Document;
/**
* 删除单个文档
*/
public void deleteOne(MongoCollection<Document> collection, String field, Object value) {
DeleteResult result = collection.deleteOne(Filters.eq(field, value));
System.out.println("删除文档数:" + result.getDeletedCount());
}
/**
* 删除多个文档
*/
public void deleteMany(MongoCollection<Document> collection, String field, Object value) {
DeleteResult result = collection.deleteMany(Filters.eq(field, value));
System.out.println("批量删除文档数:" + result.getDeletedCount());
}
// 使用示例
deleteOne(orders, "order_id", "0003"); // 删除order_id=0003的订单
deleteMany(orders, "order_num", 100); // 删除所有order_num=100的订单
五、查询操作API
5.1 查询所有文档(游标遍历)
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import org.bson.Document;
/**
* 查询所有文档并遍历输出
*/
public void findAll(MongoCollection<Document> collection) {
// 获取游标(Cursor),类似JDBC的ResultSet
MongoCursor<Document> cursor = collection.find().iterator();
try {
while (cursor.hasNext()) {
Document doc = cursor.next();
System.out.println(doc.toJson());
}
} finally {
// 必须关闭游标,释放服务器端资源
cursor.close();
}
}
/**
* 查询前N条文档
*/
public void findTopN(MongoCollection<Document> collection, int n) {
MongoCursor<Document> cursor = collection.find().limit(n).iterator();
try {
while (cursor.hasNext()) {
System.out.println(cursor.next().toJson());
}
} finally {
cursor.close();
}
}
/**
* 查询第一条文档
*/
public void findFirst(MongoCollection<Document> collection) {
Document first = collection.find().first();
if (first != null) {
System.out.println("第一条:" + first.toJson());
}
}
5.2 条件查询(Filters类)
Filters 类提供了链式API,支持所有MongoDB查询操作符:
import com.mongodb.client.MongoCollection;
import com.mongodb.client.FindIterable;
import com.mongodb.client.model.Filters;
import org.bson.Document;
import org.bson.conversions.Bson;
/**
* 多条件查询示例:60 <= score < 80 且 address="山西"
*/
public void complexQuery(MongoCollection<Document> collection) {
// 方式一:使用原生Document构建查询条件(灵活但冗长)
FindIterable<Document> docs1 = collection.find(
new Document("score", new Document("$gte", 60).append("$lt", 80))
.append("address", "山西")
);
// 方式二:使用Filters链式API(推荐,代码可读性高)
Bson filter = Filters.and(
Filters.gte("score", 60), // score >= 60
Filters.lt("score", 80), // score < 80
Filters.eq("address", "山西") // address = "山西"
);
FindIterable<Document> docs2 = collection.find(filter);
// 遍历结果
for (Document doc : docs2) {
System.out.println(doc.toJson());
}
}
| Filters方法 | 对应操作符 | 示例 |
|---|---|---|
eq(field, value) | $eq | Filters.eq("name", "张三") |
ne(field, value) | $ne | Filters.ne("status", "deleted") |
gt(field, value) | $gt | Filters.gt("score", 80) |
gte(field, value) | $gte | Filters.gte("age", 18) |
lt(field, value) | $lt | Filters.lt("price", 100) |
lte(field, value) | $lte | Filters.lte("stock", 10) |
in(field, list) | $in | Filters.in("status", Arrays.asList("A", "B")) |
nin(field, list) | $nin | Filters.nin("role", Arrays.asList("guest")) |
exists(field, true) | $exists | Filters.exists("email", true) |
regex(field, pattern) | $regex | Filters.regex("name", "^张") |
and(filters...) | $and | Filters.and(cond1, cond2) |
or(filters...) | $or | Filters.or(cond1, cond2) |
not(filter) | $not | Filters.not(Filters.eq("status", "A")) |
5.3 投影(Projection)
投影用于控制查询结果中返回哪些字段,减少网络传输量。
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import org.bson.Document;
import org.bson.conversions.Bson;
/**
* 投影查询:只返回name、sex、age字段,不返回_id
*/
public void projectionQuery(MongoCollection<Document> collection) {
// 方式一:使用原生Document构建投影
collection.find(Filters.eq("name", "李大喜"))
.projection(new Document("name", 1)
.append("sex", 1)
.append("age", 1)
.append("_id", 0) // 0表示不显示
);
// 方式二:使用Projections工具类(推荐)
Bson projection = Projections.fields(
Projections.include("name", "sex", "age"), // 包含这些字段
Projections.excludeId() // 排除_id字段
);
collection.find(Filters.eq("name", "李大喜"))
.projection(projection)
.forEach(doc -> System.out.println(doc.toJson()));
}
| Projections方法 | 作用 |
|---|---|
include("f1", "f2") | 只返回指定字段(_id默认仍返回) |
exclude("f1", "f2") | 排除指定字段(其余都返回) |
excludeId() | 排除_id字段 |
fields(include, excludeId) | 组合使用 |
投影规则:不能同时混用 include 和 exclude(_id 除外)。要么指定要显示的字段,要么指定要隐藏的字段。
5.4 排序(Sorts类)
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Sorts;
import org.bson.Document;
/**
* 排序查询:先按age升序,age相同则按sal升序
*/
public void sortQuery(MongoCollection<Document> collection) {
collection.find(Filters.lt("age", 50)) // 查询age < 50的文档
.sort(Sorts.ascending("age", "sal")) // 多字段升序
.forEach(doc -> System.out.println(doc.toJson()));
}
/**
* 复合排序:age降序,sal升序
*/
public void compoundSort(MongoCollection<Document> collection) {
collection.find()
.sort(Sorts.orderBy(
Sorts.descending("age"), // age 降序
Sorts.ascending("sal") // sal 升序
))
.forEach(doc -> System.out.println(doc.toJson()));
}
| Sorts方法 | 含义 |
|---|---|
ascending("f1", "f2") | 按指定字段升序排列 |
descending("f1", "f2") | 按指定字段降序排列 |
orderBy(sort1, sort2) | 组合多个排序规则 |
六、分页查询实战
结合 skip、limit、sort 实现完整的分页功能:
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Sorts;
import org.bson.Document;
/**
* 分页查询工具方法
* @param collection 集合
* @param pageNum 页码(从1开始)
* @param pageSize 每页大小
* @return 当前页文档列表
*/
public List<Document> paginate(MongoCollection<Document> collection, int pageNum, int pageSize) {
int skip = (pageNum - 1) * pageSize;
List<Document> result = new ArrayList<>();
collection.find()
.sort(Sorts.descending("createTime")) // 按时间倒序
.skip(skip) // 跳过前N条
.limit(pageSize) // 取N条
.into(result);
return result;
}
/**
* 获取总页数
*/
public long getTotalPages(MongoCollection<Document> collection, int pageSize) {
long total = collection.countDocuments();
return (total + pageSize - 1) / pageSize;
}
// 使用示例
public static void main(String[] args) {
MongoCollection<Document> articles = database.getCollection("articles");
// 查询第2页,每页10条
List<Document> page2 = paginate(articles, 2, 10);
page2.forEach(doc -> System.out.println(doc.getString("title")));
System.out.println("总页数:" + getTotalPages(articles, 10));
}
性能提示:skip 在大数据量时性能较差(需要扫描跳过的文档)。生产环境建议:
- 使用范围分页:find({createTime: {$lt: lastTime}}).limit(10)
- 为排序字段创建索引
- 限制最大页码(如只允许查询前100页)
七、聚合查询入门
聚合管道是MongoDB最强大的查询功能,支持 $match、$group、$sort、$project 等阶段。
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Accumulators;
import com.mongodb.client.model.Filters;
import org.bson.Document;
import org.bson.conversions.Bson;
import java.util.Arrays;
import java.util.List;
/**
* 聚合查询:按部门统计平均工资和人数
*/
public void aggregateDemo(MongoCollection<Document> collection) {
List<Bson> pipeline = Arrays.asList(
// 阶段1:匹配条件(类似WHERE)
Aggregates.match(Filters.gte("sal", 1000)),
// 阶段2:按deptno分组(类似GROUP BY)
Aggregates.group("$deptno",
Accumulators.avg("avgSal", "$sal"), // 平均工资
Accumulators.sum("count", 1), // 人数
Accumulators.max("maxSal", "$sal") // 最高工资
),
// 阶段3:排序(类似ORDER BY)
Aggregates.sort(Sorts.descending("avgSal")),
// 阶段4:限制返回数量(类似LIMIT)
Aggregates.limit(10)
);
collection.aggregate(pipeline)
.forEach(doc -> System.out.println(doc.toJson()));
}
| Aggregates方法 | 对应管道阶段 | 作用 |
|---|---|---|
match(filter) | $match | 过滤文档 |
group(id, accumulators) | $group | 分组聚合 |
sort(order) | $sort | 排序 |
limit(n) | $limit | 限制数量 |
skip(n) | $skip | 跳过数量 |
project(fields) | $project | 投影字段 |
lookup(...) | $lookup | 左外连接(关联查询) |
unwind(field) | $unwind | 展开数组 |
八、完整工具类封装
将上述API封装为可复用的工具类:
import com.mongodb.client.*;
import com.mongodb.client.model.*;
import com.mongodb.client.result.*;
import org.bson.Document;
import org.bson.conversions.Bson;
import java.util.*;
public class MongoDBUtil {
private MongoClient client;
private MongoDatabase database;
public MongoDBUtil(String uri, String dbName) {
this.client = MongoClients.create(uri);
this.database = client.getDatabase(dbName);
}
// ==================== 集合操作 ====================
public void createCollection(String name) {
database.createCollection(name);
}
public void createCappedCollection(String name, long sizeBytes) {
database.createCollection(name,
new CreateCollectionOptions().capped(true).sizeInBytes(sizeBytes));
}
public MongoCollection<Document> getCollection(String name) {
return database.getCollection(name);
}
public void dropCollection(String name) {
database.getCollection(name).drop();
}
// ==================== 文档操作 ====================
public void insertOne(String collectionName, Map<String, Object> data) {
Document doc = new Document(data);
getCollection(collectionName).insertOne(doc);
}
public void insertMany(String collectionName, List<Document> docs) {
getCollection(collectionName).insertMany(docs);
}
public long updateOne(String coll, String field, Object val,
String upField, Object upVal) {
UpdateResult r = getCollection(coll).updateOne(
Filters.eq(field, val),
Updates.set(upField, upVal)
);
return r.getModifiedCount();
}
public long updateMany(String coll, Bson filter, Bson update) {
return getCollection(coll).updateMany(filter, update).getModifiedCount();
}
public long deleteOne(String coll, String field, Object val) {
return getCollection(coll).deleteOne(Filters.eq(field, val)).getDeletedCount();
}
public long deleteMany(String coll, Bson filter) {
return getCollection(coll).deleteMany(filter).getDeletedCount();
}
// ==================== 查询操作 ====================
public List<Document> findAll(String coll) {
return getCollection(coll).find().into(new ArrayList<>());
}
public List<Document> find(String coll, Bson filter) {
return getCollection(coll).find(filter).into(new ArrayList<>());
}
public List<Document> find(String coll, Bson filter, Bson projection) {
return getCollection(coll).find(filter).projection(projection).into(new ArrayList<>());
}
public List<Document> paginate(String coll, Bson filter,
String sortField, int pageNum, int pageSize) {
int skip = (pageNum - 1) * pageSize;
return getCollection(coll).find(filter)
.sort(Sorts.descending(sortField))
.skip(skip).limit(pageSize)
.into(new ArrayList<>());
}
public long count(String coll, Bson filter) {
return getCollection(coll).countDocuments(filter);
}
// ==================== 聚合操作 ====================
public List<Document> aggregate(String coll, List<Bson> pipeline) {
return getCollection(coll).aggregate(pipeline).into(new ArrayList<>());
}
// ==================== 资源释放 ====================
public void close() {
if (client != null) {
client.close();
}
}
}
总结
本文系统覆盖了Java操作MongoDB的核心API:
| 功能模块 | 核心类 | 关键方法 |
|---|---|---|
| 连接管理 | MongoClients | create(uri) |
| 集合操作 | MongoDatabase | createCollection(), getCollection(), drop() |
| 文档插入 | MongoCollection | insertOne(), insertMany() |
| 文档更新 | Updates | set(), inc(), unset(), push() |
| 文档删除 | MongoCollection | deleteOne(), deleteMany() |
| 条件查询 | Filters | eq(), gt(), lt(), and(), or() |
| 结果投影 | Projections | include(), exclude(), excludeId() |
| 结果排序 | Sorts | ascending(), descending(), orderBy() |
| 聚合管道 | Aggregates | match(), group(), sort(), limit() |
以上就是Java操作MongoDB完整API使用的实战指南的详细内容,更多关于Java操作MongoDB API使用的资料请关注脚本之家其它相关文章!
