Mongoose: Dot notation in update doc breaks query

Created on 4 Jul 2018  路  3Comments  路  Source: Automattic/mongoose

Bug

Calling findOneAndUpdate with $setOnInsert and setDefaultsOnInsert: true, upsert: true on a nested subdocument with a default value for a field results in the error:
Updating the path 'nested.subdocument.default_field' would create a conflict at 'nested.subdocument'

MongoDB: 3.6.5
Mongoose v.5.2.1
Node v.8.11.3

Reproduction code

const mongoose = require('mongoose');
const BugSchema = new mongoose.Schema({
    nested: {
        test: String,
        default_field: {
            type: Number,
            default: 100,
        },
        subdocument: {
            test: String,
            default_field: {
                type: Number,
                default: 100,
            },
        },
    },
});
const BugModel = mongoose.model('BugSchema', BugSchema);
mongoose
    .connect('mongodb://localhost:27017')
    .then(() => {
        const failingUpdate = {
            'nested.subdocument': {
                test: 'Value',
            },
        };
        const passingUpdate = {
            'nested.subdocument': {
                test: 'Value',
                default_field: 100, // Note: Must set default_field value to prevent error.
            }
        };
        const passingUpdate2 = {
            'nested': {
                test: 'Value', // Note: No default_field value set.
            },
        };
        return bugModeQuery(failingUpdate)
            .then(() => bugModeQuery(passingUpdate))
            .then(() => bugModeQuery(passingUpdate2))
            .then(() => {
                mongoose.connection.close();
                process.exit();
            })
    })
    .catch(err => {
        console.error(err);
        mongoose.connection.close();
        process.exit();
    });

function bugModeQuery(update) {
    return BugModel.findOneAndUpdate(
        {},
        {$setOnInsert: update},
        {
            setDefaultsOnInsert: true,
            upsert: true,
        }
    )
        .then(res => {
            console.log('Success');
            console.log(res);
            return;
        })
       .catch(err => {
            console.error('ERROR');
            console.error(err);
            return Promise.resolve();
        })
}
confirmed-bug

Most helpful comment

@lineus yep that is supported. This is definitely a bug, will fix asap :+1:

All 3 comments

@redwood-egarcea the dot notation in the update doc seems to make mongodb unhappy, if you change your failingUpdate to:

    const failingUpdate = {
      nested: {
        subdocument: {
          test: 'Value',
        }
      },
    };

it works.

The mongoose debug logs show that using dot notation in the update doc causes mongoose to send a different update doc that mongodb bugs out on:

Here is the debug log from the update doc with dot notation:

Mongoose: bugschemas.findAndModify({}, [], { '$setOnInsert': { 'nested.subdocument': { test: 'Value' }, __v: 0, 'nested.default_field': 100, 'nested.subdocument.default_field': 100, _id: ObjectId("5b3d3b94df1e2a4cb1da3604") } }, { setDefaultsOnInsert: true, upsert: true, new: false, remove: false, fields: {} })

Here is the debug log from the same update doc without dot notation:

Mongoose: bugschemas.findAndModify({}, [], { '$setOnInsert': { nested: { subdocument: { test: 'Value' } }, __v: 0, _id: ObjectId("5b3d3bcdaf22214cf1f77637") } }, { setDefaultsOnInsert: true, upsert: true, new: false, remove: false, fields: {} })

@vkarpov15 using dot notation in the update doc of a query isn't something I've seen before. Is this supported?

I grok'd the tests regarding updates and I do see some usage of dot notation in the update doc but it seems to always be associated with arrays. Hopefully I get points for trying :)

@lineus yep that is supported. This is definitely a bug, will fix asap :+1:

Was this page helpful?
0 / 5 - 0 ratings