Skip to content

Commit a42d8f5

Browse files
committed
Merge branch '7.x'
2 parents fa33717 + 73e81ab commit a42d8f5

File tree

3 files changed

+48
-22
lines changed

3 files changed

+48
-22
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
7.8.4 / 2025-01-13
2+
===================
3+
* fix: disallow nested $where in populate match
4+
5+
6.13.6 / 2025-01-13
6+
===================
7+
* fix: disallow nested $where in populate match
8+
19
8.9.4 / 2025-01-09
210
==================
311
* fix(document): fix document not applying manual populate when using a function in schema.options.ref #15138 [IchirokuXVI](https://github.com/IchirokuXVI)

lib/helpers/populate/getModelsMapForPopulate.js

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
191191
if (hasMatchFunction) {
192192
match = match.call(doc, doc);
193193
}
194-
if (Array.isArray(match)) {
195-
for (const item of match) {
196-
if (item != null && item.$where) {
197-
throw new MongooseError('Cannot use $where filter with populate() match');
198-
}
199-
}
200-
} else if (match != null && match.$where != null) {
201-
throw new MongooseError('Cannot use $where filter with populate() match');
202-
}
194+
throwOn$where(match);
203195
data.match = match;
204196
data.hasMatchFunction = hasMatchFunction;
205197
data.isRefPath = isRefPath;
@@ -463,15 +455,7 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
463455
data.match = match;
464456
data.hasMatchFunction = hasMatchFunction;
465457

466-
if (Array.isArray(match)) {
467-
for (const item of match) {
468-
if (item != null && item.$where) {
469-
throw new MongooseError('Cannot use $where filter with populate() match');
470-
}
471-
}
472-
} else if (match != null && match.$where != null) {
473-
throw new MongooseError('Cannot use $where filter with populate() match');
474-
}
458+
throwOn$where(match);
475459

476460
// Get local fields
477461
const ret = _getLocalFieldValues(doc, localField, model, options, virtual);
@@ -759,3 +743,24 @@ function _findRefPathForDiscriminators(doc, modelSchema, data, options, normaliz
759743

760744
return modelNames;
761745
}
746+
747+
/**
748+
* Throw an error if there are any $where keys
749+
*/
750+
751+
function throwOn$where(match) {
752+
if (match == null) {
753+
return;
754+
}
755+
if (typeof match !== 'object') {
756+
return;
757+
}
758+
for (const key of Object.keys(match)) {
759+
if (key === '$where') {
760+
throw new MongooseError('Cannot use $where filter with populate() match');
761+
}
762+
if (match[key] != null && typeof match[key] === 'object') {
763+
throwOn$where(match[key]);
764+
}
765+
}
766+
}

test/model.populate.test.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3670,21 +3670,34 @@ describe('model: populate:', function() {
36703670
const parent = await Parent.create({ name: 'Anakin', child: child._id });
36713671

36723672
await assert.rejects(
3673-
() => Parent.findOne().populate({ path: 'child', match: { $where: 'console.log("oops!");' } }),
3673+
() => Parent.findOne().populate({ path: 'child', match: () => ({ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }) }),
36743674
/Cannot use \$where filter with populate\(\) match/
36753675
);
36763676
await assert.rejects(
3677-
() => Parent.find().populate({ path: 'child', match: { $where: 'console.log("oops!");' } }),
3677+
() => Parent.find().populate({ path: 'child', match: () => ({ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }) }),
36783678
/Cannot use \$where filter with populate\(\) match/
36793679
);
36803680
await assert.rejects(
3681-
() => parent.populate({ path: 'child', match: { $where: 'console.log("oops!");' } }),
3681+
() => parent.populate({ path: 'child', match: () => ({ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }) }),
36823682
/Cannot use \$where filter with populate\(\) match/
36833683
);
36843684
await assert.rejects(
3685-
() => Child.find().populate({ path: 'parent', match: { $where: 'console.log("oops!");' } }),
3685+
() => Child.find().populate({ path: 'parent', match: () => ({ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }) }),
36863686
/Cannot use \$where filter with populate\(\) match/
36873687
);
3688+
await assert.rejects(
3689+
() => Child.find().populate({ path: 'parent', match: () => ({ $or: [{ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }] }) }),
3690+
/Cannot use \$where filter with populate\(\) match/
3691+
);
3692+
await assert.rejects(
3693+
() => Child.find().populate({ path: 'parent', match: () => ({ $and: [{ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }] }) }),
3694+
/Cannot use \$where filter with populate\(\) match/
3695+
);
3696+
3697+
class MyClass {}
3698+
MyClass.prototype.$where = 'typeof console !== "undefined" ? doesNotExist("foo") : true;';
3699+
// OK because sift only looks through own properties
3700+
await Child.find().populate({ path: 'parent', match: () => new MyClass() });
36883701
});
36893702

36903703
it('multiple source docs', async function() {

0 commit comments

Comments
 (0)