New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
toObject/toJSON option are taken from parent for populated models #2035
Comments
Getting this too. Here's a full code to reproduce: var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var Schema = mongoose.Schema;
var userSchema = new Schema({
firstName: String,
lastName: String,
password: String
});
userSchema.virtual('fullName').get(function () {
return this.firstName + ' ' + this.lastName;
});
userSchema.set('toObject', { virtuals: false });
var postSchema = new Schema({
owner: {type: Schema.Types.ObjectId, ref: 'User'},
content: String
});
postSchema.virtual('capContent').get(function () {
return this.content.toUpperCase();
});
postSchema.set('toObject', { virtuals: true });
var User = mongoose.model('User', userSchema);
var Post = mongoose.model('Post', postSchema);
var user = new User({ firstName: 'Joe', lastName: 'Smith', password: 'password' });
user.save(function (err, savedUser) {
var post = new Post({ owner: savedUser._id, content: "lorem ipsum"});
post.save(function (err, savedPost) {
Post.findById(savedPost._id).populate('owner').exec(function (err, newPost) {
var obj = newPost.toObject();
console.dir(obj);
});
});
}); Output:
I believe this happens because of code in Document.prototype.toObject(). We create the options object from the current docs schema. Then the clone function is called with the very same options. This iteratively calls toObject() on the (user) sub document instance with the (post) parent document's toOjbect options. Then in the user's instance toObject function the options are actually Also happens if we reverse the options. Then none of the virtuals are returned. Not really sure what the best solution would be. Probably to somehow maybe keep wether we are setting options inline vs. schema (if inline takes presedence or something), and to save the old option before doing recursion and then reset it. Might play around with this some more. |
Was able to fix this by modifying Document.prototype.toObject = function (options) {
if (options && options.depopulate && this.$__.wasPopulated) {
// populated paths that we set to a document
return clone(this._id, options);
}
// When internally saving this document we always pass options,
// bypassing the custom schema options.
if (!(options && 'Object' == options.constructor.name)) {
options = this.schema.options.toObject
? clone(this.schema.options.toObject)
: {};
options.$_inline = false;
}
else if (options && options.$_inline === undefined) {
options.$_inline = clone(options); // original inline options
}
;('minimize' in options) || (options.minimize = this.schema.options.minimize);
var ret = clone(this._doc, options);
var doVirtuals = options.virtuals;
if (options.$_inline) {
doVirtuals = options.$_inline.virtuals;
}
else if(options.$_inline == false) {
doVirtuals = (this.schema.options.toObject && this.schema.options.toObject.virtuals === true);
}
if (doVirtuals) {
applyGetters(this, ret, 'virtuals', options);
}
... Not sure if this is the best approach, but seems to work for me. I think getters are effected by similar behaviour. |
The text was updated successfully, but these errors were encountered: