0

I have a Mongoose model that looks like this:

var ProjectSchema = new Schema({
    name: String,
    slug: String,
    dateCreated: { type: Date, default: new Date() },
    dateUpdated: { type: Date, default: new Date() },
    createdByUserId: Schema.Types.ObjectId,
    screens: [Schema.Types.Mixed]
});

I have a class method that looks like this:

ProjectSchema.statics.saveElementProperties = function(slugName, screenIndex, elementId, props, callback) {
    var Project = mongoose.model('Project');

    var updateProject = function(project) {
        // Init empty objects if missing
        project.screens[screenIndex] = project.screens[screenIndex] || {};
        project.screens[screenIndex].elements = project.screens[screenIndex].elements || {};
        project.screens[screenIndex].elements[elementId] = project.screens[screenIndex].elements[elementId] || {};
        // Apply properties
        project.screens[screenIndex].elements[elementId] = "Dummy Project Data";
        console.log('elements before save:', project.screens[screenIndex].elements);
        project.save(callback);
    };

    Project.findOne({ slug: slugName }, function(err, project) {
        if (!project) {
            project = new Project({ name: slugName, slug: slugName });
        }
        updateProject(project);
    });
};

This happens when I call the method saveElementProperties:

  1. The first time I run this method, it works like it should; a new object is added to project.screens[screenIndex].elements both in runtime (the 'elements before save:' log statement) and when checking the MongoDB database with the mongo client.
  2. The second time, a 2nd object is added to project.screens[screenIndex].elements in runtime, but this object is never persisted to MongoDB.
  3. The third time, object 1 and 3 are visible in project.screens[screenIndex].elements in runtime, but the 3rd object is never persisted to MongoDB.

What causes this behavior?

MAJOR UPDATE: I rewrote the entire persistence mechanism to run less frequently, and instead replace the entire project.screens[screenIndex].elements object with an updated structure:

ProjectSchema.statics.saveScreenProperties = function(slugName, screenIndex, elements, callback) {
    console.log('saveScreenProperties:', slugName, screenIndex);
    var Project = mongoose.model('Project');

    var updateProject = function(project) {
        // Init empty objects if missing
        project.screens[screenIndex] = project.screens[screenIndex] || {};
        project.screens[screenIndex].elements = elements;
        // Mark as modified and save
        project.markModified('screens.' + screenIndex);
        project.save(callback);
    };

    Project.findOne({ slug: slugName }, function(err, project) {
        if (!project) {
            project = new Project({ name: slugName, slug: slugName });
            console.log('  creating new project');
        }
        updateProject(project);
    });
};

However, it still shows the same behavior - it stores the initial elements object, but not later changes to it.

Tom Söderlund
  • 4,743
  • 4
  • 45
  • 67

1 Answers1

0

The problem is that you are manipulating the objects just as you would in standard code but mongoose is not a 'persistence engine` it's an ODM. As such you need to use the provided methods to update the datastore.

You will need to use the update operators to $push onto the array. Mongoose has some analogous methods as well. The most explainatory docs are on the MongoDB site.

http://docs.mongodb.org/manual/reference/operator/update-array/

http://docs.mongodb.org/manual/reference/operator/update/

http://docs.mongodb.org/manual/reference/method/db.collection.update/#db.collection.update

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
  • Thanks! I rewrote the save mechanism (see updated question above) and now need to store the modified `elements` object, but it doesn't persist. Any clues? – Tom Söderlund Feb 01 '14 at 22:50
  • You need to **push** as I said in the answer. Mongoose has a method as well. Also look at [populate](http://mongoosejs.com/docs/api.html#model_Model.populate) in the docs. – Neil Lunn Feb 01 '14 at 22:53
  • Not mongoose, but there are these two references from just recently. [21502654](http://stackoverflow.com/questions/21502654/update-subdocument-in-mongodb-that-stores-ids) [21502620](http://stackoverflow.com/questions/21502620/unable-to-update-inner-arraylist-object-using-mongodb-java-driver) – Neil Lunn Feb 01 '14 at 22:57