如何将 Mongoose 文档转换为普通对象?

Posted

技术标签:

【中文标题】如何将 Mongoose 文档转换为普通对象?【英文标题】:How do you turn a Mongoose document into a plain object? 【发布时间】:2016-07-13 00:22:49 【问题描述】:

我有一个来自 mongoose 的文档,我想在 JSON 编码之前扩展它并作为响应发送出去。如果我尝试向文档添加属性,它将被忽略。 Object.getOwnPropertyNames(doc) 中没有出现这些属性,因此无法进行正常扩展。奇怪的是JSON.parse(JSON.encode(doc)) 工作并返回具有所有正确属性的对象。有没有更好的方法来做到这一点?

【问题讨论】:

【参考方案1】:

Mongoose Models 继承自 Documents,它有一个 toObject() 方法。我相信你要找的应该是doc.toObject()的结果。

http://mongoosejs.com/docs/api.html#document_Document-toObject

【讨论】:

终于明白了。对于未定义 toObject 的人,请确保调用文档而不是模型。即 modelName._doc.toObject() 这没关系,但更喜欢lea()。 如果您在Model.find() 上返回数组,这是否有效,文档返回的是一个数组。你能 docs.toObject 吗? @jackblank 如果你有一个模型数组,那么你应该能够映射它们:var docArray = modelArray.map(function(model) return model.toObject(); ); @jmar777 我认为您的建议属于对此答案的编辑。【参考方案2】:

另一种方法是通过在查询链中使用lean() 告诉Mongoose,您需要的只是返回文档的纯javascript 版本。这样 Mongoose 就跳过了创建完整模型实例的步骤,您可以直接得到一个 doc ,您可以修改:

MyModel.findOne().lean().exec(function(err, doc) 
    doc.addedProperty = 'foobar';
    res.json(doc);
);

【讨论】:

@Startec 使用 lean 通常性能更高,因为您跳过了首先创建完整 Mongoose 文档的开销。 你是冠军 :) 如果我错了,请纠正我,但如果你不打算修改和保存刚收到的文档,你应该总是倾斜()你的 find()(比如,如果您只是想访问该文档并将其发送回您的客户) @Amarsh 是的,尽管这也是假设您不需要架构中定义的任何实例方法或虚拟对象。 bizzare 虽然...这可能是 find() 的一个选项...从 mongodb 读取文档并将其发送回 Web 浏览器通常太常见了。我想知道 find().lean() 是否实际上意味着 find() 首先然后对结果中的每个元素应用一个 lean() ,在这种情况下, find().lean() 组合实际上会比 find() 慢本身。 @Amarsh 否,在查询上链接lean() 会在查询实际执行之前设置选项(通过exec),以便结果直接采用“精益”形式。请参阅this question,了解调用lean 对性能的积极影响。【参考方案3】:

如果属性不在模型中的快速方法:

document.set( key,value, strict: false );

【讨论】:

是的......尽管看起来很令人惊讶,但我仍然认为这可能很有用。例如,您保留所有对象的原语。 感谢您的回答,这正是我想要的:)【参考方案4】:

JohnnyHK 建议:

在某些情况下,正如@JohnnyHK 所建议的那样,您可能希望将对象作为纯 Javascript 获取。 如Mongoose Documentation 中所述,还有另一种方法可以直接将数据作为对象进行查询:

const docs = await Model.find().lean();

有条件地返回普通对象:

另外如果有人想有条件地转向一个对象,也可以作为option参数,见第三个参数find() docs:

const toObject = true;
const docs = await Model.find(,null,lean:toObject);

可用于以下功能:find()findOne()findById()findOneAndUpdate()findByIdAndUpdate()

注意:

还值得一提的是,_id 属性不是一个字符串对象,就像你会做 JSON.parse(JSON.stringify(object)) 一样,而是一个来自猫鼬类型的 ObjectId,所以在将它与字符串进行比较时,将其转换为之前的字符串:String(object._id) === otherStringId

【讨论】:

【参考方案5】:

解决此类问题的更好方法是像这样使用doc.toObject()

doc.toObject( getters: true )

其他选项包括:

getters: 应用所有 getter(路径和虚拟 getter) virtuals: 应用虚拟吸气剂(可以覆盖吸气剂选项) minimize:删除空对象(默认为true) transform: 在返回之前应用于结果文档的转换函数 depopulate: 删除所有填充的路径,用它们的原始引用替换它们(默认为 false) versionKey:是否包含版本密钥(默认为true)

例如你可以说

Model.findOne().exec((err, doc) => 
   if (!err) 
      doc.toObject( getters: true )
      console.log('doc _id:', doc._id)
   
)

现在它可以工作了。

参考见:http://mongoosejs.com/docs/api.html#document_Document-toObject

【讨论】:

【参考方案6】:

为了从 Mongoose 文档中获取普通对象,我使用了 _doc 属性,如下所示

mongooseDoc._doc  //returns plain json object

我尝试使用toObject,但它给了我函数、参数和所有其他我不需要的东西。

【讨论】:

一开始就使用_ 访问属性或方法不是理想的解决方案。使用精益可能会解决您的问题。 @ArthurBrito 是的。它不是一个理想的解决方案,但它仍然是一个解决方案! .无需对答案投反对票。我已经多次使用_doc 属性而没有遇到任何问题。使用lean 方法可以为您提供无法执行猫鼬模型操作的普通对象。 你是对的。只需添加您的答案,这不是理想的解决方案,然后我将删除反对票(除非您编辑,否则我无法删除)【参考方案7】:

lean 选项告诉 Mongoose 跳过水合结果文档。这使得查询更快,内存占用更少,但结果文档是普通的旧 JavaScript 对象 (POJO),而不是 Mongoose 文档。

const leanDoc = await MyModel.findOne().lean();

不必使用 JSON.parse() 方法

【讨论】:

【参考方案8】:

您还可以将对象字符串化,然后再次解析以生成普通对象。 例如:-

const obj = JSON.parse(JSON.stringify(mongoObj))

【讨论】:

这还具有将_id 作为字符串获取的优势。 JSON.parse 是一个非常慢的命令并且对性能的影响很大。

以上是关于如何将 Mongoose 文档转换为普通对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Mongoose 文档转换为普通对象?

如何将 Mongoose 文档转换为普通对象?

使用 mongoose 将多个不存在的文档插入 MongoDB

使用 mongoose 将多个不存在的文档插入 MongoDB

将普通对象投射到猫鼬文档

如何在 Mongoose/Node.js 中同时保存多个文档?