MongoDB基本使用(包含工具类)
示例代码
zr/MongoDemo
✅ 1. MongoDB 概述
🔷1.1 MongoDB 是什么?
- 文档数据库(Document DB)
 - 数据以 BSON 格式存储(类似 JSON)
 - 每条数据叫 document
 - 多条 document 存储在 collection
 - 多个 collection 组成 database
 
🔷1.2 与 MySQL 的对比
| MySQL | MongoDB | 
|---|---|
| 关系型表结构 | 无固定 schema | 
| 强类型 | 弱结构,字段可变 | 
| JOIN 多 | 无 JOIN,需要聚合 | 
| 行式存储 | 文档存储(嵌套结构) | 
| 适合强一致 | 适合灵活可扩展场景 | 
🔷1.3 文档示例
{"_id": "123","name": "eric","tags": ["dev", "java"],"address": {"city": "shanghai","code": 200000}
}
 
✅ 2. Docker 启动 MongoDB
🔷2.1 拉取镜像
docker pull mongo:7.0
 

🔷2.2 启动单节点 MongoDB(开发环境)
docker run -d \--name mongodb \-p 27017:27017 \-e MONGO_INITDB_ROOT_USERNAME=admin \-e MONGO_INITDB_ROOT_PASSWORD=123456 \mongo:7.0
 

🔷2.3 使用图形化界面(强烈推荐)
✅ 方案 1:直接下载安装(最推荐,官方方式)
官网下载:
 https://www.mongodb.com/products/tools/compass



✅ 方案 2:当然,用navicat连接也是可以(个人推荐)

✅ 3. Spring Boot 使用 MongoDB

🔷3.1 添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope>
</dependency>
<dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.59</version>
</dependency>
 

🔷3.2 配置 application.yml
spring:data:mongodb:uri: mongodb://admin:123456@localhost:27017/test?authSource=admin
 

🔷3.3 创建实体
@Data
@Document("user")
public class User {@Idprivate String id;private String name;private int age;
}
 
🔥3.4 对mongo进行操作
🔹3.4.1 对比
MongoRepository = 简单 CRUD 自动化,像 JPA
 MongoTemplate = 灵活强大、复杂查询必用,像 MyBatis
| 特性 | MongoRepository | MongoTemplate | 
|---|---|---|
| 编程风格 | 声明式(接口) | 命令式(代码) | 
| 上手难度 | 极低 | 较高 | 
| CRUD 能力 | 简单 CRUD 自动生成 | CRUD 全手写 | 
| 复杂查询 | 能力弱(QueryDSL 才稍强) | 能力最强(支持聚合、管道等) | 
| 聚合操作(Aggregation) | 不支持 | ✅ 支持 | 
| 多条件动态查询 | 不方便 | ✅ 最适合 | 
| 分页排序 | 简单支持 | ✅ 全支持 | 
| 事务控制 | 支持 | 支持 | 
| 适合场景 | 普通 CRUD、快速开发 | 高级查询、复杂条件、聚合分析 | 
🔹3.4.1 Repository 使用方式(最简单)
- 继承MongoRepository
 
  public interface UserRepository extends MongoRepository<User, String> {List<User> findByName(String name);}
 
- 编写UserService
 
