MongoDB 简介
在动手装环境之前,我们先搞清楚 MongoDB 到底是什么、为什么会出现、它解决了关系数据库的哪些痛点。理解了背景,后面学语法才会"知其所以然"。
MongoDB 是什么?
MongoDB 是 2009 年由 MongoDB Inc.(原名 10gen)开源的文档型数据库,名字来自英文单词 "humongous"(巨大的)。它属于 NoSQL 阵营的一员——不用传统的表 + 行 + SQL,而是把数据存成一个个"文档"(document),每个文档本质上是一个 JSON 对象(技术上是 BSON,即二进制 JSON)。
一组相关文档放进同一个"集合"(collection),集合对应关系数据库里的"表"。整个数据库的层级是:数据库 → 集合 → 文档。
为什么需要 NoSQL?MySQL 不够用吗?
MySQL 这类关系数据库四十多年来经久不衰,擅长处理结构化、关系清晰、事务强一致的数据(银行转账、订单)。但 Web 时代之后,出现了很多"不太乖"的数据:
- 层级结构:一篇文章有作者、标签、评论、嵌套对象,扁平的表要拆好几张再 JOIN。
- schema 经常变:产品迭代快,这周加个字段、下周改个类型,关系数据库要
ALTER TABLE,大表上很慢。 - 海量且高并发:单机存不下,要横向扩展,关系数据库横向拆分(分库分表)很痛苦。
- 半结构化:日志、配置、用户画像、传感器数据,字段不固定。
MongoDB 给的答案是:直接把整个 JSON 对象存进数据库,不用拆表。看个对比就一目了然:
// 关系数据库:一篇文章相关数据拆成多张表,查询时 JOIN
posts: id=1 | title=入门 | author_id=7
authors: id=7 | name=小明 | email=x@x.com
comments: id=1 | post_id=1 | text=赞
tags: id=3 | name=MongoDB
post_tags: post_id=1 | tag_id=3
// MongoDB:把相关数据打包进"一个文档"
// 取出来时一次拿全,无需 JOIN
{
_id: ObjectId("65a1f2c8..."),
title: "入门",
author: { name: "小明", email: "x@x.com" },
tags: ["MongoDB", "NoSQL"],
comments: [
{ text: "赞", at: ISODate("2025-01-01T00:00:00Z") }
]
}同样的"一篇文章 + 作者 + 评论 + 标签",关系数据库要 4~5 张表加 JOIN,MongoDB 一个文档搞定,取出来一次拿全。读得多、关系紧密、形状经常变的场景,MongoDB 大幅简化了开发。
核心概念:数据库、集合、文档
MongoDB 的层级结构和关系数据库有清晰的对应,但有个关键差异:集合不用预先建。你往一个不存在的集合里插入文档,它会自动创建。数据库也一样。
// MongoDB 的层级结构
// 一个 mongod 实例可以管理多个数据库
// 每个数据库里有多个集合(collection)
// 每个集合里存放若干文档(document)
// 切换/创建数据库(首次写入时自动创建)
use myblog
// 集合不用预先建,插入时自动生成
db.posts.insertOne({ title: "第一篇" })
db.users.insertOne({ name: "小明" })
// 查看当前数据库里有哪些集合
show collections核心概念:_id 与 ObjectId
每个文档都必须有一个 _id 字段作为主键,全集合唯一。你不指定的话,MongoDB 自动生成一个 ObjectId。
// 每个文档都必须有一个 _id,作为主键
// 你不指定时,MongoDB 自动生成一个 ObjectId
db.users.insertOne({ name: "小明" })
// 写入后文档实际是:
// { _id: ObjectId("65a1f2c8a1b2c3d4e5f6a7b8"), name: "小明" }
// ObjectId 是 12 字节,结构如下:
// | 4 字节时间戳 | 5 字节随机值 | 3 字节自增计数 |
// 所以前 4 字节就能反推创建时间,自带"大致有序"
// 也可以自己指定 _id(比如用业务主键)
db.users.insertOne({ _id: "u-1001", name: "小红" })
// 再插一次同 _id 会报错(主键冲突)
db.users.insertOne({ _id: "u-1001", name: "重复" }) // E11000 duplicate keyObjectId 看似一串随机字符,其实结构很精巧:前 4 字节是创建时间戳,所以它"大致按时间递增",天然适合做排序键;中间 5 字节是机器/进程标识;最后 3 字节是计数器。这意味着即使没有全局协调,不同节点生成的 ObjectId 也几乎不会冲突——这对分布式系统非常重要。
核心特点:schema 灵活
MongoDB 同一个集合里的文档字段可以不一样。今天存三个字段,明天加一个,后天去掉一个,完全不用改表结构。
// 同一个集合里,文档字段可以不一样
db.posts.insertOne({ title: "A", views: 0 })
db.posts.insertOne({ title: "B", views: 5, cover: "b.jpg" })
db.posts.insertOne({ title: "C", content: "...", author: "小明" })
// 加新字段不用 ALTER TABLE,直接写就行
// 这对产品快速迭代、数据形状经常变的场景极其友好这种灵活是把双刃剑:好处是迭代飞快,代价是应用层要自己保证数据一致性(后来 MongoDB 3.2+ 加入了 validator 可选规则,平衡了灵活与严谨)。生产环境通常配合 ODM 库(如 Mongoose)在应用层定义 schema,既享受灵活性又保留约束。
MongoDB vs MySQL 对比
- 数据模型:MongoDB 是文档(JSON/BSON),MySQL 是表(行+列)。
- schema:MongoDB 默认无 schema(灵活),MySQL 强 schema(改表要 ALTER)。
- 查询语言:MongoDB 用 JS 风格对象(
db.col.find{...}),MySQL 用 SQL。 - 关联:MongoDB 弱(用 $lookup 或嵌套),MySQL 强(JOIN 是看家本领)。
- 事务:MySQL 强项;MongoDB 4.0+ 支持多文档事务,但性能开销大,能免则免。
- 扩展性:MongoDB 原生支持分片(水平扩展),MySQL 横向扩展更难。
- 适用场景:MongoDB 适合内容/画像/日志/配置;MySQL 适合订单/账务/强关系数据。
典型应用场景
- 内容管理(CMS):文章、评论、标签天然嵌套,一个文档拿全。
- 用户画像与个性化:每个用户的属性字段不一样,schema 灵活正合适。
- 实时分析与日志:高写入吞吐,字段不固定。
- 物联网(IoT)数据:海量传感器数据,按时间分片。
- 电商商品目录:不同商品属性差异大(手机有内存、衣服有尺码)。
- MERN 全栈:MongoDB + Express + React + Node,前后端全是 JS。
它还"重"得起来吗?
别以为 NoSQL 就等于"玩具"。MongoDB 早就是个企业级数据库了:
- 索引:单字段、复合、唯一、全文、地理空间、TTL 一应俱全。
- 聚合管道:功能上等价于 SQL 的 GROUP BY + JOIN + 子查询合体。
- 事务:4.0 起支持多文档 ACID 事务,副本集内一致。
- 副本集:主从复制 + 自动故障转移,生产标配。
- 分片:数据量超大时水平拆分到多台机器。
小结
这一篇你了解了 MongoDB 的定位:把 JSON 对象当数据存的文档数据库,schema 灵活、不用拆表 JOIN、扩展性强,适合内容、画像、日志等"非结构化、迭代快"场景。下一篇我们装环境——本地装 Server,或直接用云端的 Atlas,跑起第一个 mongosh 命令。
← 返回 MongoDB 教程目录
下一篇 MongoDB 环境安装 →