qqilihq qqilihq - 4 months ago 8x
Node.js Question

mongoose: Removing subdocument's content

I have a Mongoose (using current version) schema with a subdocument:

var mySchema = new Schema({
subdocument: { property1: { type: String } }
var myModel = mongoose.model('My-Model', mySchema);

Now I'm trying to update an existing document and to remove the
like so using
doc.subdocument = {}

new myModel({ name: 'test', subdocument: { property1: 'test' }}).save(function(err, doc) {
console.log('saved doc:\n', doc);
doc.subdocument = {}; // remove content of subdocument
doc.save(function(err, doc) {
console.log('updated doc:\n', doc); // subdocument: null
myModel.findById(doc._id, function(err, doc) {
console.log('retrieved doc:\n', doc); // subdocument: { property1: 'test' }

The callback in
returns the document with
subdocument: null
, so I assumed, the update worked as expected. However, when examining the database, the
's content is still there -- this can be seen by above's sample code when I retrieve the document again.

The document in the DB looks as:

{ subdocument: { property1: 'test' }, __v: 0, _id: 57593a8130f2f7b6a12886b1 }

Is this a bug or a fundamental misunderstanding?


I believe that regular JS object properties in schema are given a Mixed schema type by Mongoose.

For these types of properties, if they change, you need to explicitly tell Mongoose about that change before saving:

doc.subdocument = {};

The "updated doc" will not reflect the document as it's stored in the database, only how it's represented in memory (it's simply another reference to the doc object).

As an alternative to .save(), you can also use findByIdAndUpdate(), with the added advantage that you can make it return the updated (stored-in-the-database) document using the new option:

myModel.findByIdAndUpdate(doc._id, {
  $set : { subdocument : {} }
}, { new : true }, function(err, doc) {
  // `doc` will now reflect what's stored in the database