Skip to content

Commit

Permalink
Merge pull request #13786 from Automattic/vkarpov15/handle-top-level-…
Browse files Browse the repository at this point in the history
…dollar-keys

feat: allow top level dollar keys with findOneAndUpdate(), update()
  • Loading branch information
vkarpov15 authored Aug 29, 2023
2 parents c1d5b76 + 0d956ce commit 29de9c4
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
24 changes: 21 additions & 3 deletions lib/helpers/query/castUpdate.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ const schemaMixedSymbol = require('../../schema/symbols').schemaMixedSymbol;
const setDottedPath = require('../path/setDottedPath');
const utils = require('../../utils');

const mongodbUpdateOperators = new Set([
'$currentDate',
'$inc',
'$min',
'$max',
'$mul',
'$rename',
'$set',
'$setOnInsert',
'$unset',
'$addToSet',
'$pop',
'$pull',
'$push',
'$pullAll',
'$bit'
]);

/**
* Casts an update op based on the given schema
*
Expand Down Expand Up @@ -58,7 +76,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
while (i--) {
const op = ops[i];
// if overwrite is set, don't do any of the special $set stuff
if (op[0] !== '$' && !overwrite) {
if (!mongodbUpdateOperators.has(op) && !overwrite) {
// fix up $set sugar
if (!ret.$set) {
if (obj.$set) {
Expand Down Expand Up @@ -88,7 +106,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
if (val &&
typeof val === 'object' &&
!Buffer.isBuffer(val) &&
(!overwrite || hasDollarKey)) {
(!overwrite || mongodbUpdateOperators.has(op))) {
walkUpdatePath(schema, val, op, options, context, filter);
} else if (overwrite && ret && typeof ret === 'object') {
walkUpdatePath(schema, ret, '$set', options, context, filter);
Expand Down Expand Up @@ -540,7 +558,7 @@ function castUpdateVal(schema, val, op, $conditional, context, path) {
return Boolean(val);
}

if (/^\$/.test($conditional)) {
if (mongodbUpdateOperators.has($conditional)) {
return schema.castForQuery(
$conditional,
val,
Expand Down
17 changes: 17 additions & 0 deletions test/model.updateOne.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3051,6 +3051,23 @@ describe('model: updateOne: ', function() {
await Person.updateOne({ name: 'Anakin' }, { name: 'The Chosen One' }).orFail();
}, { message: 'No document found for query "{ name: \'Anakin\' }" on model "gh-11620"' });
});
it('updateOne with top level key that starts with $ (gh-13786)', async function() {
const [major] = await start.mongodVersion();
if (major < 5) {
return this.skip();
}

const schema = new mongoose.Schema({
$myKey: String
});

const Test = db.model('Test', schema);

const _id = new mongoose.Types.ObjectId();
await Test.updateOne({ _id }, { $myKey: 'gh13786' }, { upsert: true });
const doc = await Test.findById(_id);
assert.equal(doc.$myKey, 'gh13786');
});
});

async function delay(ms) {
Expand Down

0 comments on commit 29de9c4

Please sign in to comment.