17

I'm puzzled as of why Mongoose isn't saving my object:

var objectToSave = new ModelToSave({
  _id : req.params.id, 
  Item : customObject.Item //doesn't save with customObject.getItem() neither
});

But is saving this; as is below or with hardcoded values:

var objectToSave = new ModelToSave({
  _id : req.params.id, 
  Item : {
    SubItem : {
      property1 : customObject.Item.SubItem.property1, //also saves with customObject.getItem().SubItem.getProperty1()
      property2 : customObject.Item.SubItem.property2
    }
  }
});

The getters/setters are

MyClass.prototype.getItem = function(){ ... };

My Item object is quite big, and I'd rather not have to specify every single sub properties...

When I view my Item object with console.log(customObject.Item) or when I return it through my API as JSON, it has all the nested properties (SubItem, ...) that I'm expecting.

Item is defined as:

SubItem = require('SubItemClass.js');

function MyClass(){
  this.Item = {
    SubItem : new SubItem()
  }
}

And SubItem is defined as

function SubItem(){
  this.property1 = '';
  this.property2 = 0;
}

The model seems to work as expected, because If I hardcode data or if I specify every single properties to save to the model, I can save the data to the Model...

here's the code anyway:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var subItemDefinition = {
  Property1 : {type:String},
  Property2 : {type:Number},    
};

var itemDefinition = {
  SubItem : subItemDefinition
};

var customDefinition = {
  Item : itemDefinition
};

var customSchema = new Schema(customDefinition); 
module.exports = mongoose.model('ModelToSave', customSchema);

Thanks for your help

user1144446
  • 561
  • 1
  • 4
  • 17
  • How have you defined the schema of the `ModelToSave`. It looks like a mismatch in types from here. Can you edit your question to include this please. – Neil Lunn Jun 05 '14 at 07:54
  • it looks like if customObject.Item couldn't be accessed, hence the reason why I have to break it down into all sub properties... When I save data from a POST, I use the same code structure as above, i.e. only define the model object to be saved with its higher level properties only, like "Item : req.body.Item" – user1144446 Jun 05 '14 at 08:32

2 Answers2

48

I came across this frustrating situation and was a little surprised by the documented solution from Mongoose's website.

so what this means is to save nested array/object properties (Item in your case), you need to be explicit in specifying the change .markModified('Item')

var objectToSave = new ModelToSave({
  _id : req.params.id, 
  Item : customObject
});
objectToSave.markModified('Item');
objectToSave.save();

Since it is a schema-less type, you can change the value to anything else you like, but Mongoose loses the ability to auto detect and save those changes. To "tell" Mongoose that the value of a Mixed type has changed, call the .markModified(path) method of the document passing the path to the Mixed type you just changed.

-- http://mongoosejs.com/docs/schematypes.html#mixed

James Broad
  • 1,210
  • 12
  • 17
0

I found the same issue, indeed very frustrating.

But I don't like to jump through hoops using objectToSave.markModified() ...

In my case, I solved this issue by simpely making sure that I never write an empty sub-object !

Like this:

// add dummy 'keep' entry:
if (Object.keys(customObject.Item).length === 0) {
  customObject.Item.keep = true;
}

// save to MongoDB using Mongoose:
var objectToSave = new ModelToSave({
  _id : req.params.id, 
  Item : customObject.Item
});

// later I filter-out this "keep" entry:
Object.entries(customObject.Item).forEach(([key, sub_object]) => {
  if (key === "keep") return;
  // now do something with the acutal keys...
});