前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# 操作数据库

30 秒速记

  • 关系型(MySQL、PostgreSQL)表结构固定、支持 JOIN 和事务;文档型(MongoDB)存 JSON 风格文档,结构灵活
  • Node.js 里一般用驱动(mysql2、mongodb)或 ORM(Prisma、TypeORM、Mongoose)
  • 动态值一律走参数化查询,别拼字符串,防 SQL 注入
  • 服务里用连接池并复用,别每个请求都建连;脚本跑完记得关连接,不然进程不退出
  • 查询要有分页上限和索引,多步写入要原子就用事务

在 Node.js 里操作数据库,核心就三件事:连接怎么管、查询怎么写安全、多步操作怎么保证一致。 连接方面,常驻服务用连接池,启动时建好一直复用;一次性脚本跑完要主动关,否则连接挂着进程不会退出。查询方面,用户输入一律走参数化,? 占位交给驱动转义,拼字符串迟早被注入。一致性方面,扣库存加下单这种必须同时成功的操作放进事务,失败就回滚。选型上要关联、要事务的业务用 MySQL,结构多变的日志、内容类数据用 MongoDB 比较顺手。

理解「操作数据库」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 database 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

Node.js 操作数据库,不管用哪种库,套路都差不多:建连接(最好是连接池)→ 执行查询 → 处理结果和错误 → 归还或关闭连接。

以 mysql2 为例,一个比较规范的写法:

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASS,
  database: 'shop',
  connectionLimit: 10, // 池里最多 10 个连接
});

// 普通查询:pool.query 会自动取连接、用完归还
async function getUser(id) {
  const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
  return rows[0] ?? null; // 查不到返回 null,不要当成错误
}

