123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729 |
- 'use strict';
- const MongooseError = require('../../error/index');
- const SkipPopulateValue = require('./SkipPopulateValue');
- const get = require('../get');
- const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
- const getConstructorName = require('../getConstructorName');
- const getSchemaTypes = require('./getSchemaTypes');
- const getVirtual = require('./getVirtual');
- const lookupLocalFields = require('./lookupLocalFields');
- const mpath = require('mpath');
- const modelNamesFromRefPath = require('./modelNamesFromRefPath');
- const utils = require('../../utils');
- const modelSymbol = require('../symbols').modelSymbol;
- const populateModelSymbol = require('../symbols').populateModelSymbol;
- const schemaMixedSymbol = require('../../schema/symbols').schemaMixedSymbol;
- module.exports = function getModelsMapForPopulate(model, docs, options) {
- let doc;
- const len = docs.length;
- const map = [];
- const modelNameFromQuery = options.model && options.model.modelName || options.model;
- let schema;
- let refPath;
- let modelNames;
- const available = {};
- const modelSchema = model.schema;
- // Populating a nested path should always be a no-op re: #9073.
- // People shouldn't do this, but apparently they do.
- if (options._localModel != null && options._localModel.schema.nested[options.path]) {
- return [];
- }
- const _virtualRes = getVirtual(model.schema, options.path);
- const virtual = _virtualRes == null ? null : _virtualRes.virtual;
- if (virtual != null) {
- return _virtualPopulate(model, docs, options, _virtualRes);
- }
- let allSchemaTypes = getSchemaTypes(model, modelSchema, null, options.path);
- allSchemaTypes = Array.isArray(allSchemaTypes) ? allSchemaTypes : [allSchemaTypes].filter(v => v != null);
- if (allSchemaTypes.length === 0 && options.strictPopulate !== false && options._localModel != null) {
- return new MongooseError('Cannot populate path `' + (options._fullPath || options.path) +
- '` because it is not in your schema. Set the `strictPopulate` option ' +
- 'to false to override.');
- }
- for (let i = 0; i < len; i++) {
- doc = docs[i];
- let justOne = null;
- const docSchema = doc != null && doc.$__ != null ? doc.$__schema : modelSchema;
- schema = getSchemaTypes(model, docSchema, doc, options.path);
- // Special case: populating a path that's a DocumentArray unless
- // there's an explicit `ref` or `refPath` re: gh-8946
- if (schema != null &&
- schema.$isMongooseDocumentArray &&
- schema.options.ref == null &&
- schema.options.refPath == null) {
- continue;
- }
- const isUnderneathDocArray = schema && schema.$isUnderneathDocArray;
- if (isUnderneathDocArray && get(options, 'options.sort') != null) {
- return new MongooseError('Cannot populate with `sort` on path ' + options.path +
- ' because it is a subproperty of a document array');
- }
- modelNames = null;
- let isRefPath = false;
- let normalizedRefPath = null;
- let schemaOptions = null;
- let modelNamesInOrder = null;
- if (schema != null && schema.instance === 'Embedded') {
- if (schema.options.ref) {
- const data = {
- localField: options.path + '._id',
- foreignField: '_id',
- justOne: true
- };
- const res = _getModelNames(doc, schema, modelNameFromQuery, model);
- const unpopulatedValue = mpath.get(options.path, doc);
- const id = mpath.get('_id', unpopulatedValue);
- addModelNamesToMap(model, map, available, res.modelNames, options, data, id, doc, schemaOptions, unpopulatedValue);
- }
- // No-op if no `ref` set. See gh-11538
- continue;
- }
- if (Array.isArray(schema)) {
- const schemasArray = schema;
- for (const _schema of schemasArray) {
- let _modelNames;
- let res;
- try {
- res = _getModelNames(doc, _schema, modelNameFromQuery, model);
- _modelNames = res.modelNames;
- isRefPath = isRefPath || res.isRefPath;
- normalizedRefPath = normalizedRefPath || res.refPath;
- justOne = res.justOne;
- } catch (error) {
- return error;
- }
- if (isRefPath && !res.isRefPath) {
- continue;
- }
- if (!_modelNames) {
- continue;
- }
- modelNames = modelNames || [];
- for (const modelName of _modelNames) {
- if (modelNames.indexOf(modelName) === -1) {
- modelNames.push(modelName);
- }
- }
- }
- } else {
- try {
- const res = _getModelNames(doc, schema, modelNameFromQuery, model);
- modelNames = res.modelNames;
- isRefPath = res.isRefPath;
- normalizedRefPath = normalizedRefPath || res.refPath;
- justOne = res.justOne;
- schemaOptions = get(schema, 'options.populate', null);
- // Dedupe, because `refPath` can return duplicates of the same model name,
- // and that causes perf issues.
- if (isRefPath) {
- modelNamesInOrder = modelNames;
- modelNames = Array.from(new Set(modelNames));
- }
- } catch (error) {
- return error;
- }
- if (!modelNames) {
- continue;
- }
- }
- const data = {};
- const localField = options.path;
- const foreignField = '_id';
- // `justOne = null` means we don't know from the schema whether the end
- // result should be an array or a single doc. This can result from
- // populating a POJO using `Model.populate()`
- if ('justOne' in options && options.justOne !== void 0) {
- justOne = options.justOne;
- } else if (schema && !schema[schemaMixedSymbol]) {
- // Skip Mixed types because we explicitly don't do casting on those.
- if (options.path.endsWith('.' + schema.path) || options.path === schema.path) {
- justOne = Array.isArray(schema) ?
- schema.every(schema => !schema.$isMongooseArray) :
- !schema.$isMongooseArray;
- }
- }
- if (!modelNames) {
- continue;
- }
- data.isVirtual = false;
- data.justOne = justOne;
- data.localField = localField;
- data.foreignField = foreignField;
- // Get local fields
- const ret = _getLocalFieldValues(doc, localField, model, options, null, schema);
- const id = String(utils.getValue(foreignField, doc));
- options._docs[id] = Array.isArray(ret) ? ret.slice() : ret;
- let match = get(options, 'match', null);
- const hasMatchFunction = typeof match === 'function';
- if (hasMatchFunction) {
- match = match.call(doc, doc);
- }
- data.match = match;
- data.hasMatchFunction = hasMatchFunction;
- data.isRefPath = isRefPath;
- data.modelNamesInOrder = modelNamesInOrder;
- if (isRefPath) {
- const embeddedDiscriminatorModelNames = _findRefPathForDiscriminators(doc,
- modelSchema, data, options, normalizedRefPath, ret);
- modelNames = embeddedDiscriminatorModelNames || modelNames;
- }
- try {
- addModelNamesToMap(model, map, available, modelNames, options, data, ret, doc, schemaOptions);
- } catch (err) {
- return err;
- }
- }
- return map;
- function _getModelNames(doc, schema, modelNameFromQuery, model) {
- let modelNames;
- let isRefPath = false;
- let justOne = null;
- if (schema && schema.instance === 'Array') {
- schema = schema.caster;
- }
- if (schema && schema.$isSchemaMap) {
- schema = schema.$__schemaType;
- }
- const ref = schema && schema.options && schema.options.ref;
- refPath = schema && schema.options && schema.options.refPath;
- if (schema != null &&
- schema[schemaMixedSymbol] &&
- !ref &&
- !refPath &&
- !modelNameFromQuery) {
- return { modelNames: null };
- }
- if (modelNameFromQuery) {
- modelNames = [modelNameFromQuery]; // query options
- } else if (refPath != null) {
- if (typeof refPath === 'function') {
- const subdocPath = options.path.slice(0, options.path.length - schema.path.length - 1);
- const vals = mpath.get(subdocPath, doc, lookupLocalFields);
- const subdocsBeingPopulated = Array.isArray(vals) ?
- utils.array.flatten(vals) :
- (vals ? [vals] : []);
- modelNames = new Set();
- for (const subdoc of subdocsBeingPopulated) {
- refPath = refPath.call(subdoc, subdoc, options.path);
- modelNamesFromRefPath(refPath, doc, options.path, modelSchema, options._queryProjection).
- forEach(name => modelNames.add(name));
- }
- modelNames = Array.from(modelNames);
- } else {
- modelNames = modelNamesFromRefPath(refPath, doc, options.path, modelSchema, options._queryProjection);
- }
- isRefPath = true;
- } else {
- let ref;
- let refPath;
- let schemaForCurrentDoc;
- let discriminatorValue;
- let modelForCurrentDoc = model;
- const discriminatorKey = model.schema.options.discriminatorKey;
- if (!schema && discriminatorKey && (discriminatorValue = utils.getValue(discriminatorKey, doc))) {
- // `modelNameForFind` is the discriminator value, so we might need
- // find the discriminated model name
- const discriminatorModel = getDiscriminatorByValue(model.discriminators, discriminatorValue) || model;
- if (discriminatorModel != null) {
- modelForCurrentDoc = discriminatorModel;
- } else {
- try {
- modelForCurrentDoc = _getModelFromConn(model.db, discriminatorValue);
- } catch (error) {
- return error;
- }
- }
- schemaForCurrentDoc = modelForCurrentDoc.schema._getSchema(options.path);
- if (schemaForCurrentDoc && schemaForCurrentDoc.caster) {
- schemaForCurrentDoc = schemaForCurrentDoc.caster;
- }
- } else {
- schemaForCurrentDoc = schema;
- }
- if (schemaForCurrentDoc != null) {
- justOne = !schemaForCurrentDoc.$isMongooseArray && !schemaForCurrentDoc._arrayPath;
- }
- if ((ref = get(schemaForCurrentDoc, 'options.ref')) != null) {
- if (schemaForCurrentDoc != null &&
- typeof ref === 'function' &&
- options.path.endsWith('.' + schemaForCurrentDoc.path)) {
- // Ensure correct context for ref functions: subdoc, not top-level doc. See gh-8469
- modelNames = new Set();
- const subdocPath = options.path.slice(0, options.path.length - schemaForCurrentDoc.path.length - 1);
- const vals = mpath.get(subdocPath, doc, lookupLocalFields);
- const subdocsBeingPopulated = Array.isArray(vals) ?
- utils.array.flatten(vals) :
- (vals ? [vals] : []);
- for (const subdoc of subdocsBeingPopulated) {
- modelNames.add(handleRefFunction(ref, subdoc));
- }
- if (subdocsBeingPopulated.length === 0) {
- modelNames = [handleRefFunction(ref, doc)];
- } else {
- modelNames = Array.from(modelNames);
- }
- } else {
- ref = handleRefFunction(ref, doc);
- modelNames = [ref];
- }
- } else if ((schemaForCurrentDoc = get(schema, 'options.refPath')) != null) {
- isRefPath = true;
- if (typeof refPath === 'function') {
- const subdocPath = options.path.slice(0, options.path.length - schemaForCurrentDoc.path.length - 1);
- const vals = mpath.get(subdocPath, doc, lookupLocalFields);
- const subdocsBeingPopulated = Array.isArray(vals) ?
- utils.array.flatten(vals) :
- (vals ? [vals] : []);
- modelNames = new Set();
- for (const subdoc of subdocsBeingPopulated) {
- refPath = refPath.call(subdoc, subdoc, options.path);
- modelNamesFromRefPath(refPath, doc, options.path, modelSchema, options._queryProjection).
- forEach(name => modelNames.add(name));
- }
- modelNames = Array.from(modelNames);
- } else {
- modelNames = modelNamesFromRefPath(refPath, doc, options.path, modelSchema, options._queryProjection);
- }
- }
- }
- if (!modelNames) {
- // `Model.populate()` on a POJO with no known local model. Default to using the `Model`
- if (options._localModel == null) {
- modelNames = [model.modelName];
- } else {
- return { modelNames: modelNames, justOne: justOne, isRefPath: isRefPath, refPath: refPath };
- }
- }
- if (!Array.isArray(modelNames)) {
- modelNames = [modelNames];
- }
- return { modelNames: modelNames, justOne: justOne, isRefPath: isRefPath, refPath: refPath };
- }
- };
- /*!
- * ignore
- */
- function _virtualPopulate(model, docs, options, _virtualRes) {
- const map = [];
- const available = {};
- const virtual = _virtualRes.virtual;
- for (const doc of docs) {
- let modelNames = null;
- const data = {};
- // localField and foreignField
- let localField;
- const virtualPrefix = _virtualRes.nestedSchemaPath ?
- _virtualRes.nestedSchemaPath + '.' : '';
- if (typeof virtual.options.localField === 'function') {
- localField = virtualPrefix + virtual.options.localField.call(doc, doc);
- } else if (Array.isArray(virtual.options.localField)) {
- localField = virtual.options.localField.map(field => virtualPrefix + field);
- } else {
- localField = virtualPrefix + virtual.options.localField;
- }
- data.count = virtual.options.count;
- if (virtual.options.skip != null && !options.hasOwnProperty('skip')) {
- options.skip = virtual.options.skip;
- }
- if (virtual.options.limit != null && !options.hasOwnProperty('limit')) {
- options.limit = virtual.options.limit;
- }
- if (virtual.options.perDocumentLimit != null && !options.hasOwnProperty('perDocumentLimit')) {
- options.perDocumentLimit = virtual.options.perDocumentLimit;
- }
- let foreignField = virtual.options.foreignField;
- if (!localField || !foreignField) {
- return new MongooseError('If you are populating a virtual, you must set the ' +
- 'localField and foreignField options');
- }
- if (typeof localField === 'function') {
- localField = localField.call(doc, doc);
- }
- if (typeof foreignField === 'function') {
- foreignField = foreignField.call(doc, doc);
- }
- data.isRefPath = false;
- // `justOne = null` means we don't know from the schema whether the end
- // result should be an array or a single doc. This can result from
- // populating a POJO using `Model.populate()`
- let justOne = null;
- if ('justOne' in options && options.justOne !== void 0) {
- justOne = options.justOne;
- }
- if (virtual.options.refPath) {
- modelNames =
- modelNamesFromRefPath(virtual.options.refPath, doc, options.path);
- justOne = !!virtual.options.justOne;
- data.isRefPath = true;
- } else if (virtual.options.ref) {
- let normalizedRef;
- if (typeof virtual.options.ref === 'function' && !virtual.options.ref[modelSymbol]) {
- normalizedRef = virtual.options.ref.call(doc, doc);
- } else {
- normalizedRef = virtual.options.ref;
- }
- justOne = !!virtual.options.justOne;
- // When referencing nested arrays, the ref should be an Array
- // of modelNames.
- if (Array.isArray(normalizedRef)) {
- modelNames = normalizedRef;
- } else {
- modelNames = [normalizedRef];
- }
- }
- data.isVirtual = true;
- data.virtual = virtual;
- data.justOne = justOne;
- // `match`
- let match = get(options, 'match', null) ||
- get(data, 'virtual.options.match', null) ||
- get(data, 'virtual.options.options.match', null);
- let hasMatchFunction = typeof match === 'function';
- if (hasMatchFunction) {
- match = match.call(doc, doc);
- }
- if (Array.isArray(localField) && Array.isArray(foreignField) && localField.length === foreignField.length) {
- match = Object.assign({}, match);
- for (let i = 1; i < localField.length; ++i) {
- match[foreignField[i]] = convertTo_id(mpath.get(localField[i], doc, lookupLocalFields), model.schema);
- hasMatchFunction = true;
- }
- localField = localField[0];
- foreignField = foreignField[0];
- }
- data.localField = localField;
- data.foreignField = foreignField;
- data.match = match;
- data.hasMatchFunction = hasMatchFunction;
- // Get local fields
- const ret = _getLocalFieldValues(doc, localField, model, options, virtual);
- try {
- addModelNamesToMap(model, map, available, modelNames, options, data, ret, doc);
- } catch (err) {
- return err;
- }
- }
- return map;
- }
- /*!
- * ignore
- */
- function addModelNamesToMap(model, map, available, modelNames, options, data, ret, doc, schemaOptions, unpopulatedValue) {
- // `PopulateOptions#connection`: if the model is passed as a string, the
- // connection matters because different connections have different models.
- const connection = options.connection != null ? options.connection : model.db;
- unpopulatedValue = unpopulatedValue === void 0 ? ret : unpopulatedValue;
- if (Array.isArray(unpopulatedValue)) {
- unpopulatedValue = utils.cloneArrays(unpopulatedValue);
- }
- if (modelNames == null) {
- return;
- }
- let k = modelNames.length;
- while (k--) {
- const modelName = modelNames[k];
- if (modelName == null) {
- continue;
- }
- let Model;
- if (options.model && options.model[modelSymbol]) {
- Model = options.model;
- } else if (modelName[modelSymbol]) {
- Model = modelName;
- } else {
- try {
- Model = _getModelFromConn(connection, modelName);
- } catch (err) {
- if (ret !== void 0) {
- throw err;
- }
- Model = null;
- }
- }
- let ids = ret;
- const flat = Array.isArray(ret) ? utils.array.flatten(ret) : [];
- const modelNamesForRefPath = data.modelNamesInOrder ? data.modelNamesInOrder : modelNames;
- if (data.isRefPath && Array.isArray(ret) && flat.length === modelNamesForRefPath.length) {
- ids = flat.filter((val, i) => modelNamesForRefPath[i] === modelName);
- }
- const perDocumentLimit = options.perDocumentLimit == null ?
- get(options, 'options.perDocumentLimit', null) :
- options.perDocumentLimit;
- if (!available[modelName] || perDocumentLimit != null) {
- const currentOptions = {
- model: Model
- };
- if (data.isVirtual && get(data.virtual, 'options.options')) {
- currentOptions.options = utils.clone(data.virtual.options.options);
- } else if (schemaOptions != null) {
- currentOptions.options = Object.assign({}, schemaOptions);
- }
- utils.merge(currentOptions, options);
- // Used internally for checking what model was used to populate this
- // path.
- options[populateModelSymbol] = Model;
- available[modelName] = {
- model: Model,
- options: currentOptions,
- match: data.hasMatchFunction ? [data.match] : data.match,
- docs: [doc],
- ids: [ids],
- allIds: [ret],
- unpopulatedValues: [unpopulatedValue],
- localField: new Set([data.localField]),
- foreignField: new Set([data.foreignField]),
- justOne: data.justOne,
- isVirtual: data.isVirtual,
- virtual: data.virtual,
- count: data.count,
- [populateModelSymbol]: Model
- };
- map.push(available[modelName]);
- } else {
- available[modelName].localField.add(data.localField);
- available[modelName].foreignField.add(data.foreignField);
- available[modelName].docs.push(doc);
- available[modelName].ids.push(ids);
- available[modelName].allIds.push(ret);
- available[modelName].unpopulatedValues.push(unpopulatedValue);
- if (data.hasMatchFunction) {
- available[modelName].match.push(data.match);
- }
- }
- }
- }
- function _getModelFromConn(conn, modelName) {
- /* If this connection has a parent from `useDb()`, bubble up to parent's models */
- if (conn.models[modelName] == null && conn._parent != null) {
- return _getModelFromConn(conn._parent, modelName);
- }
- return conn.model(modelName);
- }
- /*!
- * ignore
- */
- function handleRefFunction(ref, doc) {
- if (typeof ref === 'function' && !ref[modelSymbol]) {
- return ref.call(doc, doc);
- }
- return ref;
- }
- /*!
- * ignore
- */
- function _getLocalFieldValues(doc, localField, model, options, virtual, schema) {
- // Get Local fields
- const localFieldPathType = model.schema._getPathType(localField);
- const localFieldPath = localFieldPathType === 'real' ?
- model.schema.path(localField) :
- localFieldPathType.schema;
- const localFieldGetters = localFieldPath && localFieldPath.getters ?
- localFieldPath.getters : [];
- localField = localFieldPath != null && localFieldPath.instance === 'Embedded' ? localField + '._id' : localField;
- const _populateOptions = get(options, 'options', {});
- const getters = 'getters' in _populateOptions ?
- _populateOptions.getters :
- get(virtual, 'options.getters', false);
- if (localFieldGetters.length !== 0 && getters) {
- const hydratedDoc = (doc.$__ != null) ? doc : model.hydrate(doc);
- const localFieldValue = utils.getValue(localField, doc);
- if (Array.isArray(localFieldValue)) {
- const localFieldHydratedValue = utils.getValue(localField.split('.').slice(0, -1), hydratedDoc);
- return localFieldValue.map((localFieldArrVal, localFieldArrIndex) =>
- localFieldPath.applyGetters(localFieldArrVal, localFieldHydratedValue[localFieldArrIndex]));
- } else {
- return localFieldPath.applyGetters(localFieldValue, hydratedDoc);
- }
- } else {
- return convertTo_id(mpath.get(localField, doc, lookupLocalFields), schema);
- }
- }
- /*!
- * Retrieve the _id of `val` if a Document or Array of Documents.
- *
- * @param {Array|Document|Any} val
- * @return {Array|Document|Any}
- */
- function convertTo_id(val, schema) {
- if (val != null && val.$__ != null) {
- return val._id;
- }
- if (val != null && val._id != null && (schema == null || !schema.$isSchemaMap)) {
- return val._id;
- }
- if (Array.isArray(val)) {
- const rawVal = val.__array != null ? val.__array : val;
- for (let i = 0; i < rawVal.length; ++i) {
- if (rawVal[i] != null && rawVal[i].$__ != null) {
- rawVal[i] = rawVal[i]._id;
- }
- }
- if (utils.isMongooseArray(val) && val.$schema()) {
- return val.$schema()._castForPopulate(val, val.$parent());
- }
- return [].concat(val);
- }
- // `populate('map')` may be an object if populating on a doc that hasn't
- // been hydrated yet
- if (getConstructorName(val) === '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]);
- }
- return ret;
- }
- // If doc has already been hydrated, e.g. `doc.populate('map')`
- // then `val` will already be a map
- if (val instanceof Map) {
- return Array.from(val.values());
- }
- return val;
- }
- /*!
- * ignore
- */
- function _findRefPathForDiscriminators(doc, modelSchema, data, options, normalizedRefPath, ret) {
- // Re: gh-8452. Embedded discriminators may not have `refPath`, so clear
- // out embedded discriminator docs that don't have a `refPath` on the
- // populated path.
- if (!data.isRefPath || normalizedRefPath == null) {
- return;
- }
- const pieces = normalizedRefPath.split('.');
- let cur = '';
- let modelNames = void 0;
- for (let i = 0; i < pieces.length; ++i) {
- const piece = pieces[i];
- cur = cur + (cur.length === 0 ? '' : '.') + piece;
- const schematype = modelSchema.path(cur);
- if (schematype != null &&
- schematype.$isMongooseArray &&
- schematype.caster.discriminators != null &&
- Object.keys(schematype.caster.discriminators).length !== 0) {
- const subdocs = utils.getValue(cur, doc);
- const remnant = options.path.substring(cur.length + 1);
- const discriminatorKey = schematype.caster.schema.options.discriminatorKey;
- modelNames = [];
- for (const subdoc of subdocs) {
- const discriminatorName = utils.getValue(discriminatorKey, subdoc);
- const discriminator = schematype.caster.discriminators[discriminatorName];
- const discriminatorSchema = discriminator && discriminator.schema;
- if (discriminatorSchema == null) {
- continue;
- }
- const _path = discriminatorSchema.path(remnant);
- if (_path == null || _path.options.refPath == null) {
- const docValue = utils.getValue(data.localField.substring(cur.length + 1), subdoc);
- ret.forEach((v, i) => {
- if (v === docValue) {
- ret[i] = SkipPopulateValue(v);
- }
- });
- continue;
- }
- const modelName = utils.getValue(pieces.slice(i + 1).join('.'), subdoc);
- modelNames.push(modelName);
- }
- }
- }
- return modelNames;
- }
|