数据库-MongoDB:常用语法 / MongoDB 核心知识技能梳理

MongoDB 核心语法完全梳理(从基础到高级·完整版)

MongoDB 是最流行的 NoSQL 文档数据库,使用 BSON 格式存储数据,拥有灵活的 Schema 设计和高性能的查询能力。以下是系统性的核心语法梳理。

说明 :本文聚焦于 MongoDB 特有的或核心的语法。通用的 CRUD 概念与关系型数据库类似,不再赘述。

一、MongoDB 核心概念

SQL 术语 MongoDB 术语 说明
Database Database 数据库
Table Collection 集合(相当于表)
Row Document 文档(相当于行,BSON 格式)
Column Field 字段
Index Index 索引
JOIN $lookup / 应用层 Join 关联查询
Primary Key _id 主键(自动生成 ObjectId)

文档示例

复制代码
{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "name": "张三",
  "age": 28,
  "email": "zhangsan@example.com",
  "address": { "city": "北京", "street": "朝阳路" },
  "hobbies": ["阅读", "游泳"]
}

二、数据库与集合操作

2.1 数据库操作

复制代码
show dbs                     // 显示所有数据库
use mydb                     // 创建/切换数据库
db                           // 查看当前数据库
db.dropDatabase()            // 删除当前数据库

2.2 集合操作

复制代码
db.createCollection("users") // 创建集合
db.createCollection("logs", { capped: true, size: 1048576 }) // 固定集合
show collections             // 显示所有集合
db.users.drop()              // 删除集合

三、文档插入(Create)

3.1 插入单条/多条

复制代码
// 插入单条
db.users.insertOne({ name: "张三", age: 28 })

// 插入多条
db.users.insertMany([
  { name: "王五", age: 25 },
  { name: "赵六", age: 30 }
])

// 有序/无序插入
db.users.insertMany([...], { ordered: false }) // false=遇到错误继续插入

四、文档查询(Read)------ 核心

4.1 基础查询与投影

复制代码
db.users.find({ name: "张三" }) // 条件查询
db.users.find({}, { name: 1, age: 1, _id: 0 }) // 只返回指定字段
db.users.findOne({ name: "张三" }) // 查询单条

4.2 操作符查询

类别 操作符 示例
比较 $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin { age: { $in: [25, 28] } }
逻辑 $and, $or, $not, $nor { $or: [{ age: 20 }, { status: "active" }] }
元素 $exists, $type { email: { $exists: true } }
数组 $size, $all, $in { tags: { $size: 3 } }

4.3 高级查询

复制代码
// 嵌套文档查询
db.users.find({ "address.city": "北京" })

// 正则表达式
db.users.find({ name: /^张/ }) // 开头为"张"

// 数组对象查询($elemMatch)
db.students.find({
  grades: { $elemMatch: { subject: "数学", score: { $gt: 80 } } }
})

五、文档更新 (Update)

5.1 更新操作符

操作符 含义 示例
$set 设置/更新字段 { $set: { name: "新名字" } }
$unset 删除字段 { $unset: { temp: "" } }
$inc 数值增减 { $inc: { age: 1 } }
$mul 数值相乘 { $mul: { salary: 1.1 } }
$rename 重命名字段 { $rename: { old: "new" } }
$push 数组追加 { $push: { hobbies: "跑步" } }
$pop 数组删除首尾 { $pop: { hobbies: 1 } }
$pull 删除匹配元素 { $pull: { hobbies: "电视" } }

5.2 更新方法

复制代码
// updateOne / updateMany
db.users.updateOne({ name: "张三" }, { $set: { age: 29 } })
db.users.updateMany({ status: "active" }, { $set: { updated_at: new Date() } })

// replaceOne (替换整个文档)
db.users.replaceOne({ name: "张三" }, { name: "张三", age: 30 })

// upsert (不存在则插入)
db.users.updateOne({ name: "李四" }, { $set: { age: 25 } }, { upsert: true })

六、文档删除 (Delete)

复制代码
db.users.deleteOne({ name: "赵六" })      // 删除一条
db.users.deleteMany({ status: "inactive" }) // 删除多条
db.users.deleteMany({})                  // 清空集合

七、查询高级功能(聚合与连接)

7.1 聚合管道 (Aggregation Pipeline)

聚合管道是 MongoDB 最强大的数据分析功能。

