
MongoDB vs PostgreSQL:2026年该如何选择数据库?
在 MongoDB 和 PostgreSQL 之间做选择是开发者面临的最常见的架构决策之一。两者都是优秀的数据库——但适用于不同的问题。本指南将帮助你做出正确的选择。
TL;DR
| 使用 MongoDB | 使用 PostgreSQL |
|---|---|
| 灵活、不断演进的模式 | 定义明确、稳定的模式 |
| 分层/嵌套数据 | 需要 JOIN 的关系数据 |
| 高写入吞吐量 | 复杂查询、聚合 |
| 从一开始就水平扩展 | ACID 事务至关重要 |
| 内容、目录、用户画像 | 财务数据、库存、订单 |
| 快速原型开发 | 长期生产可靠性 |
数据模型:核心差异
PostgreSQL:关系型(表 + 行)
-- 用户表
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- 订单表(引用用户)
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
total DECIMAL(10,2) NOT NULL,
status VARCHAR(50) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT NOW()
);
-- 带 JOIN 的查询
SELECT u.name, COUNT(o.id) as order_count, SUM(o.total) as total_spent
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id
ORDER BY total_spent DESC;
MongoDB:文档型(集合 + 文档)
// 用户文档——可以嵌入相关数据
{
_id: ObjectId("..."),
name: "Alice Johnson",
email: "alice@example.com",
// 嵌入地址——无需单独的表
address: {
street: "123 Main St",
city: "San Francisco",
state: "CA",
zip: "94105"
},
// 嵌入标签数组
interests: ["javascript", "databases", "devops"],
createdAt: ISODate("2026-01-15")
}
// 查询
db.users.find(
{ "address.city": "San Francisco", interests: "javascript" },
{ name: 1, email: 1 }
)
模式灵活性
PostgreSQL:模式优先
-- 模式是强制的——不能添加任意字段
ALTER TABLE users ADD COLUMN phone VARCHAR(20); -- 必须修改表
-- 添加新字段需要迁移
-- 在生产环境中,对于大表这可能很复杂
MongoDB:模式可选
// 每个文档可以有不同的字段
db.products.insertMany([
{ name: "Laptop", price: 999, specs: { ram: "16GB", cpu: "M3" } },
{ name: "Book", price: 29, author: "John Doe", isbn: "978-0-123456" },
// 不同形状没有惩罚
]);
// 但可以通过验证强制模式
db.createCollection("users", {
validator: {
$jsonSchema: {
required: ["name", "email"],
properties: {
email: { type: "string", pattern: "^.+@.+\..+quot; }
}
}
}
});
事务:ACID 保证
PostgreSQL:从一开始就完全 ACID
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- 如果这里任何一步失败,两个更新都会回滚
COMMIT;
MongoDB:多文档事务(自 v4.0 起)
const session = client.startSession();
session.startTransaction();
try {
await accounts.updateOne(
{ _id: sender },
{ $inc: { balance: -100 } },
{ session }
);
await accounts.updateOne(
{ _id: recipient },
{ $inc: { balance: 100 } },
{ session }
);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
session.endSession();
}
注意:MongoDB 现在支持事务,但比单文档操作慢,而且 PostgreSQL 的原生事务通常更快、更简单。
查询能力
PostgreSQL:强大的 SQL
-- 窗口函数
SELECT
name,
salary,
AVG(salary) OVER (PARTITION BY department) as dept_avg,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) as rank
FROM employees;
-- CTE(公用表表达式)
WITH monthly_revenue AS (
SELECT DATE_TRUNC('month', created_at) as month, SUM(total) as revenue
FROM orders
GROUP BY month
)
SELECT month, revenue,
LAG(revenue) OVER (ORDER BY month) as prev_month,
revenue - LAG(revenue) OVER (ORDER BY month) as growth
FROM monthly_revenue;
-- 全文搜索
SELECT * FROM articles
WHERE to_tsvector('english', content) @@ to_tsquery('postgresql & indexing');
MongoDB:聚合管道
// 分组和聚合
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: {
_id: "$userId",
totalSpent: { $sum: "$total" },
orderCount: { $count: {} }
}},
{ $sort: { totalSpent: -1 } },
{ $limit: 10 }
]);
// $lookup = JOIN
db.orders.aggregate([
{ $lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user"
}},
{ $unwind: "$user" },
{ $project: { "user.name": 1, total: 1 } }
]);
性能对比
读取
| 场景 | 胜者 |
|---|---|
| 简单键查找 | 平手 |
| 复杂 JOIN | PostgreSQL |
| 分层文档 | MongoDB |
| 全文搜索 | 平手(两者都支持) |
| 时间序列查询 | PostgreSQL(配合 TimescaleDB) |
写入
| 场景 | 胜者 |
|---|---|
| 单文档插入 | MongoDB |
| 批量插入 | 平手 |
| 带复杂事务的更新 | PostgreSQL |
| 高频写入(IoT、日志) | MongoDB |
扩展
PostgreSQL:
- 垂直扩展(更大的机器)——优秀
- 只读副本——内置,简单
- 水平分片——复杂,需要 Citus 或类似方案
MongoDB:
- 分片——内置,专为此设计
- 水平扩展——简单得多
- 最适合 10TB+ 且写入密集的工作负载
各自的最佳场景
选择 PostgreSQL 的场景:
- 电子商务——产品、库存、订单、支付(ACID 至关重要)
- 金融应用——交易、账本、会计
- 分析——复杂报表、仪表盘、聚合
- 关系数据——用户 → 帖子 → 评论 → 点赞链
- 法规合规——数据完整性要求
-- 非常适合关系完整性
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
-- 不能删除有订单的用户!
);
选择 MongoDB 的场景:
- 内容管理——文章、页面、媒体,字段可变
- 用户画像——丰富、嵌套、不断演化的数据结构
- 实时应用——聊天、动态流、通知
- IoT 数据——高容量传感器读数
- 目录——属性差异巨大的产品
// 非常适合可变的产品属性
{
name: "Gaming Chair",
category: "furniture",
attributes: {
material: "leather",
maxWeight: "150kg",
armrests: "4D adjustable",
lumbar: true
}
}
{
name: "JavaScript Book",
category: "books",
attributes: {
author: "Kyle Simpson",
pages: 278,
isbn: "978-1491950296",
edition: 2
}
}
“两者并用”的方法
许多生产系统同时使用两者:
PostgreSQL:
- 用户账户、认证
- 订单、支付
- 业务关键数据
MongoDB:
- 产品目录
- 用户活动日志
- 会话数据
- 内容/CMS 数据
快速决策框架
回答以下问题:
- 你的数据有复杂关系吗? → PostgreSQL
- 你需要严格的 ACID 事务吗? → PostgreSQL
- 你的模式快速演化吗? → MongoDB
- 你需要水平分片吗? → MongoDB
- 你在构建分析/报表吗? → PostgreSQL
- 高写入吞吐量且文档灵活? → MongoDB
- 不确定? → PostgreSQL(以后更容易迁移)
总结
- PostgreSQL = 经过验证、强大、完整 SQL,最适合关系型和分析型工作负载
- MongoDB = 灵活、可扩展,最适合文档数据和快速迭代
两者都是优秀的选择——关键在于将工具与你的数据模型匹配。
→ 使用 JSON 转 YAML 转换器 在 JSON 和 YAML 之间转换数据格式。