Skip to content

Commit

Permalink
fix(query): shallow clone $or and $and array elements to avoid mutati…
Browse files Browse the repository at this point in the history
…ng query filter arguments

Fix #14610
  • Loading branch information
vkarpov15 committed May 24, 2024
1 parent 32f1ee1 commit 218d50a
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 4 deletions.
12 changes: 8 additions & 4 deletions lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -2416,13 +2416,17 @@ Query.prototype.merge = function(source) {
}

opts.omit = {};
if (this._conditions && this._conditions.$and && source.$and) {
if (this._conditions && Array.isArray(source.$and)) {
opts.omit['$and'] = true;
this._conditions.$and = this._conditions.$and.concat(source.$and);
this._conditions.$and = (this._conditions.$and || []).concat(
source.$and.map(el => utils.isPOJO(el) ? utils.merge({}, el) : el)
);
}
if (this._conditions && this._conditions.$or && source.$or) {
if (this._conditions && Array.isArray(source.$or)) {
opts.omit['$or'] = true;
this._conditions.$or = this._conditions.$or.concat(source.$or);
this._conditions.$or = (this._conditions.$or || []).concat(
source.$or.map(el => utils.isPOJO(el) ? utils.merge({}, el) : el)
);
}

// plain object
Expand Down
2 changes: 2 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ exports.merge = function merge(to, from, options, path) {
to[key] = from[key];
}
}

return to;
};

/**
Expand Down
15 changes: 15 additions & 0 deletions test/query.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4214,4 +4214,19 @@ describe('Query', function() {
assert.strictEqual(doc.account.owner, undefined);
assert.strictEqual(doc.account.taxIds, undefined);
});

it('avoids mutating $or, $and elements when casting (gh-14610)', async function() {
const personSchema = new mongoose.Schema({
name: String,
age: Number
});
const Person = db.model('Person', personSchema);

const filter = [{ name: 'Me', age: '20' }, { name: 'You', age: '50' }];
await Person.find({ $or: filter });
assert.deepStrictEqual(filter, [{ name: 'Me', age: '20' }, { name: 'You', age: '50' }]);

await Person.find({ $and: filter });
assert.deepStrictEqual(filter, [{ name: 'Me', age: '20' }, { name: 'You', age: '50' }]);
});
});

0 comments on commit 218d50a

Please sign in to comment.