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

如何用Mongoose填充包含虚拟属性的嵌套文档?

问题

我定义了如下两个Mongoose Schema:

// foo.js
...

const fooSchema = new Schema(
  {
    name: {
      type: String
    }
  },
  {
    toJSON: {
      virtuals: true
    },
    toObject: {
      virtual: true
    }
  }
);

// sample virtual
fooSchema.virtual('sampleVirtual').get(function () {
  return 'I am a virtual'
});

export default mongoose.model( 'foo', fooSchema );

另一个Schema关联上述Schema:

// hello.js
...

const helloWorldSchema = new Schema(
  {
    name: {
      type: String,
      required: true
    },
    myFoo: {
      type: mongoose.Types.ObjectId,
      ref: 'foo'
    }
  },
  {
    toJSON: { 
      virtuals: true 
    },
    toObject: {
        virtual: true
    }
  }
);

export default mongoose.model( 'HelloWorld', helloWorldSchema );

我使用Mongoose的findOne()方法查询helloWorldSchema集合的文档,尝试填充myFoo文档的虚拟属性sampleVirtual:

// get.js
const retVal = await helloWorldModel
    .findOne({_id: <some-id> })
    .populate({ path: 'myFoo', select: '_id name sampleVirtual' })
    .exec();

console.log(retVal.myFoo.sampleVirtual) //undefined

请问我哪里操作出错了?


问题原因及解决办法

1. Schema配置拼写错误

两个Schema的toObject选项里,属性名写错成了virtual: true,正确的应该是virtuals: true(末尾带s)。这个配置控制文档转换成普通对象时是否包含虚拟属性,拼写错误会导致虚拟属性无法被正常输出。

2. Populate的select不能指定虚拟属性

虚拟属性是Mongoose运行时动态生成的,并非MongoDB中实际存储的字段,所以在populate的select参数里指定sampleVirtual是无效的,Mongoose会忽略这个不存在的字段。


修正后的代码

修正foo.js的Schema配置

// foo.js
...

const fooSchema = new Schema(
  {
    name: {
      type: String
    }
  },
  {
    toJSON: {
      virtuals: true
    },
    toObject: {
      virtuals: true // 修正为virtuals
    }
  }
);

// sample virtual
fooSchema.virtual('sampleVirtual').get(function () {
  return 'I am a virtual'
});

export default mongoose.model( 'foo', fooSchema );

修正hello.js的Schema配置

// hello.js
...

const helloWorldSchema = new Schema(
  {
    name: {
      type: String,
      required: true
    },
    myFoo: {
      type: mongoose.Types.ObjectId,
      ref: 'foo'
    }
  },
  {
    toJSON: { 
      virtuals: true 
    },
    toObject: {
        virtuals: true // 修正为virtuals
    }
  }
);

export default mongoose.model( 'HelloWorld', helloWorldSchema );

修正get.js的查询代码

// get.js
const retVal = await helloWorldModel
    .findOne({_id: <some-id> })
    .populate({ path: 'myFoo', select: '_id name' }) // 移除无效的sampleVirtual
    .exec();

console.log(retVal.myFoo.sampleVirtual) // 现在会输出"I am a virtual"

内容的提问来源于stack exchange,提问作者V. Pravi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 20:52:36