使用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
相关产品推荐
相关产品推荐

