MongoDB 增删改查:从青铜到王者的全攻略

各位 Java 搬砖人!今天咱们要潜入 MongoDB 的「数据魔法世界」,手把手教你用 Java 玩转这个「文档型数据库老司机」。从基础的增删改查(CRUD)到高阶的聚合索引,全程配段子手级解说,让你笑着学会硬核技术~

一、先盘门槛:连接 MongoDB 就像开房门

1. 引入依赖:给项目装上「魔法连接器」

如果你用 Maven,在pom.xml里加这段「开门咒语」:

xml 复制代码
<dependency>  
    <groupId>org.mongodb</groupId>  
    <artifactId>mongo-java-driver</artifactId>  
    <version>4.7.1</version> <!-- 最新稳定版,别用古董版本! -->  
</dependency>  

Gradle 用户直接甩锅给构建工具:

arduino 复制代码
implementation 'org.mongodb:mongo-java-driver:4.7.1'  

2. 建立连接:拿到数据库「金钥匙」

java 复制代码
import com.mongodb.client.MongoClients;  
import com.mongodb.client.MongoClient;  
import com.mongodb.client.MongoDatabase;  
public class MongoDemo {  
    public static void main(String[] args) {  
        // 连接本地数据库(默认端口27017),相当于MongoDB的默认连接地址  
        try (MongoClient client = MongoClients.create("mongodb://localhost:27017")) {  
            MongoDatabase db = client.getDatabase("blog_db"); // 创建/获取名为blog_db的数据库,对应Mongo Shell的use blog_db  
            System.out.println("成功闯入MongoDB魔法世界!");  
        }  
    }  
}  

👉 注意:用try-with-resources自动关闭连接,别学渣男用完不关门!

二、增(Create):召唤数据精灵的三种姿势

假设我们有个「用户集合」(相当于 MySQL 的表),文档结构类似:

json 复制代码
{ "name": "张三", "age": 18, "tags": ["Java", "MongoDB"] }  

1. 单例召唤:insertOne ()

go 复制代码
import org.bson.Document;  
import com.mongodb.client.MongoCollection;  
// 获取集合,没有就自动创建(比女朋友还懂事),对应Mongo Shell的db.users  
MongoCollection<Document> users = db.getCollection("users");  
// 创建文档,链式语法像搭积木  
Document user = new Document()  
    .append("name", "李四")  
    .append("age", 20)  
    .append("email", "lisi@example.com");  
// 插入单个文档,返回插入结果(含ObjectId),对应Mongo Shell的db.users.insertOne()  
users.insertOne(user);  
System.out.println("成功召唤单个数据精灵!");  

2. 批量召唤:insertMany ()

go 复制代码
List<Document> batchUsers = Arrays.asList(  
    new Document("name", "王五").append("age", 22),  
    new Document("name", "赵六").append("age", 24)  
);  
// 批量插入多个文档,对应Mongo Shell的db.users.insertMany()  
users.insertMany(batchUsers);  
System.out.println("批量召唤2个数据精灵,效率MAX!");  

3. 带 ID 召唤:自定义主键

go 复制代码
Document userWithId = new Document()  
    .append("_id", "user_001") // 手动设置ID,相当于Mongo Shell的指定_id字段  
    .append("name", "自定义ID用户");  
// 插入带自定义ID的文档,对应Mongo Shell的db.users.insertOne({_id: "user_001", name: "自定义ID用户"})  
users.insertOne(userWithId);  

👉 踩坑预警:如果重复插入相同_id,会抛DuplicateKeyException,比女朋友生气还可怕!

三、查(Read):把数据精灵翻个底朝天

1. 全查:掀翻整个精灵窝

javascript 复制代码
// 简单粗暴查所有,返回可迭代对象,对应Mongo Shell的db.users.find()  
users.find().forEach(document -> System.out.println("查到:" + document));  

👉 性能警告:数据量大时别这么干,相当于让数据库「把仓库所有箱子搬出来」,容易累趴!

