跳到主要内容

MongoDB 命令速查:CRUD、聚合、索引按场景查(含查询操作符与 SQL 对比)

把 MongoDB 日常真在 mongosh 里敲的命令按场景列清楚:find/insert/update/delete、聚合管道、索引调优、查询条件操作符,再附一张和 SQL 的对照表,照着抄就能跑。

发布于 作者 李雷
#mongodb #数据库 #速查表 #后端

MongoDB 命令速查:按场景查 CRUD、聚合、索引与查询操作符

写 MongoDB 三年,我桌上一直贴着一张手写小条,上面就五行:find 加 sort、updateOne 一定带 $set、聚合先 $match、建索引前先 explain、不锚定的 $regex 会全表扫。这五条几乎覆盖了我每天敲的八成命令。下面把它按场景摊开,配上能直接粘进 mongosh 速查表 跑的真实例子。

增删改查:四个动作的标准写法

最常用的四组命令,记住格式比记 API 名重要:

db.users.insertOne({ name: "Alice", age: 20, tags: ["vip"] })
db.users.insertMany([{ name: "Bob" }, { name: "Cathy" }], { ordered: false })
db.users.find({ age: { $gt: 18 } }).sort({ age: -1 }).limit(10)
db.users.updateOne({ _id: id }, { $set: { age: 21 } })
db.users.deleteOne({ _id: id })

insertManyordered: false,一条插失败也不会阻断后面的,做 ETL 导入提速明显。find 永远跟着 sortlimit 写,分页才稳。

头号坑:updateOne 忘了 $set 等于整条替换

这是我见过最贵的一个 bug,新同事踩过,我自己刚上手也踩过。

db.users.updateOne({ _id: id }, { name: "Alice" })   // 危险:整条替换
db.users.updateOne({ _id: id }, { $set: { name: "Alice" } })  // 正确:只改 name

第一行不报错、不告警,静默把整条文档丢掉,只留 { _id, name },email、角色、时间戳全没。规则很死:裸文档等于替换,带操作符的文档才是局部更新。$set 改字段,$inc 做计数器,$push 往数组追加。改动永远包进操作符里。

查询条件操作符:表达任何谓词

find 的 filter 文档里,靠操作符拼条件:

| 操作符 | 含义 | 例子 | |---|---|---| | $gt $gte $lt $lte | 大于/小于 | { age: { $gt: 18 } } | | $in $nin | 在/不在集合 | { status: { $in: ["a", "b"] } } | | $ne | 不等于 | { role: { $ne: "admin" } } | | $exists | 字段存在 | { email: { $exists: true } } | | $elemMatch | 数组元素同时满足多条件 | { scores: { $elemMatch: { $gt: 80, $lt: 90 } } } |

两个隐藏坑要记牢:$ne$nin 也会匹配字段缺失的文档,真要排除某值时得写成 { $exists: true, $ne: v };想给同一字段加两个范围,不能写 { age: { $gt: 18 }, age: { $lt: 65 } },JS 对象 key 唯一,第一个条件被静默丢掉,正确写法是 { age: { $gt: 18, $lt: 65 } }

聚合管道:先过滤再分组

聚合是 MongoDB 比关系库灵活的地方,记住一条:$match 越靠前越好,先把数据筛少再进后面的阶段。

db.orders.aggregate([
  { $match: { status: "paid" } },
  { $group: { _id: "$userId", total: { $sum: "$amount" } } },
  { $sort: { total: -1 } },
  { $limit: 5 }
])

$lookup 做跨集合关联时,外部 foreignField 一定要有索引,没索引就是 O(N*M),数据一大整个管道卡死。

索引:建之前先 explain

查询慢的根因九成是没走对索引。判断只看一个命令:

db.users.find({ age: { $gt: 18 } }).explain("executionStats")

winningPlan.stageIXSCAN 就是走了索引,是 COLLSCAN 就是全表扫,几千条以上就该警觉。再看 totalDocsExaminednReturned 的比例,扫了一百万返回二十条,说明该补索引。复合索引遵守前缀顺序规则,建在 { status, createdAt } 上的索引没法单独支撑按 createdAt 排序,这点 explain 会直接告诉你。

和 SQL 的对照表

从关系库迁过来的人,记不住命名时查这张表最快:

| SQL | MongoDB | |---|---| | SELECT * FROM t WHERE age > 18 | db.t.find({ age: { $gt: 18 } }) | | INSERT INTO t VALUES (...) | db.t.insertOne({ ... }) | | UPDATE t SET age=21 WHERE id=x | db.t.updateOne({ _id: x }, { $set: { age: 21 } }) | | DELETE FROM t WHERE id=x | db.t.deleteOne({ _id: x }) | | GROUP BY userId | $group: { _id: "$userId" } | | JOIN | $lookup | | CREATE INDEX | db.t.createIndex({ age: 1 }) | | COUNT(*) | db.t.countDocuments({}) |

最大的认知差:MongoDB 没有强 schema,JOIN 成本远高于关系库,所以建模时倾向把相关数据塞进一条嵌套文档,而不是拆成多张表再连。

如果你的栈不只 MongoDB,这套速查同系列还有 PostgreSQL 速查表SQL 速查表Redis 速查表Docker 速查表,一起覆盖整条后端技术栈。


Made by Toolora · Updated 2026-06-13