Skip to content

Commit

Permalink
Merge pull request #14173 from Automattic/vkarpov15/handle-nested-pro…
Browse files Browse the repository at this point in the history
…jections

fix(document): avoid treating nested projection as inclusive when applying defaults
  • Loading branch information
vkarpov15 authored Dec 14, 2023
2 parents 2a78e25 + 95d917b commit d36d134
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 1 deletion.
4 changes: 3 additions & 1 deletion lib/helpers/document/applyDefaults.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

const isNestedProjection = require('../projection/isNestedProjection');

module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
const paths = Object.keys(doc.$__schema.paths);
const plen = paths.length;
Expand Down Expand Up @@ -32,7 +34,7 @@ module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildre
}
} else if (exclude === false && fields && !included) {
const hasSubpaths = type.$isSingleNested || type.$isMongooseDocumentArray;
if (curPath in fields || (j === len - 1 && hasSubpaths && hasIncludedChildren != null && hasIncludedChildren[curPath])) {
if ((curPath in fields && !isNestedProjection(fields[curPath])) || (j === len - 1 && hasSubpaths && hasIncludedChildren != null && hasIncludedChildren[curPath])) {
included = true;
} else if (hasIncludedChildren != null && !hasIncludedChildren[curPath]) {
break;
Expand Down
1 change: 1 addition & 0 deletions lib/helpers/projection/hasIncludedChildren.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = function hasIncludedChildren(fields) {
const keys = Object.keys(fields);

for (const key of keys) {

if (key.indexOf('.') === -1) {
hasIncludedChildren[key] = 1;
continue;
Expand Down
8 changes: 8 additions & 0 deletions lib/helpers/projection/isNestedProjection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';

module.exports = function isNestedProjection(val) {
if (val == null || typeof val !== 'object') {
return false;
}
return val.$slice == null && val.$elemMatch == null && val.$meta == null && val.$ == null;
};
34 changes: 34 additions & 0 deletions test/query.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4383,4 +4383,38 @@ describe('Query', function() {
await Error.find().sort('-');
}, { message: 'Invalid field "" passed to sort()' });
});

it('does not apply sibling path defaults if using nested projection (gh-14115)', async function() {
const version = await start.mongodVersion();
if (version[0] < 5) {
return this.skip();
}

const userSchema = new mongoose.Schema({
name: String,
account: {
amount: Number,
owner: { type: String, default: () => 'OWNER' },
taxIds: [Number]
}
});
const User = db.model('User', userSchema);

const { _id } = await User.create({
name: 'test',
account: {
amount: 25,
owner: 'test',
taxIds: [42]
}
});

const doc = await User
.findOne({ _id }, { name: 1, account: { amount: 1 } })
.orFail();
assert.strictEqual(doc.name, 'test');
assert.strictEqual(doc.account.amount, 25);
assert.strictEqual(doc.account.owner, undefined);
assert.strictEqual(doc.account.taxIds, undefined);
});
});

0 comments on commit d36d134

Please sign in to comment.