2. 条件查询:精准狙击目标精灵

用Filters工具类写查询条件,支持各种神奇操作:

perl 复制代码
import static com.mongodb.client.model.Filters.*;  
// 查年龄>20的用户,对应Mongo Shell的db.users.find({age: {$gt: 20}})  
users.find(gt("age", 20)).forEach(doc -> System.out.println("大龄青年:" + doc));  
// 查名字包含"王"且年龄<25(相当于SQL的AND),对应db.users.find({name: "王五", age: {$lt: 25}})  
users.find(and(eq("name", "王五"), lt("age", 25))).forEach(...);  
// 查标签包含"Java"(数组字段查询,MongoDB强项!),对应db.users.find({tags: "Java"})  
users.find(eq("tags", "Java")).forEach(...);  

3. 投影:只看精灵的特定部位

比如只查name和age,忽略其他字段(相当于 SQL 的 SELECT):

scss 复制代码
import static com.mongodb.client.model.Projections.*;  
// 包含指定字段,对应Mongo Shell的db.users.find({}, {name: 1, age: 1})  
Document projection = include("name", "age");  
users.find().projection(projection).forEach(doc -> System.out.println(doc));  
// 排除某个字段(比如不查_id),对应db.users.find({}, {_id: 0})  
Document excludeId = exclude("_id");  
users.find().projection(excludeId).forEach(...);  

4. 排序 & 分页:让精灵排队站好

scss 复制代码
import static com.mongodb.client.model.Sorts.*;  
// 按年龄降序排列(找最老的用户),对应db.users.find().sort({age: -1})  
users.find().sort(descending("age")).forEach(...);  
// 分页查询,跳过前2条,取3条(相当于limit和offset),对应db.users.find().skip(2).limit(3)  
users.find().skip(2).limit(3).forEach(...);  

四、改(Update):给数据精灵「整活」

1. 单例改造:updateOne ()

perl 复制代码
import static com.mongodb.client.model.Updates.*;  
// 把李四的年龄改成21岁(精准匹配name),对应db.users.updateOne({name: "李四"}, {$set: {age: 21}})  
users.updateOne(eq("name", "李四"), set("age", 21));  
// 给所有Java用户加个"资深"标签(数组追加操作),对应db.users.updateMany({tags: "Java"}, {$addToSet: {tags: "资深"}})  
users.updateMany(eq("tags", "Java"), addToSet("tags", "资深"));  

2. 数值魔法:inc () 函数

perl 复制代码
// 给所有用户年龄+1(生日批量庆祝),对应db.users.updateMany({}, {$inc: {age: 1}})  
users.updateMany(new Document(), inc("age", 1));  
// 消费金额扣减(负数操作,相当于SQL的UPDATE SET balance = balance - 100),对应db.users.updateOne({name: "张三"}, {$inc: {balance: -100}})  
users.updateOne(eq("name", "张三"), inc("balance", -100));  

3. 复杂改造:替换整个文档

go 复制代码
// 把王五的信息彻底改头换面(注意:会覆盖原有文档!),对应db.users.replaceOne({name: "王五"}, newDoc)  
Document newInfo = new Document("name", "王五").append("age", 25).append("job", "程序员");  
users.replaceOne(eq("name", "王五"), newInfo);  

👉 灵魂拷问:updateOne和replaceOne的区别?前者改部分字段,后者直接换整个文档,别搞混!

五、删(Delete):送数据精灵「毕业」

1. 单例驱逐:deleteOne ()

perl 复制代码
// 删光赵六的痕迹(精准打击),对应db.users.deleteOne({name: "赵六"})  
users.deleteOne(eq("name", "赵六"));  
// 删光所有年龄<18的用户(未成年人保护法),对应db.users.deleteMany({age: {$lte: 18}})  
users.deleteMany(lte("age", 18));  

2. 清空集合:删到只剩裤衩

