Skip to content

Commit ff3d36f

Browse files
committed
fix(populate+discriminator): handle populating document whose discriminator value is different from discriminator model name
Fix #8324
1 parent a32d9a8 commit ff3d36f

File tree

9 files changed

+47
-39
lines changed

9 files changed

+47
-39
lines changed

lib/helpers/discriminator/getConstructor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
const getDiscriminatorByValue = require('../../queryhelpers').getDiscriminatorByValue;
3+
const getDiscriminatorByValue = require('./getDiscriminatorByValue');
44

55
/*!
66
* Find the correct constructor, taking into account discriminators
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
/*!
4+
* returns discriminator by discriminatorMapping.value
5+
*
6+
* @param {Model} model
7+
* @param {string} value
8+
*/
9+
10+
module.exports = function getDiscriminatorByValue(model, value) {
11+
let discriminator = null;
12+
if (!model.discriminators) {
13+
return discriminator;
14+
}
15+
for (const name in model.discriminators) {
16+
const it = model.discriminators[name];
17+
if (
18+
it.schema &&
19+
it.schema.discriminatorMapping &&
20+
it.schema.discriminatorMapping.value == value
21+
) {
22+
discriminator = it;
23+
break;
24+
}
25+
}
26+
return discriminator;
27+
}

lib/helpers/populate/getModelsMapForPopulate.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const MongooseError = require('../../error/index');
44
const get = require('../get');
5+
const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
56
const isPathExcluded = require('../projection/isPathExcluded');
67
const getSchemaTypes = require('./getSchemaTypes');
78
const getVirtual = require('./getVirtual');
@@ -297,12 +298,18 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
297298

298299
if (!schema && discriminatorKey) {
299300
modelForFindSchema = utils.getValue(discriminatorKey, doc);
300-
301301
if (modelForFindSchema) {
302-
try {
303-
modelForCurrentDoc = model.db.model(modelForFindSchema);
304-
} catch (error) {
305-
return error;
302+
// `modelForFindSchema` is the discriminator value, so we might need
303+
// find the discriminated model name
304+
const discriminatorModel = getDiscriminatorByValue(model, modelForFindSchema);
305+
if (discriminatorModel != null) {
306+
modelForCurrentDoc = discriminatorModel;
307+
} else {
308+
try {
309+
modelForCurrentDoc = model.db.model(modelForFindSchema);
310+
} catch (error) {
311+
return error;
312+
}
306313
}
307314

308315
schemaForCurrentDoc = modelForCurrentDoc.schema._getSchema(options.path);

lib/model.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const assignVals = require('./helpers/populate/assignVals');
3030
const castBulkWrite = require('./helpers/model/castBulkWrite');
3131
const discriminator = require('./helpers/model/discriminator');
3232
const each = require('./helpers/each');
33-
const getDiscriminatorByValue = require('./queryhelpers').getDiscriminatorByValue;
33+
const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue');
3434
const getModelsMapForPopulate = require('./helpers/populate/getModelsMapForPopulate');
3535
const immediate = require('./helpers/immediate');
3636
const internalToObjectOptions = require('./options').internalToObjectOptions;

lib/query.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const castArrayFilters = require('./helpers/update/castArrayFilters');
1818
const castUpdate = require('./helpers/query/castUpdate');
1919
const completeMany = require('./helpers/query/completeMany');
2020
const get = require('./helpers/get');
21+
const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue');
2122
const hasDollarKeys = require('./helpers/query/hasDollarKeys');
2223
const helpers = require('./queryhelpers');
2324
const isInclusive = require('./helpers/projection/isInclusive');
@@ -4429,7 +4430,7 @@ Query.prototype._castUpdate = function _castUpdate(obj, overwrite) {
44294430
typeof filter[schema.options.discriminatorKey] !== 'object' &&
44304431
schema.discriminators != null) {
44314432
const discriminatorValue = filter[schema.options.discriminatorKey];
4432-
const byValue = helpers.getDiscriminatorByValue(this.model, discriminatorValue);
4433+
const byValue = getDiscriminatorByValue(this.model, discriminatorValue);
44334434
schema = schema.discriminators[discriminatorValue] ||
44344435
(byValue && byValue.schema) ||
44354436
schema;

lib/queryhelpers.js

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
const checkEmbeddedDiscriminatorKeyProjection =
88
require('./helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection');
99
const get = require('./helpers/get');
10+
const getDiscriminatorByValue =
11+
require('./helpers/discriminator/getDiscriminatorByValue');
1012
const isDefiningProjection = require('./helpers/projection/isDefiningProjection');
1113
const utils = require('./utils');
1214

@@ -71,34 +73,6 @@ exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query,
7173
return pop;
7274
};
7375

74-
75-
/*!
76-
* returns discriminator by discriminatorMapping.value
77-
*
78-
* @param {Model} model
79-
* @param {string} value
80-
*/
81-
function getDiscriminatorByValue(model, value) {
82-
let discriminator = null;
83-
if (!model.discriminators) {
84-
return discriminator;
85-
}
86-
for (const name in model.discriminators) {
87-
const it = model.discriminators[name];
88-
if (
89-
it.schema &&
90-
it.schema.discriminatorMapping &&
91-
it.schema.discriminatorMapping.value == value
92-
) {
93-
discriminator = it;
94-
break;
95-
}
96-
}
97-
return discriminator;
98-
}
99-
100-
exports.getDiscriminatorByValue = getDiscriminatorByValue;
101-
10276
/*!
10377
* If the document is a mapped discriminator type, it returns a model instance for that type, otherwise,
10478
* it returns an instance of the given model.

lib/schema/array.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const util = require('util');
1717
const utils = require('../utils');
1818
const castToNumber = require('./operators/helpers').castToNumber;
1919
const geospatial = require('./operators/geospatial');
20-
const getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByValue;
20+
const getDiscriminatorByValue = require('../helpers/discriminator/getDiscriminatorByValue');
2121

2222
let MongooseArray;
2323
let EmbeddedDoc;

lib/types/documentarray.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const CoreMongooseArray = require('./core_array');
88
const Document = require('../document');
99
const ObjectId = require('./objectid');
1010
const castObjectId = require('../cast/objectid');
11-
const getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByValue;
11+
const getDiscriminatorByValue = require('../helpers/discriminator/getDiscriminatorByValue');
1212
const internalToObjectOptions = require('../options').internalToObjectOptions;
1313
const util = require('util');
1414
const utils = require('../utils');

test/model.populate.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8825,7 +8825,6 @@ describe('model: populate:', function() {
88258825
yield Model.create({ main: d._id });
88268826

88278827
const docs = yield Main.find().populate('virtualField').exec();
8828-
console.log(docs.map(d => d.virtualField))
88298828
assert.ok(docs[0].virtualField[0].main);
88308829
});
88318830
});

0 commit comments

Comments
 (0)