For my use case, this is what I got:
.toJSON
's advantage is that it's used automatically by JSON.stringify
. If you set the schema option toJSON
to your re-shaping options, then an object with the proper shape will be built when you stringify a document with that schema
.toObject
's advantage is that some times JSON.stringify
runs after breaking the link between the document and the schema, so that no re-shaping can happen. In such a case, you just call the document method toObject
with those options to get an object with the proper shape.
Example
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"
}
{
"id": "...",
"givenName": "John",
"familyName": "Doe",
"role": "dummy friend"
}