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

使用map处理Mongoose查询结果后为何出现_doc及内部属性?

Mongoose查询结果map后出现内部属性的问题解决

问题场景

我尝试对Mongoose的查询结果用map方法格式化价格,代码如下:

ProductModel.find()
.sort({ _id: -1 })
.then((products) => {

    console.log(products)

    products = products.map((product) => {
      return { ...product, price: toIdr(product.price) };
    });

    console.log(products)

    res.render("index", {
      title: "Home",
      products,
      path: req.path,
    });
  });

第一次打印的结果看起来是干净的对象:

[
  {
    _id: new ObjectId('65ffe52c31f86de770a5110c'),
    title: 'naruto',
    price: 32000,
    description: 'Vel corporis laboriosam. Fugit sed unde nulla nesciunt laudantium.',
    imageUrl: '/assets/book1.jpg',
    userId: new ObjectId('65ffe505f94c639905f4ba13'),
    __v: 0
  }
]

但经过map处理后,第二次打印出现了大量Mongoose内部属性:

[
  {
    '$__': InternalCache { activePaths: [StateMachine], skipId: true },
    '$isNew': false,
    _doc: {
      _id: new ObjectId('65ffe52c31f86de770a5110c'),
      title: 'naruto',
      price: 32000,
      description: 'Vel corporis laboriosam. Fugit sed unde nulla nesciunt laudantium.',
      imageUrl: '/assets/book1.jpg',
      userId: new ObjectId('65ffe505f94c639905f4ba13'),
      __v: 0
    },
    price: 'Rp 32.000,00'
  }
]

我想要的是这样的干净对象结构:

[
  {
    _id: new ObjectId('65ffe52c31f86de770a5110c'),
    title: 'naruto',
    price: 'Rp 32.000,00',
    description: 'Vel corporis laboriosam. Fugit sed unde nulla nesciunt laudantium.',
    imageUrl: '/assets/book1.jpg',
    userId: new ObjectId('65ffe505f94c639905f4ba13'),
    __v: 0
  }
]

原因分析

Mongoose查询返回的不是普通JavaScript对象,而是Mongoose文档对象(Document),这类对象自带ORM相关的内部属性(比如$__、_doc)和方法,用来实现数据校验、关联查询等功能。

你用...product展开语法时,会把文档对象的内部属性也一并展开;而第一次打印看起来干净,是因为Mongoose对文档对象的console.log做了重载,默认只显示_doc里的真实数据,不会暴露内部属性。

解决方法

方法1:用.toObject()转成普通对象

在map时先把文档对象转换为普通JS对象,再修改价格:

products = products.map((product) => {
  const plainProduct = product.toObject();
  return { ...plainProduct, price: toIdr(plainProduct.price) };
});

方法2:查询时直接返回普通对象

在find()后添加.lean(),让Mongoose跳过文档对象的创建,直接返回纯JS对象,这是最高效的方案:

ProductModel.find()
.sort({ _id: -1 })
.lean() // 关键:返回普通对象
.then((products) => {
    products = products.map((product) => {
      return { ...product, price: toIdr(product.price) };
    });
    res.render("index", {
      title: "Home",
      products,
      path: req.path,
    });
  });

方法3:直接修改_doc属性(不推荐)

可以直接修改_doc里的价格,但这样会改动原始文档对象,且打印显示仍依赖Mongoose的重载,不如前两种方法直观:

products = products.map((product) => {
  product._doc.price = toIdr(product.price);
  return product;
});

内容的提问来源于stack exchange,提问作者Lutfi Khoirudin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 06:00:09