概览
MongoDB 是全球最流行的NoSQL 文档数据库,由 MongoDB Inc. 于 2009 年发布。它以灵活的 JSON/BSON 文档模型替代传统行列表结构,无需预定义 Schema,特别适合快速迭代的 Web 应用、实时分析、内容管理和微服务架构。支持水平扩展(分片)、高可用副本集、聚合管道和强大的查询语言,是 MEAN/MERN 技术栈的核心组件。
MongoDB 是全球最流行的NoSQL 文档数据库,由 MongoDB Inc. 于 2009 年发布。它以灵活的 JSON/BSON 文档模型替代传统行列表结构,无需预定义 Schema,特别适合快速迭代的 Web 应用、实时分析、内容管理和微服务架构。支持水平扩展(分片)、高可用副本集、聚合管道和强大的查询语言,是 MEAN/MERN 技术栈的核心组件。
# 导入公钥
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \
sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg
# 添加源
echo "deb [signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg] \
https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | \
sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sudo apt update
sudo apt install mongodb-org -y
sudo systemctl start mongod
sudo systemctl enable mongod
brew tap mongodb/brew
brew install mongodb-community@7.0
brew services start mongodb-community@7.0
choco install mongodb
# 或下载 MSI:https://www.mongodb.com/try/download/community
docker run --name mongo-dev \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=admin123 \
-p 27017:27017 -v ~/mongo-data:/data/db \
-d mongo:7
mongosh
# 或
docker exec -it mongo-dev mongosh -u admin -p admin123
Q: MongoDB 连接被拒绝
sudo systemctl status mongod
# 检查是否运行。如启动失败查看日志:
sudo journalctl -u mongod --no-pager -n 50
Q: Apple Silicon (M1/M2/M3) 兼容性
推荐使用 Docker:
docker run --platform linux/amd64 -d --name mongo-dev \
-p 27017:27017 mongo:7
Q: 认证失败
首次安装默认无认证。启用认证需在 /etc/mongod.conf 中:
security:
authorization: enabled
然后创建管理员用户:
use admin
db.createUser({
user: "admin",
pwd: "admin123",
roles: ["root"]
})
通过 mongosh Shell 和 Python/PyMongo 完成 MongoDB 数据库创建、集合操作、文档 CRUD 和聚合管道。
mongosh mongodb://localhost:27017
# 或 Docker:
docker exec -it mongo-dev mongosh
// 切换到测试数据库(不存在则自动创建)
use hello_mongo
// 直接插入文档 = 隐式创建集合
db.users.insertMany([
{
name: "张三",
age: 21,
email: "zhangsan@example.com",
hobbies: ["编程", "篮球"],
address: { city: "北京", district: "海淀" }
},
{
name: "李四",
age: 22,
email: "lisi@example.com",
hobbies: ["编程", "摄影", "旅行"],
address: { city: "上海", district: "浦东" }
}
])
// 查询
db.users.find({ age: { $gte: 21 } })
db.users.findOne({ "address.city": "北京" })
// 投影(只返回部分字段)
db.users.find({}, { name: 1, email: 1, _id: 0 })
// 更新
db.users.updateOne(
{ name: "张三" },
{ $set: { age: 22 }, $push: { hobbies: "摄影" } }
)
// 条件更新
db.users.updateMany(
{ "address.city": "北京" },
{ $set: { "address.country": "中国" } }
)
// 删除
db.users.deleteOne({ name: "李四" })
// 统计各城市用户数
db.users.aggregate([
{ $group: { _id: "$address.city", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
])
// 展开数组统计最受欢迎爱好
db.users.aggregate([
{ $unwind: "$hobbies" },
{ $group: { _id: "$hobbies", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
])
pip install pymongo
from pymongo import MongoClient
client = MongoClient("mongodb://localhost:27017")
db = client["hello_mongo"]
col = db["products"]
# 创建索引
col.create_index("name", unique=True)
# 插入
products = [
{"name": "机械键盘", "price": 299, "tags": ["外设", "办公"], "stock": 50},
{"name": "无线鼠标", "price": 89, "tags": ["外设", "移动"], "stock": 200},
]
col.insert_many(products)
# 查询
for p in col.find({"price": {"$lt": 300}}).sort("price", -1):
print(f"{p['name']}: ¥{p['price']} (库存:{p['stock']})")
# 聚合:各标签商品数
pipeline = [
{"$unwind": "$tags"},
{"$group": {"_id": "$tags", "count": {"$sum": 1}}}
]
for r in col.aggregate(pipeline):
print(f"标签[{r['_id']}]: {r['count']}件商品")
# 更新
col.update_one(
{"name": "机械键盘"},
{"$set": {"price": 259}, "$inc": {"stock": -1}}
)
client.close()
# mongosh find
{
_id: ObjectId("..."),
name: '张三',
age: 22,
email: 'zhangsan@example.com',
hobbies: ['编程', '篮球', '摄影']
}
# Python
机械键盘: ¥299 (库存:50)
无线鼠标: ¥89 (库存:200)
标签[外设]: 2件商品
标签[办公]: 1件商品
标签[移动]: 1件商品
MongoDB 是一个面向文档(Document-Oriented)的 NoSQL 数据库。不同于 MySQL 的表格行,MongoDB 的数据单元是 BSON 文档(Binary JSON),最接近 JavaScript 对象。
| RDBMS | MongoDB |
|---|---|
| Database | Database |
| Table | Collection(集合) |
| Row | Document(文档) |
| Column | Field(字段) |
| Primary Key | _id (自动生成 ObjectId) |
| JOIN | $lookup(聚合管道) |
// 方案 A:内嵌(Embed)- 适合"包含"关系
{
_id: ObjectId("..."),
title: "MongoDB 入门",
author: { name: "张三", email: "z@s.com" }, // 内嵌作者
tags: ["NoSQL", "数据库"],
comments: [
{ user: "alice", text: "很棒!", at: ISODate("...") },
{ user: "bob", text: "学习了", at: ISODate("...") }
]
}
// 方案 B:引用(Reference)- 适合"多对多"关系
// courses 集合
{ _id: 1, name: "数据库原理", teacher: "王教授" }
// students 集合
{ _id: 1001, name: "小明", course_ids: [1, 2, 3] }
use school
// === 1. 集合与索引 ===
db.students.createIndex({ email: 1 }, { unique: true })
db.students.createIndex({ name: 1 })
db.courses.createIndex({ name: 1 }, { unique: true })
db.enrollments.createIndex({ student_id: 1, course_id: 1 }, { unique: true })
// === 2. 插入数据 ===
db.students.insertMany([
{ name: "张三", email: "zs@school.edu", age: 20, gender: "M" },
{ name: "李四", email: "ls@school.edu", age: 21, gender: "M" },
{ name: "王五", email: "ww@school.edu", age: 19, gender: "F" },
])
db.courses.insertMany([
{ name: "数据库原理", credits: 3, teacher: "王教授", capacity: 60 },
{ name: "数据结构", credits: 4, teacher: "李教授", capacity: 50 },
{ name: "操作系统", credits: 3, teacher: "张教授", capacity: 55 },
])
// === 3. 选课(事务 - MongoDB 4.0+) ===
const session = db.getMongo().startSession()
session.startTransaction()
try {
const enrollments = session.getDatabase("school").enrollments
enrollments.insertMany([
{ student_id: ObjectId("..."), course_id: ObjectId("..."), enrolled_at: new Date() },
{ student_id: ObjectId("..."), course_id: ObjectId("..."), enrolled_at: new Date() },
])
// 更新课程已选人数
db.courses.updateOne({ _id: ObjectId("...") }, { $inc: { enrolled: 2 } })
session.commitTransaction()
} catch (e) {
session.abortTransaction()
throw e
} finally {
session.endSession()
}
// === 4. 聚合:学生成绩单 ===
// 先添加成绩嵌入到 enrollments
db.enrollments.updateMany({}, { $set: { score: Math.floor(Math.random() * 40) + 60 } })
db.enrollments.aggregate([
{
$lookup: {
from: "students",
localField: "student_id",
foreignField: "_id",
as: "student"
}
},
{ $unwind: "$student" },
{
$lookup: {
from: "courses",
localField: "course_id",
foreignField: "_id",
as: "course"
}
},
{ $unwind: "$course" },
{
$group: {
_id: "$student._id",
name: { $first: "$student.name" },
avg_score: { $avg: "$score" },
courses: { $push: { name: "$course.name", score: "$score" } }
}
},
{ $sort: { avg_score: -1 } }
])
// 单字段索引
db.students.createIndex({ age: 1 })
// 复合索引
db.enrollments.createIndex({ student_id: 1, course_id: 1 })
// 文本索引(全文搜索)
db.courses.createIndex({ name: "text", teacher: "text" })
db.courses.find({ $text: { $search: "数据库" } })
// 分析查询性能
db.students.find({ age: { $gte: 20 } }).explain("executionStats")
除了命令行,强烈推荐安装 MongoDB Compass(GUI 工具):
$lookup 的局限性是什么?为什么 MongoDB 不建议大量使用它?