package com.zr.mongodemo.service;import com.zr.mongodemo.entity.User;
import com.zr.mongodemo.repository.UserRepository;
import org.springframework.stereotype.Service;import java.util.List;/*** @Author: zr* @Date: 2025/11/03/13:59* @Description:*/
@Service
public class UserService {private final UserRepository repo;public UserService(UserRepository repo) {this.repo = repo;}public User create(User user) {return repo.save(user);}public User get(String id) {return repo.findById(id).orElse(null);}public List<User> list() {return repo.findAll();}public User update(User user) {return repo.save(user);   // save = insert or update}public void delete(String id) {repo.deleteById(id);}
}
 
- 编写测试类
 
package com.zr.mongodemo;import com.alibaba.fastjson2.JSON;
import com.zr.mongodemo.entity.User;
import com.zr.mongodemo.repository.UserRepository;
import com.zr.mongodemo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest
@Slf4j
class MongoDemoApplicationTests {@Autowiredprivate UserService userService;@Testvoid create() {User user = new User();user.setId("2");user.setName("zr2");user.setAge(19);userService.create(user);}@Testvoid list() {List<User> list = userService.list();log.info("list: {}", JSON.toJSONString(list));}@Testvoid get() {User user = userService.get("1");log.info("user: {}", JSON.toJSONString(user));}@Testvoid update() {User user = new User();user.setId("1");user.setAge(20);userService.update(user);}@Testvoid delete() {userService.delete("1");}} 
3.1 测试新增


可以看到新增了一条数据

3.2 测试列表查询

可以看到返回了多条数据

3.3 测试id获取

可以看到返回了对应id的数据

3.4 测试更新
此处发现一个问题,没有设置的字段会被清空


3.4.1 只更新不为空的字段
回滚数据

创建MongoUpdateUtil使用反射的方式,只对每个非空字段做赋值处理
package com.zr.mongodemo.util;import org.springframework.data.mongodb.core.query.Update;import java.lang.reflect.Field;/*** @Author: zr* @Date: 2025/11/03/14:44* @Description:*/
public class MongoUpdateUtil {public static Update convertToUpdate(Object obj) {Update update = new Update();Field[] fields = obj.getClass().getDeclaredFields();for (Field field : fields) {field.setAccessible(true);try {Object value = field.get(obj);// 跳过 id,跳过 nullif (value != null && !"id".equals(field.getName())) {update.set(field.getName(), value);}} catch (IllegalAccessException e) {throw new RuntimeException(e);}}return update;}
} 
此处还是用到了mongoTemplate
    public void update2(User user) {Query query = Query.query(Criteria.where("_id").is(user.getId()));Update update = MongoUpdateUtil.convertToUpdate(user);mongoTemplate.updateFirst(query, update, User.class);}
 
修改id为1的年龄为20

可以看到没有更新的字段没有被清空,需要更新的字段也更新了

3.5 删除

可以看到对应数据被删除了

🔹3.4.2 Template 使用方式(更灵活)
@Autowired
MongoTemplate mongoTemplate;public User save(User user) {
return mongoTemplate.save(user);
}
 
工具类对mongo进行操作
package com.zr.mongodemo.util;import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;import org.springframework.data.mongodb.core.query.Update;import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;/*** @Author: zr* @Date: 2025/11/03/15:06* @Description:*/
public class MongoTemplateUtil {private final MongoTemplate mongoTemplate;public MongoTemplateUtil(MongoTemplate mongoTemplate) {this.mongoTemplate = mongoTemplate;}// ✅ 插入public <T> T insert(T obj) {return mongoTemplate.insert(obj);}// ✅ 根据 ID 查询public <T> T findById(String id, Class<T> clazz) {return mongoTemplate.findById(id, clazz);}// ✅ 查询所有public <T> List<T> findAll(Class<T> clazz) {return mongoTemplate.findAll(clazz);}// ✅ 单字段查询public <T> List<T> findByField(String field, Object value, Class<T> clazz) {Query query = Query.query(Criteria.where(field).is(value));return mongoTemplate.find(query, clazz);}// ✅ 多条件精确查询public <T> List<T> findByFields(Map<String, Object> map, Class<T> clazz) {Query query = new Query();map.forEach((k, v) -> query.addCriteria(Criteria.where(k).is(v)));return mongoTemplate.find(query, clazz);}// ✅ 分页查询 + 排序public <T> List<T> findPage(Query query, int page, int size, String sortField, boolean asc, Class<T> clazz) {if (sortField != null) {query.with(Sort.by(asc ? Sort.Direction.ASC : Sort.Direction.DESC, sortField));}query.skip((long) (page - 1) * size);query.limit(size);return mongoTemplate.find(query, clazz);}// ✅ 获取数量public long count(Query query, Class<?> clazz) {return mongoTemplate.count(query, clazz);}// ✅ 删除public void deleteById(String id, Class<?> clazz) {Query query = Query.query(Criteria.where("_id").is(id));mongoTemplate.remove(query, clazz);}// ✅ 按条件批量删除public void deleteByFields(Map<String, Object> map, Class<?> clazz) {Query query = new Query();map.forEach((k, v) -> query.addCriteria(new Criteria(k).is(v)));mongoTemplate.remove(query, clazz);}// ✅ ✅ 动态局部更新(自动忽略 null 字段)public <T> void updatePartialById(T obj) {try {Field idField = obj.getClass().getDeclaredField("id");idField.setAccessible(true);Object idValue = idField.get(obj);if (idValue == null) {throw new RuntimeException("id 不能为空");}Query query = Query.query(Criteria.where("_id").is(idValue));Update update = buildDynamicUpdate(obj);mongoTemplate.updateFirst(query, update, obj.getClass());} catch (Exception e) {throw new RuntimeException(e);}}// ✅ 核心:构建动态 Update,只更新非 null 字段private <T> Update buildDynamicUpdate(T obj) {Update update = new Update();Field[] fields = obj.getClass().getDeclaredFields();for (Field f : fields) {f.setAccessible(true);try {Object value = f.get(obj);String fieldName = f.getName();if ("id".equals(fieldName) || value == null) {continue;}update.set(fieldName, value);} catch (Exception e) {throw new RuntimeException(e);}}return update;}// ✅ 条件更新(多条件 WHERE)public <T> void updatePartialByQuery(Query query, T obj, Class<T> clazz) {Update update = buildDynamicUpdate(obj);mongoTemplate.updateMulti(query, update, clazz);}
} 
该工具类支持的能力
| 功能 | 方法 | 
|---|---|
| 新增 | insert(obj) | 
| 根据 ID 查询 | findById(id) | 
| 全查询 | findAll() | 
| 单字段查询 | findByField() | 
| 多字段查询 | findByFields() | 
| 分页 | findPage() | 
| 获取数量 | count() | 
| 删除 ID | deleteById() | 
| 条件批量删除 | deleteByFields() | 
| ✅ 动态局部更新(自动忽略 null) | updatePartialById() | 
| ✅ 条件更新 | updatePartialByQuery() | 
使用示例
package com.zr.mongodemo.service;import com.zr.mongodemo.entity.User;
import com.zr.mongodemo.repository.UserRepository;
import com.zr.mongodemo.util.MongoTemplateUtil;
import com.zr.mongodemo.util.MongoUpdateUtil;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;import java.util.List;/*** @Author: zr* @Date: 2025/11/03/13:59* @Description:*/
@Service
public class UserServiceTemplate {private final MongoTemplateUtil mongoUtils;@Autowiredpublic UserServiceTemplate(MongoTemplate mongoTemplate) {this.mongoUtils = new MongoTemplateUtil(mongoTemplate);}public void add(User user) {mongoUtils.insert(user);}public User get(String id) {return mongoUtils.findById(id, User.class);}public void update(User user) {mongoUtils.updatePartialById(user); // ✅ 动态局部更新}public void delete(String id) {mongoUtils.deleteById(id, User.class);}public List<User> list() {return mongoUtils.findAll(User.class);}
}
 
✅ 4. 高级用法(非常实用)
🔶4.1 建索引
@Document("user")
public class User {@Indexedprivate String name;
}
 
🔶4.2 聚合查询(类似 SQL group by)
Aggregation agg = Aggregation.newAggregation(Aggregation.group("age").count().as("count")
);List<Document> result = mongoTemplate.aggregate(agg, "user", Document.class).getMappedResults();
 
🔶4.3 分页查询
Query query = new Query().limit(10).skip(20);
List<User> list = mongoTemplate.find(query, User.class);
 
✅ 5. Docker Compose 部署 MongoDB 副本集(生产环境)
当你需要:
 ✔ 数据高可用
 ✔ 支持事务
 ✔ 副本集复制
使用下面配置:
🔶docker-compose.yml
version: "3"
services:mongo1:image: mongo:7.0container_name: mongo1ports:- "27017:27017"environment:- MONGO_INITDB_ROOT_USERNAME=admin- MONGO_INITDB_ROOT_PASSWORD=123456- TZ=Asia/Shanghaicommand: ["--replSet", "rs0"]mongo2:image: mongo:7.0container_name: mongo2environment:- MONGO_INITDB_ROOT_USERNAME=admin- MONGO_INITDB_ROOT_PASSWORD=123456command: ["--replSet", "rs0"]mongo3:image: mongo:7.0container_name: mongo3environment:- MONGO_INITDB_ROOT_USERNAME=admin- MONGO_INITDB_ROOT_PASSWORD=123456command: ["--replSet", "rs0"]
 
✅ 6. 常见错误与解决方案
❗ Invalid BSON field name
出现:
Invalid BSON field name
 
原因:
 ✅ MongoDB key 不能包含以下字符:
".""$"
比如错误例子:
{"status.pass": "ok"  // 错误
}
 
解决方式:
- 替换 “.” → “_”
 - 使用 @Field 映射
 - 复杂结构用 Document 包装
 
