ChatGPT解决这个技术问题 Extra ChatGPT

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

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

模型.find().lean()

T
Tamlyn

Mongoose Model 继承自具有 toObject() 方法的 Document。我相信您正在寻找的应该是 doc.toObject() 的结果。

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


终于明白了。对于未定义 toObject 的人,请确保调用文档而不是模型。即modelName._doc.toObject()
这没关系,但更喜欢lean()。
如果您在 Model.find({}) 上返回数组,这是否有效,文档返回的是一个数组。你能 docs.toObject 吗?
@jackblank 如果您有一组模型,那么您应该能够映射它们:var docArray = modelArray.map(function(model) { return model.toObject(); });
遗憾的是,这不适用于嵌套项目 afaik - 我数组中的对象仍然是猫鼬特殊的
J
JohnnyHK

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

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

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

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

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


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

JohnnyHK 建议:

在某些情况下,正如@JohnnyHK 所建议的那样,您可能希望将 Object 作为纯 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)) 一样,而是来自 mongoose 类型的 ObjectId,所以在将它与字符串进行比较时,将其转换为之前的字符串:String(object._id) === otherStringId


把 toObject 作为一个字符串,否则你会得到一个错误。谢谢你的解决方案。
J
Jalasem

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

doc.toObject({ getters: true })

其他选项包括:

getters:应用所有 getter(路径和虚拟 getter)

virtuals:应用虚拟吸气剂(可以覆盖吸气剂选项)

最小化:删除空对象(默认为 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


d
dd619

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

mongooseDoc._doc  //returns plain json object

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


在开头使用 _ 访问属性或方法并不是理想的解决方案。使用精益可能会解决您的问题。
@ArthurBrito 是的。它不是一个理想的解决方案,但它仍然是一个解决方案!我已经多次使用 _doc 属性而没有遇到任何问题。并且使用 lean 方法为您提供了无法执行猫鼬模型操作的普通对象。
A
Amir BenAmara

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

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

不需要使用 JSON.parse() 方法


k
kaushik_pm

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

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

这还具有将 _id 作为字符串的优点。
JSON.parse 是一个非常慢的命令并且对性能非常重要。
真的,您如何衡量它的速度@BertC
@chuklore,类似这样的各种文章:itnext.io/…
C
Cizia

我一直在我的文档上使用 toObject 方法,但没有成功。我需要将 flattenMap 属性添加到 true 以最终获得 POJO。

const data = document.data.toObject({ flattenMaps: true });