基本语法
复制代码
db.collection.aggregate([
  { $match: { ... } },      // 过滤
  { { $group: { ... } },      // 分组
  { { $sort: { ... } },       // 排序
  { { $project: { ... } },    // 投影
  { $limit: ... },           // 限制
  { $unwind: ... }           // 展开数组
])

常用阶段示例

复制代码
// $group: 分组统计
db.orders.aggregate([
  { $group: {
      _id: "$status",
      total: { $sum: "$amount" },
      avg: { $avg: "$amount" },
      count: { $sum: 1 }
    }
  }
])

// $project: 重塑文档
db.users.aggregate([
  {
    $project: {
      name: 1,
      full_name: { $concat: ["$firstName", " ", "$lastName"] },
      is_adult: { $gte: ["$age", 18] }
    }
  }
])

// $unwind: 展开数组
db.articles.aggregate([
  { $unwind: "$comments" }, // 每条评论生成一条记录
  { $group: { _id: "$title", count: { $sum: 1 } } }
])

7.2 连接查询 ($lookup)

$lookup 用于实现类似 SQL 的 JOIN 操作。

基础左连接
复制代码
db.orders.aggregate([
  {
    $lookup: {
      from: "users",           // 关联集合
      localField: "userId",     // 本集合字段
      foreignField: "_id",      // 外集合字段
      as: "user_info"           // 结果存入数组
    }
  }
])

高级关联(带管道的 $lookup)

支持在关联时进行子查询和条件过滤。

复制代码
db.orders.aggregate([
  {
    $lookup: {
      from: "users",
      let: { uid: "$userId" }, // 定义变量
      pipeline: [
        { $match: { $expr: { $eq: ["$_id", "$$uid"] } } },
        { $project: { name: 1, email: 1 } } // 只返回需要的字段
      ],
      as: "user_info"
    }
  }
])

八、高级数据处理与多集合输出

MongoDB 在处理"一源多目标"的数据流转时,提供了类似 Oracle INSERT ALL 的机制,以及更强大的聚合输出能力。

8.1 多集合关联查询进阶

除了基础的 $lookup,还可以实现复杂的多字段关联和非等值关联。

8.1.1 多字段复合关联

当外键由多个字段组成时,使用 letpipeline 实现。

复制代码
// 场景:订单表 orders 有 user_id 和 region_code,需关联 users 表
db.orders.aggregate([
  {
    $lookup: {
      from: "users",
      let: { uid: "$userId", rc: "$region_code" },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                { $eq: ["$_id", "$$uid"] },
                { $eq: ["$region_code", "$$rc"] }
              ]
            }
          }
        }
      ],
      as: "user_info"
    }
  }
])

8.1.2 关联后展开与文档合并(模拟 INNER JOIN)

默认 $lookup 返回数组。通过 $unwind$replaceRoot 可以将关联文档"平铺"到主文档中。

复制代码
db.orders.aggregate([
  { $match: { status: "completed" } },
  {
    $lookup: {
      from: "users",
      localField: "userId",
      foreignField: "_id",
      as: "user_doc"
    }
  },
  { $unwind: "$user_doc" },  // 展开数组(一对一关系)
  {
    $replaceRoot: { 
      newRoot: { $mergeObjects: [ "$user_doc", "$$ROOT" ] } 
    }
  },
  { $project: { user_doc: 0 } } // 删除冗余字段
])

8.2 结果集拆分与分发(类似 INSERT ALL)

在 ETL 场景中,需要根据条件将数据写入不同的集合。

8.2.1 使用 $out 阶段(覆盖写入)

将聚合结果直接输出到一个新集合(注意:若集合已存在则覆盖)。

复制代码
// 将活跃用户筛选出来,存入 active_users 集合
db.users.aggregate([
  { $match: { status: "active" } },
  { $project: { name: 1, email: 1 } },
  { $out: "active_users" }  // 覆盖写入
])

8.2.2 使用 $merge 阶段(增量合并,推荐)

$merge$out 更灵活,支持 Upsert(更新或插入),且不会删除目标集合中未匹配的旧数据

复制代码
// 场景:同步订单状态到历史表
db.orders.aggregate([
  { $match: { status: "completed" } },
  {
    $merge: {
      into: "order_history",    // 目标集合
      on: "_id",                // 匹配主键
      whenMatched: "merge",     // 匹配时:合并字段(类似 UPDATE)
      whenNotMatched: "insert"  // 不匹配时:插入新文档
    }
  }
])

$merge 的高级用法(条件更新/字段操作)

复制代码
db.orders.aggregate([
  { $match: { status: "cancelled" } },
  {
    $merge: {
      into: "order_archive",
      on: "_id",
      whenMatched: [
        { $set: { cancelled_at: "$$NOW" } }, // 匹配时设置取消时间
        { $unset: ["temp_field"] }           // 同时删除临时字段
      ],
      whenNotMatched: "discard"  // 如果历史表没有这条记录,直接丢弃(不插入)
    }
  }
])

8.3 客户端格式化输出

8.3.1 聚合管道中的格式化

使用 $project 阶段可以完全重排文档结构,甚至重命名字段(支持中文别名)。

复制代码
db.users.aggregate([
  {
    $project: {
      _id: 0,
      "用户ID": "$_id",
      "姓名": "$name",
      "联系方式": { $ifNull: ["$email", "$phone"] },
      "注册年份": { $year: "$created_at" }
    }
  }
]).pretty()

8.3.2 导出为 CSV/JSON

