You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将缺失实例方法委托给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)也会直接作用于原始文档,保存时自动生效。
  • 私有字段访问:在类的内部上下文创建Proxy,因此可以直接访问私有字段#document,无需额外暴露。
  • 类型验证:在构造函数中添加文档实例验证,避免传入无效数据。
  • 异步逻辑处理:示例中使用async/await正确处理Mongoose的异步操作(findOne、save)。

优势

  • 业务逻辑完全封装在Company类中,与Mongoose的数据操作逻辑解耦,代码更易维护。
  • 外部调用时无需区分业务方法和Mongoose原生方法,实现透明委托。
  • 嵌套属性的修改自然同步到Mongoose文档,无需额外处理。

内容的提问来源于stack exchange,提问作者Thiago Ururay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 02:55:06