arduino 复制代码
// 危险操作!清空整个集合(比清空购物车还爽),对应db.users.deleteMany({})  
users.deleteMany(new Document()); // 条件为空,删所有  

👉 保命提示:生产环境千万别直接用deleteMany()不加条件,删库跑路警告!

六、高阶玩法:让 MongoDB 飞起来

1. 聚合管道:数据精灵的流水线作业

比如统计各年龄段用户数量(相当于 SQL 的 GROUP BY):

less 复制代码
import com.mongodb.client.AggregateIterable;  
import static com.mongodb.client.model.Aggregates.*;  
import static com.mongodb.client.model.Accumulators.*;  
// 按age分组统计数量并排序,对应Mongo Shell的db.users.aggregate([{$group: {_id: "$age", count: {$sum: 1}}}, {$sort: {count: -1}}])  
AggregateIterable<Document> result = users.aggregate(Arrays.asList(  
    group("$age", sum("count", 1)), // 按age分组,统计每组数量  
    sort(descending("count")) // 按数量降序排列  
));  
result.forEach(doc -> System.out.println("年龄" + doc.get("_id") + "有" + doc.get("count") + "人"));  

聚合管道支持 <math xmlns="http://www.w3.org/1998/Math/MathML"> m a t c h (过滤)、 match(过滤)、 </math>match(过滤)、lookup(联表查询)等骚操作,能玩出花来!

2. 索引:给数据精灵装 GPS

创建索引能让查询速度起飞,比如给name字段建索引:

csharp 复制代码
import static com.mongodb.client.model.Indexes.ascending;  
// 创建升序索引,对应Mongo Shell的db.users.createIndex({name: 1})  
users.createIndex(ascending("name"));  
// 创建唯一索引(防止重复数据),对应db.users.createIndex({email: 1}, {unique: true})  
users.createIndex(ascending("email"), new IndexOptions().unique(true));  

👉 索引原则:常用查询字段必建索引,不常用的别乱建,否则会拖慢写入速度!

3. 嵌套文档:处理精灵家族

假设用户文档里有嵌套的地址信息:

json 复制代码
{  
    "name": "张三",  
    "address": { "city": "北京", "district": "海淀" }  
}  

查询嵌套字段只需用点号语法:

perl 复制代码
// 查海淀区的用户,对应db.users.find({address.district: "海淀"})  
users.find(eq("address.district", "海淀")).forEach(...);  
// 更新嵌套字段:把张三的区改成朝阳,对应db.users.updateOne({name: "张三"}, {$set: {address.district: "朝阳"}})  
users.updateOne(eq("name", "张三"), set("address.district", "朝阳"));  

七、避坑指南:别在 MongoDB 里踩雷

  1. 类型问题:文档字段类型不固定,但查询时要严格匹配(比如数字和字符串别搞混)
  1. 主键坑:_id默认是ObjectId类型,手动设置时别用重复值
  1. 大文档陷阱:单个文档最大 16MB,别把整个 Excel 塞进去
  1. 索引滥用:不是所有字段都要建索引,多了会影响写入性能

八、总结:MongoDB 到底适合啥场景?

  • 优点:灵活的文档结构(适合数据变化快的场景)、高性能查询(配合索引)、天生支持分布式
  • 缺点:不支持强事务(复杂事务别用)、学习曲线比 MySQL 陡一丢丢

最后送大家一句口诀:增删改查用 CRUD,复杂操作靠聚合;索引建对快如飞,嵌套文档别搞糊!

赶紧去你的项目里试试吧,记得在评论区分享你的踩坑故事~ 要是觉得有用,点赞转发走一波,咱们下期聊聊 MongoDB 分布式集群的那些事儿!

相关推荐
李慕婉学姐7 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
效率客栈老秦8 小时前
Python Trae提示词开发实战(8):数据采集与清洗一体化方案让效率提升10倍
人工智能·python·ai·提示词·trae
奋进的芋圆8 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin9 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model20059 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉9 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国9 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_941882489 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈10 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_9910 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc