如何将缺失实例方法委托给Mongoose文档?实现业务与数据逻辑分离
解决方案
以下是实现业务逻辑与数据逻辑分离的完整代码,通过Proxy正确委托Mongoose文档的属性和方法,同时保留自定义业务逻辑:
const { Schema, model, ObjectId } = require('mongoose'); // 定义Mongoose Schema const AboutSchema = new Schema({ slogan: String, description: String, }); const CompanySchema = new Schema({ name: String, about: AboutSchema, status: String, user: ObjectId, email: String }); const CompanyModel = model('Company', CompanySchema); class Company { #document; constructor(document) { // 验证传入的是Mongoose文档实例 if (!document || !document._doc) { throw new Error('必须传入有效的Mongoose文档实例'); } this.#document = document; return new Proxy(this, { get(target, prop, receiver) { // 优先返回自身的业务方法/属性 if (Reflect.has(target, prop)) { return Reflect.get(target, prop, receiver); } // 其余属性/方法委托给Mongoose文档 return Reflect.get(target.#document, prop); }, set(target, prop, value, receiver) { // 优先将属性修改同步到Mongoose文档 if (Reflect.has(target.#document, prop)) { Reflect.set(target.#document, prop, value); return true; } // 自身属性的修改 return Reflect.set(target, prop, value, receiver); } }); } // 自定义业务方法:发送公司邮件 sendEmail() { console.log(`触发业务逻辑:向 ${this.email} 发送邮件`); // 这里可以集成邮件服务(如Nodemailer)实现具体发送逻辑 } // 自定义业务方法:激活公司状态 async activate() { this.status = 'active'; await this.save(); console.log(`公司 ${this.name} 已激活`); } } // 使用示例 async function runExample() { // 异步获取Mongoose文档 const doc = await CompanyModel.findOne({ email: 'some@company.com' }); if (!doc) return console.log('未找到目标公司'); const company = new Company(doc); // 调用自定义业务方法 company.sendEmail(); // 修改属性(自动委托到Mongoose文档) company.name = 'Updated Company Name'; company.about.slogan = '更新后的企业口号'; // 调用Mongoose原生方法(自动委托) await company.save(); // 调用自定义业务方法 await company.activate(); } runExample();
关键改进点
- Proxy路由逻辑优化:
- Get陷阱优先返回
Company类自身的属性/方法(如sendEmail),确保业务逻辑优先执行;未匹配到的属性/方法直接从Mongoose文档获取。 - Set陷阱优先将属性修改同步到Mongoose文档,保证所有属性变更都能被Mongoose追踪,嵌套属性修改(如
about.slogan)也会直接作用于原始文档,保存时自动生效。
- Get陷阱优先返回
- 私有字段访问:在类的内部上下文创建Proxy,因此可以直接访问私有字段
#document,无需额外暴露。 - 类型验证:在构造函数中添加文档实例验证,避免传入无效数据。
- 异步逻辑处理:示例中使用
async/await正确处理Mongoose的异步操作(findOne、save)。
优势
- 业务逻辑完全封装在
Company类中,与Mongoose的数据操作逻辑解耦,代码更易维护。 - 外部调用时无需区分业务方法和Mongoose原生方法,实现透明委托。
- 嵌套属性的修改自然同步到Mongoose文档,无需额外处理。
内容的提问来源于stack exchange,提问作者Thiago Ururay
相关产品推荐
相关产品推荐

