Do you want to request a feature or report a bug?
Bug. This used to work in v4.10.8. Recently upgraded to v4.11.4 and this is now broken
What is the current behavior?
I have a schema for Application
:
{
docs: {
type: Envelope,
default: {}
}
}
I have a schema for Envelope
:
const Envelope = new mongoose.Schema({
envelopeId: String,
status: String,
documents: {
type: [{
key: String,
bucket: String,
name: String,
_id: false,
}],
default: [],
},
_id: false,
});
Let's say my app.docs
has some data in envelopeId
, status
, etc. and my goal is to "reset" the entire property by doing to following:
app.docs = {}
app.save()
This should reset the MongoDB entry for that application's docs
to be:
{
documents: []
}
Previously in v4.10.8, this works as expected above. In v4.11.4, nothing happens and docs
is not reset.
Please mention your node.js, mongoose and MongoDB version.
Node 7.10. Mongoose 4.11.4, latest mongo
Here's the repro script. run this in v4.10.8 (works as expected) and then v4.11.5 (does not work)
const mongoose = require('mongoose');
mongoose.connect('mongodb://127.0.0.1/test');
const db = mongoose.connection;
db.once('open', async () => {
try {
const ChildSchema = new mongoose.Schema({
name: String,
_id: false,
});
const ParentSchema = new mongoose.Schema({
child: {
type: ChildSchema,
default: {},
},
});
const Parent = mongoose.model('Parent', ParentSchema);
const ogParent = new Parent({ child: { name: 'child' } });
await ogParent.save();
const foundParent = await Parent.findById(ogParent._id).exec();
console.log(foundParent.child); // { name: 'child' };
foundParent.child = {};
await foundParent.save();
const reFoundParent = await Parent.findById(ogParent._id).exec();
console.log(reFoundParent.child); // should be {}
db.close();
} catch (e) {
console.log(e);
}
});
Thanks for the detailed repro, fixed in master and will push a new release tomorrow :+1:
@vkarpov15 have you had a chance to merge this into master yet? i'm running into the same issue right now
@mistermoe which version? This fix was deployed several months ago with 4.11.6
@vkarpov15 4.13.4.
My schema looks like this:
const Role = new mongoose.Schema({
name: {
type: String,
required: 'A role name is required',
validate: {
isAsync: true,
validator: validators.validateName
}
},
organization: {
type: mongoose.Schema.ObjectId,
ref: 'Organization',
required: 'A role must belong to an organization'
},
permissions: {
type: Object,
required: true,
validate: {
isAsync: true, // this validator is not actually async but it's the only way that we can provide in depth error messages from a custom validator
validator: validators.validatePermissions
}
},
tags: {
type: [mongoose.Schema.Types.ObjectId],
ref: 'Tag'
}
}, {
timestamps: {
createdAt: 'dateCreated',
updatedAt: 'dateUpdated'
}
});
An example of permissions
looks like the following:
members: {
post: {
'email': true,
'firstName': true,
'lastName': true,
'office': true
},
get: {
'active': true,
'disabled': true,
'email': true,
'firstName': true,
'lastName': true,
'office': true,
'dateCreated': true,
'dateUpdated': true
},
put: {
'active': true,
'disabled': true,
'office': true
},
delete: {}
},
offices: {
post: {
'name': true,
'numSeats': true
},
get: {
'name': true,
'numSeats': true,
'dateCreated': true,
'dateUpdated': true,
'numMembers': true,
'numSeatsAvailable': true
},
put: {
'name': true,
'numSeats': true
},
delete: {}
},
roles: {
post: {
'name': true,
'permissions': true
},
get: {
'name': true,
'dateCreated': true,
'dateUpdated': true
},
put: {
'name': true,
'permissions': true
},
delete: {}
},
tags: {
post: {
'name': true,
'color': true
},
get: {
'name': true,
'color': true,
'dateCreated': true,
'dateUpdated': true,
'role': true
},
put: {
'name': true,
'color': true
},
delete: {}
},
self: {
put: {
'firstName': true,
'lastName': true,
'email': true,
'password': true
}
}
If i create a role with the permissions i've posted above and then fetch it the delete
property is missing. I skimmed over the changes you made and am wondering if they account for the existence of empty objects beyond just the top level but haven't had time to mess with it yet. I may have some time tomorrow to sit down and familiarize myself with the codebase enough to write a failing test using something similar to the example i've provided above and then make it pass
@vkarpov15 any word here? should i create a new issue?
@mistermoe yes please. Also, try setting the minimize option to false on your schema
@vkarpov15 setting minimize to false did the trick. Thanks! Sorry, i must've missed that in the documentation
Note that the minimize
option also affects schema's which explicitly define an empty object as a default value for a property, e.g.
foo: {
type: {},
default: {},
},
When the document is converted to JSON, it will not include the foo: {}
property as you would expect, unless the {minimize: false}
option is used. Not sure if this is a bug or expected behaviour.
I don't really want to _store_ empty objects in the database, but I would want the default values to be included when I send JSON to the client.
Most helpful comment
@mistermoe yes please. Also, try setting the minimize option to false on your schema