如何在Mongoose中从关联模型填充虚拟字段?
解决Mongoose Populate时获取关联文档虚拟字段的问题
我来帮你搞定这个问题,你遇到的情况是因为用了.lean()之后,Mongoose返回的是纯JavaScript对象,而非它的Document实例,这时候默认不会触发Schema里配置的虚拟字段序列化规则。另外,默认的populate操作在lean模式下也不会自动带上关联文档的虚拟字段,所以我们需要调整查询配置来解决。
方法1:在Populate时指定Lean选项包含虚拟字段
这是最直接的适配你现有代码的方案,只需修改populate的参数,明确要求填充的文档包含虚拟字段:
const getAllData = async () => { const shops = await Shop.find() .populate({ path: "owner", lean: { virtuals: true } // 指定填充owner时要包含其虚拟字段 }) .lean({ virtuals: true }); // 若Shop自身有虚拟字段需返回则添加,否则可只保留populate内的配置 console.log(shops); };
说明
.populate({ path: "owner", lean: { virtuals: true } }):告诉Mongoose,即使在lean模式下填充owner,也要将其虚拟字段(比如fullName)纳入返回结果。- 后续的
.lean({ virtuals: true }):如果你的Shop模型本身也有需要返回的虚拟字段,就加上这部分;若不需要,仅保留populate内的配置即可。
方法2:去掉.lean()(业务允许的情况下)
如果你的代码不需要纯JS对象,能接受Mongoose的Document实例,去掉.lean()后,填充回来的owner是Document对象,此时通过toJSON()或toObject()方法就能获取包含虚拟字段的对象:
const getAllData = async () => { const shops = await Shop.find().populate("owner"); // 将每个shop转换为包含虚拟字段的JS对象 const shopsWithVirtuals = shops.map(shop => shop.toJSON()); console.log(shopsWithVirtuals); };
因为你已经在PersonSchema里配置了toJSON: { virtuals: true },调用toJSON()时会自动把fullName虚拟字段包含进去。
方法3:全局配置Lean默认包含虚拟字段(可选)
如果你的项目中有大量场景需要用lean且包含虚拟字段,可以在Mongoose全局设置:
mongoose.set('leanVirtuals', true);
设置后,所有.lean()查询都会自动包含虚拟字段(包括populate的关联文档),你原来的查询代码无需修改就能拿到fullName。不过要注意这个全局设置的影响范围,确保所有业务场景都需要这个行为。
验证效果
无论用哪种方法,执行查询后,打印的shops数据里的owner对象都会出现fullName字段,示例如下:
[ { _id: ObjectId("xxx"), name: "My Shop", owner: { _id: ObjectId("yyy"), name: { first: "John", last: "Doe" }, fullName: "John Doe" // 虚拟字段已成功返回 } } ]
内容的提问来源于stack exchange,提问作者yathomasi
相关产品推荐
相关产品推荐

