系列文章: 数据库
  1. 1 PostgreSQL是什么?世界上最先进的开源关系数据库
  2. 2 MongoDB是什么?文档数据库与何时选择NoSQL
✦ 快速摘要
MongoDB是以灵活JSON/BSON格式存储数据的文档数据库,适合schema频繁变化的场景。学习CRUD、聚合管道、副本集以及何时选择MongoDB而非PostgreSQL。
这篇文章怎么样?

MongoDB是全球领先的文档数据库,以灵活的JSON格式存储数据,而非像SQL那样使用固定表结构。本文解释MongoDB是什么、文档模型的工作原理、聚合管道,以及何时应选择MongoDB而非PostgreSQL。

MongoDB是什么?

MongoDB是一款文档型NoSQL数据库管理系统,诞生于2009年。与SQL不同,MongoDB不将数据存储在固定的行列表中,而是以灵活的JSON文档(实际上是BSON——Binary JSON)形式存储:

JSON
 1{
 2  "_id": "64a1f2...",
 3  "name": "Alice",
 4  "email": "alice@example.com",
 5  "orders": [
 6    { "product": "笔记本电脑", "price": 999 },
 7    { "product": "鼠标", "price": 29 }
 8  ],
 9  "address": {
10    "city": "河内",
11    "district": "还剑"
12  }
13}

单个用户文档内嵌了订单数据——而在SQL中这需要通过多表JOIN才能实现。

文档模型 vs 关系模型

MongoDB(文档型) PostgreSQL(关系型)
存储单元 文档(JSON) 表中的行
Schema 灵活(不固定) 固定(需迁移)
数据关系 嵌入或引用 外键 + JOIN
扩展方式 水平扩展(分片) 垂直扩展(为主)
事务 多文档(4.0+) 完整ACID

使用pymongo进行CRUD(Python)

Python
 1from pymongo import MongoClient
 2
 3client = MongoClient("mongodb://localhost:27017/")
 4db = client["myapp"]
 5users = db["users"]
 6
 7# 插入
 8result = users.insert_one({
 9    "name": "Alice",
10    "email": "alice@example.com",
11    "active": True
12})
13print(result.inserted_id)  # ObjectId('64a1f2...')
14
15# 带条件查询
16active_users = users.find({"active": True}, {"name": 1, "email": 1})
17for user in active_users:
18    print(user)
19
20# 更新
21users.update_one(
22    {"email": "alice@example.com"},
23    {"$set": {"active": False}}
24)
25
26# 删除
27users.delete_one({"email": "alice@example.com"})

使用Mongoose操作Node.js

JavaScript
 1const mongoose = require('mongoose');
 2await mongoose.connect('mongodb://localhost:27017/myapp');
 3
 4const UserSchema = new mongoose.Schema({
 5  name: { type: String, required: true },
 6  email: { type: String, required: true, unique: true },
 7  active: { type: Boolean, default: true },
 8});
 9
10const User = mongoose.model('User', UserSchema);
11
12// 创建
13const user = await User.create({ name: 'Alice', email: 'alice@example.com' });
14
15// 查询
16const activeUsers = await User.find({ active: true }).select('name email');
17
18// 更新
19await User.updateOne({ email: 'alice@example.com' }, { $set: { active: false } });

聚合管道

JavaScript
 1// 按月统计收入
 2db.orders.aggregate([
 3  { $match: { status: "completed" } },
 4  { $group: {
 5      _id: { $month: "$createdAt" },
 6      totalRevenue: { $sum: "$amount" },
 7      orderCount: { $sum: 1 }
 8  }},
 9  { $sort: { "_id": 1 } }
10])

副本集与高可用性

MongoDB副本集由一个主节点(Primary)和一个或多个从节点(Secondary)组成。主节点接收所有写操作;从节点持续从主节点复制数据。若主节点故障,副本集会在几秒内自动选举新的主节点——为应用提供零停机保障。

何时选择MongoDB vs PostgreSQL?

当schema不稳定、数据天然嵌套或需要快速水平扩展时,选择MongoDB。当需要复杂JOIN、完整ACID或重度报表与分析时,选择PostgreSQL

PostgreSQL是什么?领先的关系型数据库管理系统

Elasticsearch是什么?用于全文搜索的分布式搜索引擎

Redis是什么?内存缓存、发布订阅与队列

常见问题Q&A
MongoDB以什么格式存储数据?
MongoDB以BSON(Binary JSON)格式存储数据——这是JSON的二进制扩展格式,额外支持Date、ObjectId、Binary和Decimal128等类型。通过驱动程序操作时,你看到的是普通JSON;MongoDB在存储时自动转换为BSON。
MongoDB支持事务吗?
支持,从MongoDB 4.0(2018年)起。MongoDB在副本集上支持多文档ACID事务,从4.2起在分片集群上也支持。不过MongoDB的事务开销高于PostgreSQL,只有在确实需要原子更新多个文档时才建议使用。
MongoDB中的副本集是什么?
副本集是一组存储相同数据集的MongoDB实例:一个主节点(Primary)接收所有写操作,一个或多个从节点(Secondary)持续从主节点复制数据。若主节点故障,副本集会在几秒内自动选举新的主节点——这是MongoDB基本的高可用机制。
什么是聚合管道?
聚合管道是一系列按顺序处理数据的阶段:$match(过滤文档)、$group(聚合计算,如COUNT、SUM、AVG)、$sort、$project(选择字段)、$lookup(与其他集合JOIN)。每个阶段接收上一阶段的输出,从而构建复杂的分析查询。
什么时候应该选择MongoDB而非PostgreSQL?
在以下情况选择MongoDB:schema经常变化或尚未明确(敏捷开发)、数据天然具有嵌套结构(每个品类属性不同的商品目录)、需要通过分片快速水平扩展,或团队比起SQL更熟悉JavaScript/JSON。在需要复杂JOIN、严格ACID保证或数据关系紧密时选择PostgreSQL。
MongoDB Atlas是什么?
MongoDB Atlas是云端(AWS、GCP、Azure)完全托管的MongoDB服务。Atlas自动处理备份、扩缩容、安全补丁和监控。提供免费套餐(M0:512MB),适合学习和原型开发。生产环境通常使用M10及以上的专用集群。