跳转至

MongoDB 基础

参考文档: - MongoDB 官方手册 - MongoDB CRUD 操作 - MongoDB Shell (mongosh)


一、MongoDB 简介

MongoDB 是一个基于分布式文件存储的开源 NoSQL 数据库,使用 C++ 编写,数据存储为 BSON(Binary JSON)格式。

📖 MongoDB 官方手册

为什么选择 MongoDB

  • 灵活的 Schema:集合中的文档不需要有相同的字段结构
  • 类 JSON 格式:对前端/Node.js/Python 开发者友好
  • 原生支持分布式:副本集(高可用)+ 分片集群(水平扩展)
  • 丰富的查询能力:支持嵌套文档查询、数组查询、聚合管道

二、Docker 部署

📖 Docker 安装参考

# 拉取镜像
docker pull mongo:7.0

# 启动容器
docker run -d \
  --name mongodb \
  -p 27017:27017 \
  -v mongo_data:/data/db \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=admin123 \
  mongo:7.0 \
  --auth

# 进入 mongosh 交互模式
docker exec -it mongodb mongosh -u admin -p admin123 --authenticationDatabase admin

认证模式

加上 --auth 参数后,所有操作都需要认证。默认会创建 admin 数据库用于认证管理。


三、核心概念

📖 核心概念文档

3.1 术语对照

关系型数据库 MongoDB
数据库(Database) 数据库(Database)
表(Table) 集合(Collection)
行(Row) 文档(Document)
列(Column) 字段(Field)
主键(Primary Key) _id(自动生成 ObjectId)
索引(Index) 索引(Index)

3.2 数据库层次

Server(MongoDB 实例)
├── Database(数据库)
│   ├── Collection(集合)
│   │   ├── Document(文档)
│   │   │   ├── Field(字段): value
│   │   │   └── Field(字段): value
│   │   └── Document
│   └── Collection
└── Database

3.3 BSON 数据类型

📖 BSON 类型文档

类型 说明 示例
String UTF-8 字符串 "张三"
Number 整数 / 浮点数 25, 3.14
Boolean 布尔值 true, false
Array 数组 [1, 2, 3]
Object 嵌套文档 {name: "张三"}
ObjectId 12 字节唯一 ID ObjectId("507f1f...")
Date 日期时间 ISODate("2024-01-01")
null 空值 null

四、基础操作(CRUD)

4.1 插入文档

📖 插入文档官方教程

// 切换/创建数据库
use myblog

// 插入单条文档
db.users.insertOne({
    name: "张三",
    age: 25,
    email: "zhangsan@example.com",
    tags: ["Java", "Python"],
    createdAt: new Date()
})

// 插入多条文档
db.users.insertMany([
    { name: "李四", age: 28, email: "lisi@example.com" },
    { name: "王五", age: 30, email: "wangwu@example.com" },
    { name: "赵六", age: 22, email: "zhaoliu@example.com" }
])

隐式创建

MongoDB 不需要提前创建数据库或集合。第一次向某个集合插入文档时,数据库和集合会自动创建。

4.2 查询文档

📖 查询文档官方教程

// 查询所有文档
db.users.find()

// 条件查询
db.users.find({ age: 25 })

// 条件查询(格式化输出)
db.users.find({ age: { $gte: 25 } }).pretty()

常用查询操作符

操作符 含义 示例
$eq 等于 { age: { $eq: 25 } }
$ne 不等于 { age: { $ne: 25 } }
$gt 大于 { age: { $gt: 25 } }
$gte 大于等于 { age: { $gte: 25 } }
$lt 小于 { age: { $lt: 30 } }
$lte 小于等于 { age: { $lte: 30 } }
$in 在数组中 { age: { $in: [25, 28] } }
$nin 不在数组中 { age: { $nin: [25, 28] } }
$regex 正则匹配 { name: { $regex: "^张" } }
$exists 字段存在 { email: { $exists: true } }

逻辑操作符

// AND:逗号分隔即可
db.users.find({ age: { $gte: 25 }, name: "李四" })

// OR
db.users.find({ $or: [
    { age: { $lt: 23 } },
    { name: "赵六" }
]})

// AND + OR 混合
db.users.find({
    age: { $gte: 25 },
    $or: [
        { tags: "Java" },
        { tags: "Python" }
    ]
})

投影(选择返回字段)

// 只返回 name 和 age(排除 _id)
db.users.find({}, { name: 1, age: 1, _id: 0 })

排序、分页、计数

// 排序(1=升序,-1=降序)
db.users.find().sort({ age: -1 })

// 跳过 + 限制
db.users.find().sort({ age: -1 }).skip(0).limit(10)

// 统计数量
db.users.countDocuments({ age: { $gte: 25 } })

查询技巧

查询嵌套文档字段使用点号:db.users.find({ "address.city": "北京" })

4.3 更新文档

📖 更新文档官方教程

// 更新单条(第一个匹配项)
db.users.updateOne(
    { name: "张三" },
    { $set: { age: 26 } }
)

// 更新多条(所有匹配项)
db.users.updateMany(
    { age: { $lt: 25 } },
    { $set: { status: "junior" } }
)

// 替换整个文档(不包括 _id)
db.users.replaceOne(
    { name: "张三" },
    { name: "张三丰", age: 30, email: "new@example.com" }
)

常用更新操作符

操作符 含义
$set 设置字段值(字段不存在则新增)
$unset 删除字段
$inc 字段值增加
$push 向数组追加元素
$pull 从数组中删除元素
$rename 重命名字段
// 数组操作
db.users.updateOne(
    { name: "张三" },
    {
        $push: { tags: "Go" },      // 添加元素
        $pull: { tags: "Java" },    // 删除元素
        $inc:  { age: 1 }           // 年龄 +1
    }
)

4.4 删除文档

📖 删除文档官方教程

// 删除单条(第一个匹配项)
db.users.deleteOne({ name: "赵六" })

// 删除多条(所有匹配项)
db.users.deleteMany({ age: { $lt: 25 } })

// 删除集合中所有文档(保留索引)
db.users.deleteMany({})

// 删除整个集合(含索引)
db.users.drop()

五、索引基础

📖 索引官方文档

5.1 创建索引

// 单字段索引
db.users.createIndex({ name: 1 })  // 1=升序,-1=降序

// 复合索引
db.users.createIndex({ name: 1, age: -1 })

// 唯一索引
db.users.createIndex({ email: 1 }, { unique: true })

// TTL 索引(自动过期删除)
db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })

// 查看所有索引
db.users.getIndexes()

5.2 查看执行计划

// 分析查询是否走索引
db.users.find({ name: "张三" }).explain("executionStats")

索引优化

  • MongoDB 默认会为 _id 字段自动创建唯一索引
  • 复合索引同样遵循最左前缀原则
  • 索引不是越多越好,每次写入都需要更新索引树

六、与 Python 集成

📖 PyMongo 官方文档

pip install pymongo
from pymongo import MongoClient

# 1. 连接数据库
client = MongoClient("mongodb://admin:admin123@localhost:27017/")
db = client["myblog"]
users = db["users"]

# 2. 插入
users.insert_one({"name": "张三", "age": 25})
users.insert_many([
    {"name": "李四", "age": 28},
    {"name": "王五", "age": 30}
])

# 3. 查询
for user in users.find({"age": {"$gte": 25}}).sort("age", -1):
    print(user["name"], user["age"])

# 4. 更新
users.update_one({"name": "张三"}, {"$set": {"age": 26}})

# 5. 删除
users.delete_one({"name": "李四"})

连接字符串

认证模式下的连接格式:mongodb://用户名:密码@host:port/?authSource=admin