虽然 MongoDB Shell 不直接支持复杂的 Excel 导出,但可以通过 mongoexport 工具或驱动程序实现。

复制代码
# 命令行导出 CSV
mongoexport --db=mydb --collection=users --type=csv --fields=name,age,email --out=users.csv

九、索引管理

9.1 索引类型

复制代码
// 单字段/复合索引
db.users.createIndex({ name: 1 })
db.users.createIndex({ status: 1, age: -1 })

// 唯一索引
db.users.createIndex({ email: 1 }, { unique: true })

// 稀疏索引(只索引有值的文档)
db.users.createIndex({ email: 1 }, { sparse: true })

// TTL 索引(自动过期)
db.sessions.createIndex({ created_at: 1 }, { expireAfterSeconds: 3600 })

// 文本索引
db.articles.createIndex({ title: "text", content: "text" })

9.2 索引管理

复制代码
db.users.getIndexes()       // 查看索引
db.users.dropIndex("name_1") // 删除索引
db.users.hideIndex("name_1") // 隐藏索引(用于测试)

十、事务处理 (4.0+)

MongoDB 支持多文档 ACID 事务(仅限副本集)。

复制代码
const session = db.getMongo().startSession()
session.startTransaction()

try {
  const orders = session.getDatabase("store").orders
  const inventory = session.getDatabase("store").inventory

  orders.insertOne({ orderId: "001", amount: 100 })
  inventory.updateOne({ sku: "A001" }, { $inc: { stock: -1 } })

  session.commitTransaction()
} catch (error) {
  session.abortTransaction()
} finally {
  session.endSession()
}

十一、批量操作

11.1 批量写入

复制代码
// 混合操作(插入、更新、删除)
const bulk = db.users.initializeOrderedBulkOp()
bulk.insert({ name: "用户A" })
bulk.find({ name: "用户B" }).updateOne({ $set: { age: 25 } })
bulk.find({ status: "inactive" }).remove()

const result = bulk.execute() // 执行批量操作

十二、性能分析与调优

12.1 查询分析

复制代码
// 查看执行计划
db.users.find({ age: { $gt: 18 } }).explain()

// 详细执行计划(含统计信息)
db.users.find({ age: { $gt: 18 } }).explain("executionStats")

12.2 慢查询日志

复制代码
db.setProfilingLevel(1, { slowms: 100 }) // 记录超过100ms的查询
db.system.profile.find().pretty()       // 查看慢查询

十三、常用命令速查

命令 说明
show dbs 显示所有数据库
use dbname 切换/创建数据库
show collections 显示当前数据库所有集合
db.collection.countDocuments() 统计文档数(精确)
db.collection.estimatedDocumentCount() 估计文档数(快速)
db.collection.stats() 查看集合统计信息
db.currentOp() 查看当前操作
db.killOp(opid) 终止操作

十四、备份与恢复

复制代码
# 导出集合(JSON/CSV)
mongoexport --db mydb --collection users --out users.json
mongoexport --db mydb --collection users --type=csv --fields name,age

# 导入集合
mongoimport --db mydb --collection users --file users.json

# 备份整个数据库(二进制)
mongodump --db mydb --out /backup/dir

# 恢复数据库
mongorestore --db mydb /backup/dir/mydb

MongoDB 多表输出方案选型

需求场景 推荐方案 性能 复杂度 备注
简单关联查询 $lookup (基础) ⭐⭐⭐⭐ 适合大多数一对一/多对一场景
复杂关联/非等值 $lookup + pipeline ⭐⭐⭐ 灵活度高,支持子查询
ETL 数据归档 $merge / $out ⭐⭐⭐⭐⭐ 服务端原子操作,比客户端循环快
跨集合复杂 Join 客户端手动合并 ⭐⭐ 减少 DB 压力,但增加网络 IO
报表格式化 聚合 $project ⭐⭐⭐⭐ 直接在 DB 层清洗数据
相关推荐
想躺平的小羊2 小时前
关于金额在数据库设置类型问题
数据库
zhangchaoxies2 小时前
MySQL触发器能否监控特定用户操作_结合审计功能实现分析
jvm·数据库·python
chushiyunen2 小时前
faiss向量检索库(并非向量数据库)
数据库·faiss
qq_413502022 小时前
如何解决ORA-12518监听程序无法分配进程_内存耗尽与PGA溢出
jvm·数据库·python
Mr_pyx3 小时前
Java 注解(Annotation)详解:从基础到 APT 实战
java·数据库·sqlserver
djjdjdjdjjdj3 小时前
如何用参数解构在函数入口处直接提取对象属性
jvm·数据库·python
forEverPlume3 小时前
mysql如何批量增加表的字段_脚本化DDL操作实践
jvm·数据库·python
精益数智工坊3 小时前
物料管理是什么?物料管理的具体工作有哪些?
大数据·前端·数据库·人工智能·精益工程
m0_596406373 小时前
CSS如何高效引入样式表_对比link标签与import指令的性能差异
jvm·数据库·python