ToolkitX
知识库工具箱

MongoDB 概念入门

NoSQL 理念、文档模型 vs 关系模型

15min·入门

01. NoSQL 跟 SQL 到底差在哪

关系型数据库(SQL)把数据存成一张张互相有关联的表——用户表、订单表、商品表,查的时候用 JOIN 把它们缝在一起。 MongoDB 是文档数据库——不像表那样一行行一列列,而是把数据存成 BSON(类似 JSON)的文档。一个文档就是一个自包含的数据单元,用户的订单可以嵌套在用户文档里,不用拆散到多个表。 核心区别:SQL 的表结构是死的,所有行都得一个样。MongoDB 文档是灵活的,不同文档可以有不同字段。SQL 靠 JOIN 拆表关联,MongoDB 靠嵌套文档减少关联,但也能用 lookup 做类似 JOIN 的事。 选 MongoDB 的场景:数据格式不固定经常变;数据之间天然有嵌套关系(如博客文章加评论);快速原型开发。不适合:复杂事务多、需要大量关联查询的场景。

02. 安装与 MongoDB Shell(mongosh)

MongoDB 安装后自带 mongosh(新版命令行客户端,替代老版 mongo shell)。mongosh 是个完整的 Node.js REPL,可以直接写 JavaScript。 常用命令:show dbs 看所有数据库,use mydb 切换数据库,show collections 看当前库所有集合,db.help() 看帮助。 集合相当于 SQL 的表,文档相当于 SQL 的行。MongoDB 会自动为每个文档生成一个下划线 id 字段,类型是 ObjectId——一个 12 字节的唯一 ID,包含时间戳信息。
bash
# 启动 MongoDB 服务
mongod --dbpath /data/db

# 连接
mongosh mongodb://localhost:27017

# mongosh 常用命令
show dbs
use mydb
show collections
db.users.find()
db.users.findOne()
exit
mongosh 用的是 JavaScript 语法,db.users.findOne() 后面不需要分号但加了也没事。

03. 文档模型设计——嵌套 vs 引用

MongoDB 里设计数据模型有一个核心问题:嵌套还是引用? 嵌套——把关联数据直接嵌入到父文档里。比如把评论嵌入文章文档里。好处是一次查询就全拿到了,不用 JOIN。坏处是文档可能变大超过 16MB 限制;评论多了更新也麻烦。 引用——类似 SQL 的外键。文章和评论分开存,评论文档里放一个文章 ID 指向文章。好处是灵活安全,坏处是查的时候可能要跑 lookup 关联。 选嵌套还是引用的经验法则:子数据跟父数据同生共死且数量不多(几十条)就嵌套;子数据可能被多个父文档引用或数量很大就引用。
javascript
// 嵌套模型:文章里嵌入评论
{
  _id: ObjectId("..."),
  title: "MongoDB 教程",
  comments: [
    { user: "Alice", text: "好文章!", date: ISODate("2024-01-01") },
    { user: "Bob", text: "学习了", date: ISODate("2024-01-02") }
  ]
}

// 引用模型
// articles 集合
{ _id: ObjectId("..."), title: "MongoDB 教程" }
// comments 集合
{ article_id: ObjectId("..."), user: "Alice", text: "好文章!" }
嵌套的评论有上限——单个文档最大 16MB,如果评论可能非常多,老老实实用引用模型。

04. 数据库与集合的管理

MongoDB 的数据库和集合是懒创建的——你不用去建库建表,直接用就行。第一次往 database.collection 插入数据时,数据库和集合自动就长出来了。 但有些高级选项需要显式创建: 固定集合——大小固定的集合,写满了自动覆盖最老的数据,适合存日志。 文档校验——虽然 MongoDB 是 schema-less 的,但你可以在集合上定义校验规则,拒绝不符合格式的文档插入。 过期索引——给某个日期字段建 TTL 索引,时间一到文档自动删除,适合存临时数据。
javascript
// 固定集合(最大 1MB,最多存 1000 条)
db.createCollection("logs", { capped: true, size: 1048576, max: 1000 });

// 定义集合校验规则
db.createCollection("users", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name", "email"],
      properties: {
        name: { bsonType: "string" },
        email: { bsonType: "string", pattern: "^.+@.+$" },
        age: { bsonType: "int", minimum: 0, maximum: 150 }
      }
    }
  }
});
dropDatabase() 没有确认对话框,执行直接删,不会问第二遍。生产环境操作前再三确认。

05. 数据类型与 ObjectId

MongoDB 的 BSON 支持丰富的数据类型:String、Integer、Boolean、Double、Array、Object、Date、ObjectId、Binary Data、Null、Regular Expression、Timestamp。 ObjectId 是最特殊的一个——默认主键 _id 的类型。12 字节的结构:前 4 字节是时间戳(精确到秒),中间 5 字节是随机值(机器 ID 加进程 ID),后 3 字节是计数器。这意味着从 ObjectId 就能反解出文档是什么时候创建的。 Date 类型存的是 UTC 时间,mongosh 里显示会转成本地时间。数字分 Integer(32 位)、Long(64 位)、Double(浮点)。默认输入数字是 Double,想用 Integer 得用 NumberInt()。
javascript
// ObjectId 里提取时间
ObjectId("669c8a1234567890abcdef12").getTimestamp()
// 返回 ISODate 对象

// 数字类型
NumberInt(42)   // 32 位整数
NumberLong(99)  // 64 位整数
NumberDecimal("123.45") // 高精度小数

// 日期
db.events.insertOne({ name: "Conference", date: new Date("2024-12-01") });
db.events.insertOne({ name: "Webinar", date: ISODate("2024-12-15") });
ObjectId 不需要你手动生成,插入时不提供 _id 系统自动创建。但也可以用 ObjectId() 手动创建。

知识测验

1/5正确 0

MongoDB 的集合相当于 SQL 的什么?

下一节

CRUD 操作

下一节