Skip to content

Commit

Permalink
fix(populate): allow deselecting discriminator key when populating
Browse files Browse the repository at this point in the history
Fix #3230
Re: #13760
Re: #13679
  • Loading branch information
vkarpov15 committed Dec 5, 2023
1 parent 2d65e00 commit 1f1f897
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 18 deletions.
5 changes: 2 additions & 3 deletions lib/helpers/projection/isExclusive.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ module.exports = function isExclusive(projection) {
}

const keys = Object.keys(projection);
let ki = keys.length;
let exclude = null;

if (ki === 1 && keys[0] === '_id') {
if (keys.length === 1 && keys[0] === '_id') {
exclude = !projection._id;
} else {
while (ki--) {
for (let ki = 0; ki < keys.length; ++ki) {
// Does this projection explicitly define inclusion/exclusion?
// Explicitly avoid `$meta` and `$slice`
const key = keys[ki];
Expand Down
2 changes: 1 addition & 1 deletion lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -4408,7 +4408,7 @@ function populate(model, docs, options, callback) {
select = select.replace(excludeIdRegGlobal, ' ');
} else {
// preserve original select conditions by copying
select = utils.object.shallowCopy(select);
select = { ...select };
delete select._id;
}
}
Expand Down
9 changes: 3 additions & 6 deletions lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -4932,16 +4932,14 @@ Query.prototype._castFields = function _castFields(fields) {
elemMatchKeys,
keys,
key,
out,
i;
out;

if (fields) {
keys = Object.keys(fields);
elemMatchKeys = [];
i = keys.length;

// collect $elemMatch args
while (i--) {
for (let i = 0; i < keys.length; ++i) {
key = keys[i];
if (fields[key].$elemMatch) {
selected || (selected = {});
Expand All @@ -4960,8 +4958,7 @@ Query.prototype._castFields = function _castFields(fields) {
}

// apply the casted field args
i = elemMatchKeys.length;
while (i--) {
for (let i = 0; i < elemMatchKeys.length; ++i) {
key = elemMatchKeys[i];
fields[key] = out[key];
}
Expand Down
5 changes: 3 additions & 2 deletions lib/queryhelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,12 @@ exports.applyPaths = function applyPaths(fields, schema) {
if (!isDefiningProjection(field)) {
continue;
}
// `_id: 1, name: 0` is a mixed inclusive/exclusive projection in
// MongoDB 4.0 and earlier, but not in later versions.
if (keys[keyIndex] === '_id' && keys.length > 1) {
continue;
}
if (keys[keyIndex] === schema.options.discriminatorKey && keys.length > 1 && field != null && !field) {
continue;
}
exclude = !field;
break;
}
Expand Down
6 changes: 0 additions & 6 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -687,12 +687,6 @@ exports.object.vals = function vals(o) {
return ret;
};

/**
* @see exports.options
*/

exports.object.shallowCopy = exports.options;

const hop = Object.prototype.hasOwnProperty;

/**
Expand Down
25 changes: 25 additions & 0 deletions test/model.populate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10834,4 +10834,29 @@ describe('model: populate:', function() {
[id1.toString(), id2.toString(), id3.toString(), id4.toString()]
);
});

it('allows deselecting discriminator key when populating (gh-3230) (gh-13760) (gh-13679)', async function() {
const Test = db.model(
'Test',
Schema({ name: String, arr: [{ testRef: { type: 'ObjectId', ref: 'Test2' } }] })
);

const schema = Schema({ name: String });
const Test2 = db.model('Test2', schema);
const D = Test2.discriminator('D', Schema({ prop: String }));


await Test.deleteMany({});
await Test2.deleteMany({});
const { _id } = await D.create({ name: 'foo', prop: 'bar' });
const test = await Test.create({ name: 'test', arr: [{ testRef: _id }] });

const doc = await Test
.findById(test._id)
.populate('arr.testRef', { name: 1, prop: 1, _id: 0, __t: 0 });
assert.deepStrictEqual(
doc.toObject().arr[0].testRef,
{ name: 'foo', prop: 'bar' }
);
});
});

0 comments on commit 1f1f897

Please sign in to comment.