服务端2月22日 19:54
Mongoose 插件怎么写?schema.plugin() 的原理是什么?Mongoose 插件是一个接收 `schema` 和 `options` 参数的函数,通过 `schema.plugin(pluginFn, options)` 注册。插件内部可以调用 `schema.add()` 添加字段、`schema.pre()/post()` 注册中间件、`schema.method()` 添加实例方法、`schema.static()` 添加静态方法,本质就是对 Schema 的封装扩展。常用社区插件:`mongoose-paginate-v2` 分页、`mongoose-delete` 软删除、`mongoose-unique-validator` 唯一校...服务端2月22日 19:45
Mongoose 实例方法和静态方法有什么区别?实例方法定义在 schema.methods 上,通过文档实例调用,this 指向当前文档,适合操作单条记录(如密码比对、计算总价)。静态方法定义在 schema.statics 上,通过模型类调用,this 指向模型本身,适合查询和批量操作(如按邮箱查找、统计数量)。核心区别:需不需要访问文档实例数据。
## 追问
**this 上下文在两种方法中分别是什么?**
实例方法中 this 是当前 Document 实例,可访问 this.name、this.save() 等。静态方法中 this 是 Model 构造函数,等价于 User,可直接调用 this.find()、this...服务端2月25日 23:08
JavaScript 中如何解析和序列化 JSON?有哪些高级用法?JavaScript 通过 `JSON.parse()` 将 JSON 字符串转为 JS 值,通过 `JSON.stringify()` 将 JS 值转为 JSON 字符串。基本用法直观,但有几个关键细节:`JSON.parse()` 第二个参数 reviver 可在解析时转换值(如把日期字符串还原为 Date 对象);`JSON.stringify()` 第二个参数 replacer 可过滤或转换属性,第三个参数 space 控制缩进格式化输出。序列化时 undefined 和函数在对象中会被忽略、在数组中变为 null,Date 转为 ISO 字符串,RegExp 变为空对象,Sym...服务端2月22日 19:44
Mongoose 查询性能怎么优化?Mongoose 性能优化核心三板斧:.lean() 返回纯 JS 对象跳过文档 hydrated 过程提速 5-10 倍;.select() 投影只取需要的字段减少传输;合理建索引覆盖高频查询。三者组合使用效果最显著,读多写少的场景优先考虑 lean。
## 追问
**.lean() 具体省掉了什么?**
Mongoose 默认将查询结果包装为 Document 实例,附带 change tracking、虚拟字段、方法等。lean() 跳过这些直接返回 POJO,丧失 save()、modify 等实例能力,但只读场景下性能提升显著。
**复合索引的 ESR 规则是什么?**
...服务端2月22日 19:55
Mongoose 和原生 MongoDB 驱动有什么区别,各适合什么场景?核心区别在于抽象层级:Mongoose 是 ODM,通过 Schema 强制文档结构、内置验证、中间件钩子和类型转换;原生驱动是薄封装,直接操作集合,无结构约束,灵活但需手动处理验证和安全。Mongoose 适合需要数据一致性保障的业务系统,原生驱动适合高性能场景和非结构化数据处理。
## 追问
**Mongoose 的性能开销主要来自哪里?**
三个来源:文档实例化(每条查询结果包装为 Mongoose Document)、Schema 验证和类型转换(save 前的校验链)、查询结果钩子(post hook 执行)。高读场景用 `.lean()` 跳过文档实例化,性能接近原生驱动...服务端2月22日 19:43
Mongoose 事务怎么用?乐观锁和悲观锁有什么区别?Mongoose 事务依赖 MongoDB 副本集(单机不支持),通过 `session` 实现多文档原子操作。核心流程:`startSession()` 创建会话,`session.startTransaction()` 开启事务,操作时每条 CRUD 必须传 `{ session }` 参数,最后 `commitTransaction()` 或 `abortTransaction()`,`endSession()` 释放资源。推荐用 `withTransaction()` 辅助方法自动提交/回滚。常见坑:忘记在操作中传 session 参数导致操作不在事务内、事务超时默认 60 秒需...服务端2月25日 23:07
JSON 的语法规则有哪些?哪些是容易踩坑的?JSON 语法看似简单,但有几条规则与 JavaScript 对象字面量不同,容易踩坑。核心规则:键名必须用双引号包裹(`"name"` 不能写成 `name`);字符串也只能用双引号,单引号非法;最后一个键值对后不能有尾逗号;不支持注释;值只能是 string、number、boolean、null、object、array 六种类型,不支持 undefined、Date、Function、RegExp。数字不支持前导零(`01` 非法)和 NaN/Infinity。字符串中的特殊字符需转义,如 `\n`、`\"`、`\\`。大小写敏感:只有小写的 `true`、`false`、`nu...服务端2月22日 19:53
Mongoose 子文档和引用怎么选?子文档是嵌套在父文档中的 Schema,分单个子文档和子文档数组两种形式。子文档与父文档同生同灭、原子更新,适合总是一起访问且数量有限的数据。当数据需要独立查询、数量可能很大时,改用 ObjectId 引用。
## 追问
**子文档的验证是何时触发的?**
父文档保存时,子文档的验证会自动级联触发。如果子文档校验失败,整个保存操作回滚,无需手动调用子文档验证。
**子文档怎么访问父文档?**
通过子文档的 $parent 属性:comment.$parent 可拿到所属的 post 文档,便于在子文档方法中读取父级上下文。
**向子文档数组添加元素有哪些方式?**
push/un...服务端2月22日 19:42
Mongoose 中间件的 pre 和 post 钩子怎么用?Mongoose 中间件分两类:文档中间件(作用于 `save`/`validate`/`remove`,`this` 指向文档实例)和查询中间件(作用于 `find`/`findOne`/`updateOne`/`deleteOne`,`this` 指向 Query 对象)。`pre` 钩子在操作前执行,可修改数据或通过 `next(err)` 中止操作;`post` 钩子在操作后执行,接收结果参数,不能中止但适合日志和通知。异步中间件用 `async function` 即可,不需要手动调 `next()`,抛异常自动中止。经典场景:pre save 哈希密码、post save 写...服务端2月22日 19:42
Mongoose 数据验证有哪些类型,自定义验证器怎么写?Mongoose 验证分内置和自定义两类。内置验证器包括:required(必填)、min/max(数值范围)、minlength/maxlength(字符串长度)、enum(枚举值)、match(正则匹配)。自定义验证通过字段的 `validate` 选项实现,支持同步和异步两种方式。验证默认在 `save()` 时触发,也可显式调用 `validate()` 或 `validateSync()`。
## 追问
**unique 是验证器吗?它和 required 有什么本质区别?**
unique 不是验证器,是索引声明器。它在数据库层创建唯一索引,Mongoose 验证阶段不检...