MongoDB
MongoDB 是面向文档的 NoSQL 数据库,使用 BSON(二进制 JSON)格式存储数据。与关系型数据库不同,MongoDB 不要求预定义表结构(schema-less),同一个集合中的文档可以有不同的字段。
适用场景:内容管理系统(CMS)、日志存储与分析、用户画像与行为数据、物联网数据采集、需要快速迭代的产品原型。当数据结构频繁变化或需要存储嵌套文档时,MongoDB 比关系型数据库更灵活。
核心要点
面向文档的NoSQL数据库,使用BSON格式存储数据,支持灵活的数据模型
核心概念
| 概念 | 说明 |
|---|---|
| Document | 文档,MongoDB 的最小数据单元,类似于 JSON 对象 |
| Collection | 集合,多个文档组成,类似于关系型数据库的表 |
| Database | 数据库,集合的容器 |
数据类型
| 类型 | 说明 |
|---|---|
| String | 字符串 |
| Number | 数值(整数/浮点) |
| Boolean | 布尔值 |
| Array | 数组 |
| Object | 嵌套文档 |
| Null | 空值 |
| Date | 日期 |
| ObjectId | 对象 ID |
快速开始
Docker 启动
docker run -d --name mongodb \
-p 27017:27017 \
-v ~/mongo/data:/data/db \
mongo:latest基本操作
show dbs // 显示所有数据库
use mydb // 切换/创建数据库
show collections // 显示当前数据库的集合
db.createCollection("users") // 创建集合
db.users.drop() // 删除集合CRUD 操作
Create(插入)
// 插入单条
db.users.insertOne({
name: "张三",
age: 25,
email: "zhangsan@example.com",
skills: ["Java", "Python"],
createdAt: new Date()
})
// 插入多条
db.users.insertMany([
{ name: "李四", age: 30 },
{ name: "王五", age: 28 }
])Read(查询)
db.users.find() // 查询所有
db.users.find({ age: { $gte: 18 } }) // 条件查询
db.users.findOne({ name: "张三" }) // 查询单个
db.users.find({}, { name: 1, email: 1 }) // 投影
db.users.find().skip(10).limit(10) // 分页
db.users.find().sort({ age: -1 }) // 排序(-1降序,1升序)
db.users.countDocuments({ age: { $gte: 18 } }) // 统计
db.users.distinct("name") // 去重常用查询运算符
| 运算符 | 说明 | 示例 |
|---|---|---|
| $eq | 等于 | { age: { $eq: 20 } } |
| $ne | 不等于 | { age: { $ne: 20 } } |
| $gt | 大于 | { age: { $gt: 20 } } |
| $gte | 大于等于 | { age: { $gte: 20 } } |
| $lt | 小于 | { age: { $lt: 20 } } |
| $lte | 小于等于 | { age: { $lte: 20 } } |
| $in | 在数组中 | { age: { $in: [18, 20, 25] } } |
| $nin | 不在数组中 | { age: { $nin: [18, 20] } } |
| $and | 逻辑与 | { $and: [{ age: { $gt: 18 } }, { name: "张三" }] } |
| $or | 逻辑或 | { $or: [{ age: { $lt: 20 } }, { name: "张三" }] } |
| $exists | 字段存在 | { email: { $exists: true } } |
| $regex | 正则匹配 | { name: { $regex: "^张" } } |
Update(更新)
db.users.updateOne(
{ name: "张三" },
{ $set: { age: 26 } }
)
db.users.updateMany(
{ age: { $lt: 18 } },
{ $set: { status: "未成年" } }
)常用更新操作符:$set 更新字段、$inc 递增/递减、$push 添加到数组、$pull 从数组移除、$addToSet 添加到数组(不重复)。
Delete(删除)
db.users.deleteOne({ name: "张三" })
db.users.deleteMany({ age: { $lt: 18 } })
db.users.drop() // 删除集合
db.dropDatabase() // 删除数据库聚合管道
聚合管道用于复杂的数据处理:
db.orders.aggregate([
{ $match: { status: "completed" } }, // 筛选
{ $unwind: "$items" }, // 展开数组
{ $group: { // 分组聚合
_id: "$userId",
totalAmount: { $sum: "$items.price" },
orderCount: { $sum: 1 }
}},
{ $sort: { totalAmount: -1 } }, // 排序
{ $limit: 10 } // 限制数量
])常用聚合阶段:$match 筛选、$group 分组聚合、$sort 排序、$limit 限制数量、$skip 跳过、$unwind 展开数组、$project 投影、$lookup 左连接、$count 计数、$addFields 添加字段。
索引
创建索引
db.users.createIndex({ email: 1 }, { unique: true }) // 单字段索引
db.users.createIndex({ age: 1, name: 1 }) // 复合索引
db.users.createIndex({ skills: 1 }) // 多键索引(数组字段)
db.users.createIndex({ bio: "text" }) // 文本索引
db.users.getIndexes() // 查看索引
db.users.dropIndex("索引名") // 删除索引索引类型
| 类型 | 说明 |
|---|---|
| 单字段索引 | 在单个字段上创建 |
| 复合索引 | 在多个字段上创建 |
| 多键索引 | 在数组字段上创建 |
| 文本索引 | 全文搜索 |
| 2dsphere 索引 | 地理空间查询 |
Spring Boot 集成
Maven 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>配置
spring:
data:
mongodb:
uri: mongodb://localhost:27017/mydb实体类
@Document(collection = "users")
public class User {
@Id
private String id;
@Field("name")
private String name;
private Integer age;
private List<String> skills;
private Address address; // 嵌套文档
}
@Document
class Address {
private String city;
private String street;
}Repository
public interface UserRepository extends MongoRepository<User, String> {
User findByName(String name);
List<User> findByAgeBetween(Integer min, Integer max);
List<User> findByNameContaining(String keyword);
@Query("{ 'age': { $gte: ?0 } }")
List<User> findByAgeGreaterThan(Integer age);
}MongoTemplate
@Autowired
private MongoTemplate mongoTemplate;
// 插入
User user = new User("张三", 25);
mongoTemplate.insert(user);
// 查询
Query query = new Query(Criteria.where("age").gte(18));
List<User> users = mongoTemplate.find(query, User.class);
// 更新
Query query = new Query(Criteria.where("name").is("张三"));
Update update = new Update().set("age", 30);
mongoTemplate.updateFirst(query, update, User.class);常见问题
ObjectId 与自增主键
MongoDB 默认使用 ObjectId(12 字节,包含时间戳、机器 ID、进程 ID、计数器)作为 _id。ObjectId 是分布式的,无需协调即可全局唯一,但不如自增 ID 有序。高写入场景下,ObjectId 的单调递增特性有利于 B-Tree 索引性能。
内存不足
MongoDB 使用 WiredTiger 存储引擎,默认缓存大小为 (RAM - 1GB) / 2。使用 db.serverStatus().wiredTiger.cache 查看缓存使用情况,必要时调整 wiredTigerCacheSizeGB 参数。
慢查询排查
使用 db.setProfilingLevel(1, { slowms: 100 }) 开启慢查询日志,db.system.profile.find().sort({ts:-1}).limit(10) 查看最近的慢查询。确保常用查询字段已建立索引。