猫鼬和打字稿如何自动将'_id'转换为'id'?

How does mongoose and typescript convert '_id' to 'id' automatically?

我正在使用 NestJs (TypeScript) 和 mongoose 来保持 mongodb,我有一个这样的界面(在一个文件中):

import * as mg from 'mongoose' ; 

export const ProductSchema = new mg.Schema(
  {
    title: { type : String, required: true}, 
    description: { type : String, required: true}, 
    price: { type: Number, required: true} 

  }
)
export interface Product{
  title: string ;  
  description: string ; 
  price: number ;
  
}

然后另一个 class 使用该模型,如下所示:

@Injectable()
export class ProductsService {
    private products: Product[] = [];

    constructor(
        @InjectModel('Product') private readonly productModel: Model<Product>
    ) { };

    async findProduct(prodId: string) {
        
        const product = await this.productModel.findById(prodId)

        if (!product) {
            console.log("product null")
            throw new NotFoundException('no product with that id');
        }
   
        return { id: product.id, title: product.title, description: product.description, price: product.price };

    }
}

令人惊讶的是,在最后一个函数 findProduct() 中,当我执行 product.id(最后一行)时没有出现任何错误,而且代码运行起来非常神奇。显然,我的Product模型中没有字段id,当然在mongodb中,id字段是_id(id前有下划线)。

为什么代码有效?

Moongose's Schemas add a virtual getter id by default 并且可以关闭。

这是链接函数的 source code(自 v6.0.12 起),在给定特定 Schema:

实例化 Model 时调用该链接函数
'use strict';

module.exports = function addIdGetter(schema) {
  // ensure the documents receive an id getter unless disabled
  const autoIdGetter = !schema.paths['id'] &&
    schema.paths['_id'] &&
    schema.options.id;
  if (!autoIdGetter) {
    return schema;
  }

  schema.virtual('id').get(idGetter);

  return schema;
};

/*!
 * Returns this documents _id cast to a string.
 */

function idGetter() {
  if (this._id != null) {
    return String(this._id);
  }

  return null;
}

我们可以在其中看到它作为虚拟 属性 添加到具有 getter 函数的模式中,returns 属性 _id 转换为String