// 事务:必须拿一个固定连接
async function createOrder(userId, goodsId) {
  const conn = await pool.getConnection();
  try {
    await conn.beginTransaction();
    await conn.query('UPDATE goods SET stock = stock - 1 WHERE id = ? AND stock > 0', [goodsId]);
    await conn.query('INSERT INTO orders (user_id, goods_id) VALUES (?, ?)', [userId, goodsId]);
    await conn.commit();
  } catch (err) {
    await conn.rollback();
    throw err;
  } finally {
    conn.release(); // 无论成败都归还
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

数据库访问要区分查询结果和执行错误:参数用 ? 占位;查不到数据返回 null,连接或语法错误则向上抛出。事务中的语句共用 getConnection() 拿到的连接,release() 放在 finally;一次性脚本结束时再调用 pool.end() 关闭连接池。

面试官追问

追问 1一个导数据的脚本写完库之后不退出,挂在那里,为什么?
参考回答

连接或连接池还开着,事件循环里有活跃句柄,进程就不会退。在 finally 里 await pool.end() 或 client.close(),成功和失败都要走到。

追问 2批量导入有一条数据格式错了,脚本还是以退出码 0 结束,CI 判成功了,怎么改?
参考回答

捕获到错误要 process.exitCode = 1,或者直接把异常抛出去让进程非零退出。允许跳过坏数据的话,至少把成功数和失败数打出来,失败数大于 0 就别返回 0。

追问 3下单要扣库存再插订单,第二步失败了,库存已经扣掉了怎么办?
参考回答

这两步要放在同一个事务里:beginTransaction,两条都成功再 commit,任何一步出错 rollback。注意事务里的语句必须用同一个连接,用 pool.query 每次可能拿到不同连接,事务就失效了。

追问 4线上数据库连接数一直涨,重启服务就好了,像什么问题?
参考回答

典型的连接泄漏,八成是某个分支拿了连接没还,比如 getConnection 之后提前 return 或者抛异常没走到 release()。把 release() 放进 finally,再看连接池的活跃数指标能不能稳住。

追问 5用了 ORM 是不是就不会有注入问题了?
参考回答

正常用 API 时基本安全,但 ORM 也都提供原生查询,比如 Prisma 的 $queryRawUnsafe,里面拼字符串一样会被注入。原生查询用带参数的版本,比如 $queryRaw 的模板字符串写法。

# MongoDB 基础

30 秒速记

  • MongoDB 是文档型数据库:库(database)→ 集合(collection)→ 文档(document),对应 MySQL 的库、表、行
  • 文档是 BSON(二进制 JSON),同一个集合里字段可以不一样,不用提前建表
  • 每个文档都有唯一的 _id,默认是 ObjectId
  • 常用操作:insertOne / find / updateOne / deleteOne,查询条件本身也是对象,如 { age: { $gt: 18 } }
  • 适合结构多变、读写量大的内容类数据;强关联、强事务的业务还是关系型更稳(4.0 起才支持多文档事务)

MongoDB 是文档型数据库,数据以类似 JSON 的文档存在集合里,不需要像 MySQL 那样先定义表结构。 对照着记最快:库还是库,表叫集合,行叫文档,每个文档自带一个唯一的 _id。查询条件也写成对象,比如 { age: { $gt: 18 } } 就是年龄大于 18。它的好处是字段灵活、嵌套结构天然好存,比如一篇文章连同评论数组放一个文档里;代价是关联查询弱,多文档事务从 4.0 才支持,账务类业务我一般不选它。

MongoDB教程 https://www.yiibai.com/mongodb

理解「MongoDB 基础」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 database 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

MongoDB 的几个基本概念和 MySQL 对照着记:

MySQL MongoDB
数据库 数据库
表 集合(collection)
行 文档(document)
列 字段(field)
主键 _id(默认 ObjectId)

文档存的是 BSON,比 JSON 多了日期、二进制、ObjectId 等类型。一个文档大致长这样:

{
  _id: ObjectId('652f...'),
  title: '前端面试题',
  tags: ['js', 'css'],
  author: { name: '小王', level: 3 },
  createdAt: ISODate('2026-10-01T00:00:00Z')
}
@前端进阶之旅: 代码已经复制到剪贴板

在 mongosh 里的常用操作:

db.posts.insertOne({ title: 'hello', views: 0 })
db.posts.find({ views: { $gt: 100 } }).sort({ createdAt: -1 }).limit(10)
db.posts.updateOne({ title: 'hello' }, { $inc: { views: 1 } })
db.posts.deleteOne({ title: 'hello' })
db.posts.createIndex({ createdAt: -1 }) // 按时间排序的列表一定要建索引
@前端进阶之旅: 代码已经复制到剪贴板

查询操作符以 $ 开头:$gt 大于、$in 在列表里、$set 设置字段、$inc 自增。选型上,内容、日志、配置这类结构多变、嵌套多的数据用 MongoDB 很顺手;订单、账务这类强关联、强一致的数据,还是 MySQL、PostgreSQL 更稳妥。

面试官追问

追问 1按一个不存在的 _id 查商品,返回 null,接口该报 500 吗?
参考回答

不该。查不到是正常结果,返回 404 或空数据就行;连不上库、命令执行报错才是 500。这两种情况混在一起,告警会被用户输错的 id 刷屏。

基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
      • MongoDB 基础
        • Node.js 操作 MongoDB
      • MySql 基础
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

操作数据库|Nodejs专题系列

# 操作数据库

30 秒速记

  • 关系型(MySQL、PostgreSQL)表结构固定、支持 JOIN 和事务;文档型(MongoDB)存 JSON 风格文档,结构灵活
  • Node.js 里一般用驱动(mysql2、mongodb)或 ORM(Prisma、TypeORM、Mongoose)
  • 动态值一律走参数化查询,别拼字符串,防 SQL 注入
  • 服务里用连接池并复用,别每个请求都建连;脚本跑完记得关连接,不然进程不退出
  • 查询要有分页上限和索引,多步写入要原子就用事务

在 Node.js 里操作数据库,核心就三件事:连接怎么管、查询怎么写安全、多步操作怎么保证一致。 连接方面,常驻服务用连接池,启动时建好一直复用;一次性脚本跑完要主动关,否则连接挂着进程不会退出。查询方面,用户输入一律走参数化,? 占位交给驱动转义,拼字符串迟早被注入。一致性方面,扣库存加下单这种必须同时成功的操作放进事务,失败就回滚。选型上要关联、要事务的业务用 MySQL,结构多变的日志、内容类数据用 MongoDB 比较顺手。

理解「操作数据库」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 database 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

Node.js 操作数据库,不管用哪种库,套路都差不多:建连接(最好是连接池)→ 执行查询 → 处理结果和错误 → 归还或关闭连接。

以 mysql2 为例,一个比较规范的写法:

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASS,
  database: 'shop',
  connectionLimit: 10, // 池里最多 10 个连接
});

// 普通查询:pool.query 会自动取连接、用完归还
async function getUser(id) {
  const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
  return rows[0] ?? null; // 查不到返回 null,不要当成错误
}

