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 唯一校验。全局注册用 mongoose.plugin(fn) 对之后创建的所有 Schema 生效。写自定义插件时注意:接受 options 参数提供可配置字段名;通过 schema.pre('find') 过滤而非覆盖查询;在插件中检查依赖字段是否存在避免隐性报错。
追问
插件执行顺序有影响吗? 有。plugin() 按调用顺序执行,后注册的中间件排后面。如果插件 A 在 pre save 中设置字段、插件 B 依赖该字段,A 必须先注册。
全局插件对已有模型生效吗? 不生效。mongoose.plugin() 只对调用之后新创建的 Schema 生效,已编译的 Model 不会回溯应用。
插件里能给 Schema 加虚拟属性吗? 可以,用 schema.virtual('name').get(fn)。但虚拟属性不持久化到数据库,且在 lean() 查询和 JSON 序列化时需显式配置 toJSON: { virtuals: true } 才能输出。
mongoose-delete 插件的 overrideMethods 选项有什么用? 设为 true 后,find()、findOne() 等方法自动过滤已删除文档,无需手动加条件。本质是注册了查询中间件 pre('find') 添加 deleted: { $ne: true } 条件。
写段代码
javascriptfunction paginatePlugin(schema) { schema.statics.paginate = async function(query, { page = 1, limit = 10 }) { const docs = await this.find(query) .skip((page - 1) * limit).limit(limit); const total = await this.countDocuments(query); return { docs, total, pages: Math.ceil(total / limit) }; }; } schema.plugin(paginatePlugin);