diff --git a/lib/helpers/populate/getModelsMapForPopulate.js b/lib/helpers/populate/getModelsMapForPopulate.js index 62fc180c6bc..abb68b7bf09 100644 --- a/lib/helpers/populate/getModelsMapForPopulate.js +++ b/lib/helpers/populate/getModelsMapForPopulate.js @@ -166,7 +166,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) { ret = localFieldPath.applyGetters(localFieldValue, hydratedDoc); } } else { - ret = convertTo_id(utils.getValue(localField, doc)); + ret = convertTo_id(utils.getValue(localField, doc), schema); } const id = String(utils.getValue(foreignField, doc)); @@ -377,7 +377,7 @@ function handleRefFunction(ref, doc) { * @return {Array|Document|Any} */ -function convertTo_id(val) { +function convertTo_id(val, schema) { if (val != null && val.$__ != null) return val._id; if (Array.isArray(val)) { @@ -395,7 +395,11 @@ function convertTo_id(val) { // `populate('map')` may be an object if populating on a doc that hasn't // been hydrated yet - if (val != null && val.constructor.name === 'Object') { + if (val != null && + val.constructor.name === 'Object' && + // The intent here is we should only flatten the object if we expect + // to get a Map in the end. Avoid doing this for mixed types. + (schema == null || schema[schemaMixedSymbol] == null)) { const ret = []; for (const key of Object.keys(val)) { ret.push(val[key]); diff --git a/test/types.map.test.js b/test/types.map.test.js index 19cc6762a61..34a72d3ee04 100644 --- a/test/types.map.test.js +++ b/test/types.map.test.js @@ -371,7 +371,7 @@ describe('Map', function() { }); }); - it('avoid populating as map if populate on obj (gh-6460)', function() { + it('avoid populating as map if populate on obj (gh-6460) (gh-8157)', function() { const UserSchema = new mongoose.Schema({ apiKeys: {} }); @@ -387,8 +387,12 @@ describe('Map', function() { const doc = yield User.create({ apiKeys: { github: key._id, twitter: key2._id } }); - const populated = yield User.findById(doc).populate('apiKeys'); + const populated = yield User.findById(doc).populate({ + path: 'apiKeys', + skipInvalidIds: true + }); assert.ok(!(populated.apiKeys instanceof Map)); + assert.ok(!Array.isArray(populated.apiKeys)); }); });