diff --git a/lib/queryhelpers.js b/lib/queryhelpers.js index dfc98e49ec5..62a8cb5b1f4 100644 --- a/lib/queryhelpers.js +++ b/lib/queryhelpers.js @@ -232,7 +232,9 @@ exports.applyPaths = function applyPaths(fields, schema) { schema.eachPath(function(path, type) { if (prefix) path = prefix + '.' + path; if (type.$isSchemaMap || path.endsWith('.$*')) { - if (type.options && type.options.select === false) { + const plusPath = '+' + path; + const hasPlusPath = fields && plusPath in fields; + if (type.options && type.options.select === false && !hasPlusPath) { excluded.push(path); } return; diff --git a/test/query.test.js b/test/query.test.js index b61b39631b7..b56a5e6c3de 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -4133,6 +4133,34 @@ describe('Query', function() { assert.equal(item.doNotSelect, undefined); }); + it('Map field with select: false is selected when explicitly requested (gh-12603)', async function() { + const testSchema = new mongoose.Schema({ + title: String, + body: { + type: Map, + of: { en: String, pt: String }, + select: false + } + }); + + const Test = db.model('Test', testSchema); + await Test.create({ + title: 'test', + body: { + A: { en: 'en test A value', pt: 'pt test A value' }, + B: { en: 'en test B value', pt: 'pt test B value' } + } + }); + + const item = await Test.findOne({}).select('+body'); + assert.equal(item.title, 'test'); + assert.equal(item.get('body.A.en'), 'en test A value'); + + const item2 = await Test.findOne({}).select('body'); + assert.equal(item2.title, undefined); + assert.equal(item2.get('body.A.en'), 'en test A value'); + }); + it('treats ObjectId as object with `_id` for `merge()` (gh-12325)', async function() { const testSchema = new mongoose.Schema({ name: String }); const Test = db.model('Test', testSchema);