Skip to content

Commit 4fe9a90

Browse files
committed
Merge branch '6.x' into 7.x
2 parents ad7b0e0 + e59e342 commit 4fe9a90

File tree

3 files changed

+46
-24
lines changed

3 files changed

+46
-24
lines changed

CHANGELOG.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
6.13.6 / 2025-01-13
2+
===================
3+
* fix: disallow nested $where in populate match
4+
15
7.8.3 / 2024-11-26
26
==================
37
* fix: disallow using $where in match
@@ -646,7 +650,7 @@
646650
* fix(document): isModified should not be triggered when setting a nested boolean to the same value as previously #12994 [lpizzinidev](https://github.com/lpizzinidev)
647651
* fix(document): save newly set defaults underneath single nested subdocuments #13002 #12905
648652
* fix(update): handle custom discriminator model name when casting update #12947 [wassil](https://github.com/wassil)
649-
* fix(connection): handles unique autoincrement ID for connections #12990 [lpizzinidev](https://github.com/lpizzinidev)
653+
* fix(connection): handles unique autoincrement ID for connections #12990 [lpizzinidev](https://github.com/lpizzinidev)
650654
* fix(types): fix type of options of Model.aggregate #12933 [ghost91-](https://github.com/ghost91-)
651655
* fix(types): fix "near" aggregation operator input type #12954 [Jokero](https://github.com/Jokero)
652656
* fix(types): add missing Top operator to AccumulatorOperator type declaration #12952 [lpizzinidev](https://github.com/lpizzinidev)
@@ -675,7 +679,7 @@
675679
* docs(typescript): add notes about virtual context to Mongoose 6 migration and TypeScript virtuals docs #12912 #12806
676680
* docs(schematypes): removed dead link and fixed formatting #12897 #12885 [lpizzinidev](https://github.com/lpizzinidev)
677681
* docs: fix link to lean api #12910 [manniL](https://github.com/manniL)
678-
* docs: list all possible strings for schema.pre in one place #12868
682+
* docs: list all possible strings for schema.pre in one place #12868
679683
* docs: add list of known incompatible npm packages #12892 [IslandRhythms](https://github.com/IslandRhythms)
680684

681685
6.8.3 / 2023-01-06

lib/helpers/populate/getModelsMapForPopulate.js

+23-18
Original file line numberDiff line numberDiff line change
@@ -184,15 +184,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
184184
if (hasMatchFunction) {
185185
match = match.call(doc, doc);
186186
}
187-
if (Array.isArray(match)) {
188-
for (const item of match) {
189-
if (item != null && item.$where) {
190-
throw new MongooseError('Cannot use $where filter with populate() match');
191-
}
192-
}
193-
} else if (match != null && match.$where != null) {
194-
throw new MongooseError('Cannot use $where filter with populate() match');
195-
}
187+
throwOn$where(match);
196188
data.match = match;
197189
data.hasMatchFunction = hasMatchFunction;
198190
data.isRefPath = isRefPath;
@@ -470,15 +462,7 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
470462
data.match = match;
471463
data.hasMatchFunction = hasMatchFunction;
472464

473-
if (Array.isArray(match)) {
474-
for (const item of match) {
475-
if (item != null && item.$where) {
476-
throw new MongooseError('Cannot use $where filter with populate() match');
477-
}
478-
}
479-
} else if (match != null && match.$where != null) {
480-
throw new MongooseError('Cannot use $where filter with populate() match');
481-
}
465+
throwOn$where(match);
482466

483467
// Get local fields
484468
const ret = _getLocalFieldValues(doc, localField, model, options, virtual);
@@ -751,3 +735,24 @@ function _findRefPathForDiscriminators(doc, modelSchema, data, options, normaliz
751735

752736
return modelNames;
753737
}
738+
739+
/**
740+
* Throw an error if there are any $where keys
741+
*/
742+
743+
function throwOn$where(match) {
744+
if (match == null) {
745+
return;
746+
}
747+
if (typeof match !== 'object') {
748+
return;
749+
}
750+
for (const key of Object.keys(match)) {
751+
if (key === '$where') {
752+
throw new MongooseError('Cannot use $where filter with populate() match');
753+
}
754+
if (match[key] != null && typeof match[key] === 'object') {
755+
throwOn$where(match[key]);
756+
}
757+
}
758+
}

test/model.populate.test.js

+17-4
Original file line numberDiff line numberDiff line change
@@ -3582,21 +3582,34 @@ describe('model: populate:', function() {
35823582
const parent = await Parent.create({ name: 'Anakin', child: child._id });
35833583

35843584
await assert.rejects(
3585-
() => Parent.findOne().populate({ path: 'child', match: { $where: 'console.log("oops!");' } }),
3585+
() => Parent.findOne().populate({ path: 'child', match: () => ({ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }) }),
35863586
/Cannot use \$where filter with populate\(\) match/
35873587
);
35883588
await assert.rejects(
3589-
() => Parent.find().populate({ path: 'child', match: { $where: 'console.log("oops!");' } }),
3589+
() => Parent.find().populate({ path: 'child', match: () => ({ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }) }),
35903590
/Cannot use \$where filter with populate\(\) match/
35913591
);
35923592
await assert.rejects(
3593-
() => parent.populate({ path: 'child', match: { $where: 'console.log("oops!");' } }),
3593+
() => parent.populate({ path: 'child', match: () => ({ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }) }),
35943594
/Cannot use \$where filter with populate\(\) match/
35953595
);
35963596
await assert.rejects(
3597-
() => Child.find().populate({ path: 'parent', match: { $where: 'console.log("oops!");' } }),
3597+
() => Child.find().populate({ path: 'parent', match: () => ({ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }) }),
35983598
/Cannot use \$where filter with populate\(\) match/
35993599
);
3600+
await assert.rejects(
3601+
() => Child.find().populate({ path: 'parent', match: () => ({ $or: [{ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }] }) }),
3602+
/Cannot use \$where filter with populate\(\) match/
3603+
);
3604+
await assert.rejects(
3605+
() => Child.find().populate({ path: 'parent', match: () => ({ $and: [{ $where: 'typeof console !== "undefined" ? doesNotExist("foo") : true;' }] }) }),
3606+
/Cannot use \$where filter with populate\(\) match/
3607+
);
3608+
3609+
class MyClass {}
3610+
MyClass.prototype.$where = 'typeof console !== "undefined" ? doesNotExist("foo") : true;';
3611+
// OK because sift only looks through own properties
3612+
await Child.find().populate({ path: 'parent', match: () => new MyClass() });
36003613
});
36013614

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

0 commit comments

Comments
 (0)