mongoose: Model.save() doesn't save embedded arrays

I have nested arrays of documents, and when I change them and do a .save() on the model it does not save the changes in the nested document.

Here are my models and schemas (some ommited for brevity):

var Votes = new mongoose.Schema({
    date: Date, 
    user_name: String,
    is_up: Boolean
});

var EventSchema = new mongoose.Schema({
  to_date: Date,
  from_date: Date,
  location: String,
  name: String,
  suggested_by: String,
  description: String,
  users: [EventUser],
  comments: [Comments],
  suggestions: [Event],
  votes: [Votes]
});

var Event = mongoose.model('Event', EventSchema);

Model before event.save() called:

{ 
     __v: 1,
    _id: 509e87e583ccbfa00e000004,
    description: 'Pfft',
    from_date: Sun Nov 11 2012 08:00:00 GMT-0500 (EST),
    location: 'Home',
    name: 'Whatever',
    suggested_by: 'No one',
    to_date: Sun Nov 11 2012 00:00:00 GMT-0500 (EST),
    votes: [],
    suggestions: 
     [ { users: [],
         comments: [],
         suggestions: [],
         votes: [],
         _id: 509e880883ccbfa00e000005,
         suggested_by: 'Some one',
         to_date: Sun Nov 11 2012 04:00:00 GMT-0500 (EST),
         from_date: Mon Nov 12 2012 00:00:00 GMT-0500 (EST),
         location: 'Home',
         name: 'Football',
         description: 'FOOTBALL!!' } ],
    comments: [],
    users: [] 
}

The same object with the nested votes right before event.save() is called.

{
   "__v":1,
   "_id":"509e87e583ccbfa00e000004",
   "description":"Pfft",
   "from_date":"2012-11-11T13:00:00.000Z",
   "location":"Home",
   "name":"Whatever",
   "suggested_by":"No one",
   "to_date":"2012-11-11T05:00:00.000Z",
   "votes":[ ],
   "suggestions":
      [ {
         "users":[],
         "comments":[ ],
         "suggestions":[ ],
         "votes":
            [{
               "is_up":true,
               "date":"2012-11-10T18:05:25.796Z",
               "user_name":"No one"
            }],
         "_id":"509e880883ccbfa00e000005",
         "suggested_by":"Some one",
         "to_date":"2012-11-11T09:00:00.000Z",
         "from_date":"2012-11-12T05:00:00.000Z",
         "location":"Home",
         "name":"Football",
         "description":"FOOTBALL!!"
      }],
   "comments":[],
   "users":[]
}

When event.save() is called, no error is thrown, but the nested votes schema inside of the nested events schema is not actually saved. If I use the same overall logic in the top level event object to save a vote, it does work.

When I looked through the code, briefly, it appears that .save() is suppose to be a shortcut for both saving new objects, as well as updating ones that already exist.

My hunch is Model.prototype._delta isn’t going deep enough to catch all nested objects, https://github.com/LearnBoost/mongoose/blob/master/lib/model.js#L529

About this issue

  • Original URL
  • State: closed
  • Created 12 years ago
  • Comments: 26

Most upvoted comments

I see what the issue is - classic case of the first question on the mongoose FAQ.

Thanks, it was this issue in my case ! 😃

model.myArray[index] = anyValue

becomes

model.myArray.set(index, anyValue)

I see what the issue is - classic case of the first question on the mongoose FAQ. Mongoose can’t track changes when you set an array index directly without something like ES6 proxies or ES7 Object.observe(). Use

chart.sizes[0].lengths.set(0, "20");

or

chart.sizes[0].lengths[0] = '20';
chart.markModified('sizes.0.lengths.0');

This also was issue for me, I wish I saw this thread sooner!

If you’re ever unsure of mongoose getting notified of changes, you can use

doc.markModified('propChanged') doc.save() // works

Try fixing your EventSchema ref used in suggestions:

// bad
var EventSchema = new mongoose.Schema({
  suggestions: [EventSchema] <== at this time, EventSchema is undefined which is interpreted as Mixed

// instead...

var EventSchema = new mongoose.Schema;
EventSchema.add({
  suggestions: [EventSchema] <== EventSchema exists
})


I’m using 5.5.11 and still having this issue. I’ve tried all the solutions proposed on this thread with no luck. My document layout looks like this:

{
  myObj: {
    myArr: [{ key: "value" }]
  }
}

myDoc.myObj.myArr.push({ key: "value2" });
// debugging myDoc shows new embedded doc
await myDoc.save();
// console shows new embedded doc is gone

Edit: Upgraded to latest (5.7.6) and still having the issue.

@thehme what version of mongoose are you using?

on this line, {$set: {["dT." + index +".ts." + i + ".th"]: newValue}}, the square brackets feel out of place to me. does it make any difference to use {$set: { "dT." + index +".ts." + i + ".th": newValue } } instead?

$set docs show just a string

feel free to join us on Gitter.im or Slack to talk about it in real time 👍

@vkarpov15 Haha Ok, thanks for the answer! 👍 Got a lot of things to learn 😃

@crispen-smith here’s my basic attempt to reproduce the issue as a standalone script:

var mongoose = require('mongoose');
mongoose.set('debug', true);
var util = require('util');
var assert = require('assert');

mongoose.connect('mongodb://localhost:27017/gh1204');

var Schema = mongoose.Schema;

var measurement = new Schema({
    name: {type: String, required: true},
    instruction: {type: String, required: true}
});

var size = new Schema({
    name: {type: String, required: true},
    lengths: [String]
});

var chartSchema = new Schema({
    measurements: [measurement],
    sizes: [size]
});

var Chart = mongoose.model('gh1204', chartSchema);

Chart.create({}, function(error, chart) {
  assert.ifError(error);
  chart.sizes.push({ name: 'bacon', lengths: ['25'] });
  chart.save(function(error, chart) {
    assert.ifError(error);
    assert.equal(chart.sizes[0].lengths.length, 1);
    assert.equal(chart.sizes[0].lengths[0], '25');
    console.log('done');
    process.exit(0);
  });
});

No dice so far, it runs as expected. Can you modify the above example to demonstrate the issue that you’re seeing? I haven’t been able to translate your prose descriptions into code.