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", "[email protected]");  
// 插入单个文档,返回插入结果(含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 分钟前
[SpringMVC]上手案例
java·开发语言
九转苍翎14 分钟前
Java虚拟机——JVM(Java Virtual Machine)解析二
java·jvm
顾林海26 分钟前
深度解析LinkedHashMap工作原理
android·java·面试
一路向北he36 分钟前
杰理10k3950温度测量
java·数据结构·算法
K哥112537 分钟前
【多线程】线程池
java·开发语言·线程池
小奏技术38 分钟前
Cursor AI写码一月20美刀太贵?试试这套免费替代方案
aigc·openai·trae
LeicyII1 小时前
面试题:Eureka和Nocas的区别
java·云原生·eureka
SoFlu软件机器人1 小时前
高并发秒杀系统设计:关键技术解析与典型陷阱规避
java·人工智能
码农小站1 小时前
MyBatis-Plus 表字段策略详解:@TableField(updateStrategy) 的配置与使用指南
java·后端