// 事务:必须拿一个固定连接
async function createOrder(userId, goodsId) {
  const conn = await pool.getConnection();
  try {
    await conn.beginTransaction();
    await conn.query('UPDATE goods SET stock = stock - 1 WHERE id = ? AND stock > 0', [goodsId]);
    await conn.query('INSERT INTO orders (user_id, goods_id) VALUES (?, ?)', [userId, goodsId]);
    await conn.commit();
  } catch (err) {
    await conn.rollback();
    throw err;
  } finally {
    conn.release(); // 无论成败都归还
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

数据库访问要区分查询结果和执行错误:参数用 ? 占位;查不到数据返回 null,连接或语法错误则向上抛出。事务中的语句共用 getConnection() 拿到的连接,release() 放在 finally;一次性脚本结束时再调用 pool.end() 关闭连接池。

面试官追问

追问 1一个导数据的脚本写完库之后不退出,挂在那里,为什么?
参考回答

连接或连接池还开着,事件循环里有活跃句柄,进程就不会退。在 finally 里 await pool.end() 或 client.close(),成功和失败都要走到。

追问 2批量导入有一条数据格式错了,脚本还是以退出码 0 结束,CI 判成功了,怎么改?
参考回答

捕获到错误要 process.exitCode = 1,或者直接把异常抛出去让进程非零退出。允许跳过坏数据的话,至少把成功数和失败数打出来,失败数大于 0 就别返回 0。

追问 3下单要扣库存再插订单,第二步失败了,库存已经扣掉了怎么办?
参考回答

这两步要放在同一个事务里:beginTransaction,两条都成功再 commit,任何一步出错 rollback。注意事务里的语句必须用同一个连接,用 pool.query 每次可能拿到不同连接,事务就失效了。

追问 4线上数据库连接数一直涨,重启服务就好了,像什么问题?
参考回答

典型的连接泄漏,八成是某个分支拿了连接没还,比如 getConnection 之后提前 return 或者抛异常没走到 release()。把 release() 放进 finally,再看连接池的活跃数指标能不能稳住。

追问 5用了 ORM 是不是就不会有注入问题了?
参考回答

正常用 API 时基本安全,但 ORM 也都提供原生查询,比如 Prisma 的 $queryRawUnsafe,里面拼字符串一样会被注入。原生查询用带参数的版本,比如 $queryRaw 的模板字符串写法。

# MongoDB 基础

30 秒速记

  • MongoDB 是文档型数据库:库(database)→ 集合(collection)→ 文档(document),对应 MySQL 的库、表、行
  • 文档是 BSON(二进制 JSON),同一个集合里字段可以不一样,不用提前建表
  • 每个文档都有唯一的 _id,默认是 ObjectId
  • 常用操作:insertOne / find / updateOne / deleteOne,查询条件本身也是对象,如 { age: { $gt: 18 } }
  • 适合结构多变、读写量大的内容类数据;强关联、强事务的业务还是关系型更稳(4.0 起才支持多文档事务)

MongoDB 是文档型数据库,数据以类似 JSON 的文档存在集合里,不需要像 MySQL 那样先定义表结构。 对照着记最快:库还是库,表叫集合,行叫文档,每个文档自带一个唯一的 _id。查询条件也写成对象,比如 { age: { $gt: 18 } } 就是年龄大于 18。它的好处是字段灵活、嵌套结构天然好存,比如一篇文章连同评论数组放一个文档里;代价是关联查询弱,多文档事务从 4.0 才支持,账务类业务我一般不选它。

MongoDB教程 https://www.yiibai.com/mongodb

理解「MongoDB 基础」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 database 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

MongoDB 的几个基本概念和 MySQL 对照着记:

MySQL MongoDB
数据库 数据库
表 集合(collection)
行 文档(document)
列 字段(field)
主键 _id(默认 ObjectId)

文档存的是 BSON,比 JSON 多了日期、二进制、ObjectId 等类型。一个文档大致长这样:

{
  _id: ObjectId('652f...'),
  title: '前端面试题',
  tags: ['js', 'css'],
  author: { name: '小王', level: 3 },
  createdAt: ISODate('2026-10-01T00:00:00Z')
}
@前端进阶之旅: 代码已经复制到剪贴板

在 mongosh 里的常用操作:

db.posts.insertOne({ title: 'hello', views: 0 })
db.posts.find({ views: { $gt: 100 } }).sort({ createdAt: -1 }).limit(10)
db.posts.updateOne({ title: 'hello' }, { $inc: { views: 1 } })
db.posts.deleteOne({ title: 'hello' })
db.posts.createIndex({ createdAt: -1 }) // 按时间排序的列表一定要建索引
@前端进阶之旅: 代码已经复制到剪贴板

查询操作符以 $ 开头:$gt 大于、$in 在列表里、$set 设置字段、$inc 自增。选型上,内容、日志、配置这类结构多变、嵌套多的数据用 MongoDB 很顺手;订单、账务这类强关联、强一致的数据,还是 MySQL、PostgreSQL 更稳妥。

面试官追问

追问 1按一个不存在的 _id 查商品,返回 null,接口该报 500 吗?
参考回答

不该。查不到是正常结果,返回 404 或空数据就行;连不上库、命令执行报错才是 500。这两种情况混在一起,告警会被用户输错的 id 刷屏。

追问 2用户传的查询条件直接塞进 find() 有什么风险?
参考回答

NoSQL 注入。比如登录时前端传 { "password": { "$ne": "" } },直接当条件就能匹配任意密码。入参要校验类型,字符串字段就强制 String(x),或者用 zod 这类库限定结构。

追问 3集合里字段不固定,是不是就不用管数据结构了?
参考回答

恰恰相反,结构灵活意味着约束要自己做。用 Mongoose 的 Schema 或者 MongoDB 自带的 $jsonSchema 校验,不然半年后同一个字段会出现字符串、数字、数组好几种类型。

追问 4订单表和用户表要频繁关联查询,适合用 MongoDB 吗?
参考回答

不太适合。MongoDB 有 $lookup 能做关联,但性能和写法都不如 SQL 的 JOIN。关系强、要事务的业务优先关系型数据库。

追问 5列表接口 find({}) 不加限制,数据量大了会怎样?
参考回答

toArray() 会把所有文档一次性读进内存,几十万条就能把接口拖慢甚至把进程撑爆。一定要 .limit() 加分页,查询字段建索引,用 .explain() 确认走了索引。

# Node.js 操作 MongoDB

← 9.2 koa jsonp中间件Session 与 Token →

fe