Mongoose中toObject和toJSON有什么区别?

28

Mongoose 的 toObject 文档 列出了 toObject 的特性、选项,并提供了 toObject 功能的示例。

toJSON 的 Mongoose 文档表示该选项与 toObject 相同,但并未解释 toJSON 的作用。在文档的其他地方,有这样的说明:

当调用文档的 toJSON 方法时,toJSON 与 toObject 选项完全相同。

toJSONtoObject 的别名吗?如果不是,它们有什么区别?

4个回答

28

查看源代码可知,这两种方法都调用了内部的$toObject方法,但是toJSON传递了第二个参数true

Document.prototype.toObject = function (options) {
  return this.$toObject(options);
};
...
Document.prototype.toJSON = function (options) {
  return this.$toObject(options, true);
};

第二个参数决定$toObject是否使用toJSONtoObject模式选项作为默认值。因此,除非这些模式选项已经配置不同,否则这两种方法是相同的。


2
顺便说一句,使用不同的toJSON配置实际上是有意义的 - 你可以在从控制器返回对象之前进行一些转换(在express中res.json(object)调用JSON.stringify即为object.toJSON) - 例如去除某些条目以避免堆栈溢出... - kboom

7

就像JohnnyHK的回答所说,toJSONtoObject之间没有区别。我猜测,toJSON是为了支持JSON.stringify方法而创建的。

根据MDN文档,如果一个对象有toJSON属性作为函数,JSON.stringify会使用toJSON函数来序列化对象,而不是使用对象本身。


5

根据我的使用情况,我得到了以下结果:

  • .toJSON的优点是它会被JSON.stringify自动使用。如果你将模式选项toJSON设置为重新塑造选项,则当您对具有该模式的文档进行字符串化时,将构建一个具有正确形状的对象。

  • .toObject的优点在于有时候JSON.stringify在打破文档和模式之间的链接后运行,这样就不会发生重新塑造。在这种情况下,您只需使用那些选项调用文档方法toObject,即可获得具有正确形状的对象。

示例

  • 假设有以下内容:
const reshapingOptions = {

    // include .id (it's a virtual)
    virtuals: true,

    // exclude .__v
    versionKey: false,

    // exclude ._id
    transform: function (doc, ret) {
        delete ret._id;
        return ret;
    },

};

const friendSchema = mongoose.Schema({ 
    givenName: String,
    familyName: String,
}, { toJSON: reshapingOptions });

const friendModel = mongoose.model('Friend', friendSchema);

const john = friendModel.findOne({ givenName: 'John' });
if (!john) {
    res.status(404).json({ error: 'No John Found' });
}
  • the statement

    JSON.stringify(john);
    

    returned:

{
    "id": "...",
    "givenName": "John",
    "familyName": "Doe"
}
  • but this equally innocent statement

    JSON.stringify({ 
        ...john, // the spread breaks the link
        role: 'dummy friend' 
    })
    

    suddenly returned:

{
    "_id": "...",
    "givenName": "John",
    "familyName": "Doe",
    "__v": 0,
    "role": "dummy friend"
}
  • So that I used

    res.json({ 
        ...john.toObject(reshapingOptions), 
        role: 'dummy friend' 
    })
    

    to get:

{
    "id": "...",
    "givenName": "John",
    "familyName": "Doe",
    "role": "dummy friend"
}

2

在开发一个插件的过程中,我发现在保存操作期间也会调用toObject方法。这可能会有害。例如,如果一个设置了toObject的插件(就像我的插件)改变了字段,那么该更改的结果将被持久化。


这可能是一个需要在 Github 上提出的问题:https://github.com/Automattic/mongoose/issues - steampowered
@steampowered Fred,我正在使用.toObject()方法,并在从docs.toObject()分配值的对象上更改值,但是当我调用docs.save时,新对象更改的值不会出现在MongoDB中。我希望这样做可以使一切都完美地运作,您能告诉我这对我的情况有何不利影响吗?我不明白你的意思。 - Sudhanshu Gaur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接