@depup/mongoose 9.1.3-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/LICENSE.md +22 -0
  2. package/README.md +397 -0
  3. package/SECURITY.md +1 -0
  4. package/eslint.config.mjs +198 -0
  5. package/index.js +64 -0
  6. package/lib/aggregate.js +1189 -0
  7. package/lib/cast/bigint.js +46 -0
  8. package/lib/cast/boolean.js +32 -0
  9. package/lib/cast/date.js +41 -0
  10. package/lib/cast/decimal128.js +39 -0
  11. package/lib/cast/double.js +50 -0
  12. package/lib/cast/int32.js +36 -0
  13. package/lib/cast/number.js +42 -0
  14. package/lib/cast/objectid.js +29 -0
  15. package/lib/cast/string.js +37 -0
  16. package/lib/cast/uuid.js +35 -0
  17. package/lib/cast.js +436 -0
  18. package/lib/collection.js +321 -0
  19. package/lib/connection.js +1855 -0
  20. package/lib/connectionState.js +26 -0
  21. package/lib/constants.js +73 -0
  22. package/lib/cursor/aggregationCursor.js +466 -0
  23. package/lib/cursor/changeStream.js +198 -0
  24. package/lib/cursor/queryCursor.js +622 -0
  25. package/lib/document.js +5521 -0
  26. package/lib/driver.js +15 -0
  27. package/lib/drivers/SPEC.md +4 -0
  28. package/lib/drivers/node-mongodb-native/bulkWriteResult.js +5 -0
  29. package/lib/drivers/node-mongodb-native/collection.js +393 -0
  30. package/lib/drivers/node-mongodb-native/connection.js +506 -0
  31. package/lib/drivers/node-mongodb-native/index.js +10 -0
  32. package/lib/error/browserMissingSchema.js +29 -0
  33. package/lib/error/bulkSaveIncompleteError.js +44 -0
  34. package/lib/error/bulkWriteError.js +41 -0
  35. package/lib/error/cast.js +158 -0
  36. package/lib/error/createCollectionsError.js +26 -0
  37. package/lib/error/divergentArray.js +40 -0
  38. package/lib/error/eachAsyncMultiError.js +41 -0
  39. package/lib/error/index.js +237 -0
  40. package/lib/error/invalidSchemaOption.js +32 -0
  41. package/lib/error/messages.js +47 -0
  42. package/lib/error/missingSchema.js +33 -0
  43. package/lib/error/mongooseError.js +13 -0
  44. package/lib/error/notFound.js +47 -0
  45. package/lib/error/objectExpected.js +31 -0
  46. package/lib/error/objectParameter.js +31 -0
  47. package/lib/error/overwriteModel.js +31 -0
  48. package/lib/error/parallelSave.js +33 -0
  49. package/lib/error/parallelValidate.js +33 -0
  50. package/lib/error/serverSelection.js +62 -0
  51. package/lib/error/setOptionError.js +103 -0
  52. package/lib/error/strict.js +35 -0
  53. package/lib/error/strictPopulate.js +31 -0
  54. package/lib/error/syncIndexes.js +30 -0
  55. package/lib/error/validation.js +97 -0
  56. package/lib/error/validator.js +100 -0
  57. package/lib/error/version.js +38 -0
  58. package/lib/helpers/aggregate/prepareDiscriminatorPipeline.js +39 -0
  59. package/lib/helpers/aggregate/stringifyFunctionOperators.js +50 -0
  60. package/lib/helpers/arrayDepth.js +33 -0
  61. package/lib/helpers/clone.js +204 -0
  62. package/lib/helpers/common.js +127 -0
  63. package/lib/helpers/createJSONSchemaTypeDefinition.js +24 -0
  64. package/lib/helpers/cursor/eachAsync.js +225 -0
  65. package/lib/helpers/discriminator/applyEmbeddedDiscriminators.js +36 -0
  66. package/lib/helpers/discriminator/areDiscriminatorValuesEqual.js +16 -0
  67. package/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js +12 -0
  68. package/lib/helpers/discriminator/getConstructor.js +29 -0
  69. package/lib/helpers/discriminator/getDiscriminatorByValue.js +28 -0
  70. package/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js +27 -0
  71. package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +91 -0
  72. package/lib/helpers/document/applyDefaults.js +132 -0
  73. package/lib/helpers/document/applyTimestamps.js +106 -0
  74. package/lib/helpers/document/applyVirtuals.js +147 -0
  75. package/lib/helpers/document/cleanModifiedSubpaths.js +45 -0
  76. package/lib/helpers/document/compile.js +238 -0
  77. package/lib/helpers/document/getDeepestSubdocumentForPath.js +38 -0
  78. package/lib/helpers/document/getEmbeddedDiscriminatorPath.js +53 -0
  79. package/lib/helpers/document/handleSpreadDoc.js +35 -0
  80. package/lib/helpers/each.js +25 -0
  81. package/lib/helpers/error/combinePathErrors.js +22 -0
  82. package/lib/helpers/firstKey.js +8 -0
  83. package/lib/helpers/get.js +65 -0
  84. package/lib/helpers/getConstructorName.js +16 -0
  85. package/lib/helpers/getDefaultBulkwriteResult.js +18 -0
  86. package/lib/helpers/getFunctionName.js +10 -0
  87. package/lib/helpers/immediate.js +16 -0
  88. package/lib/helpers/indexes/applySchemaCollation.js +13 -0
  89. package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +14 -0
  90. package/lib/helpers/indexes/getRelatedIndexes.js +63 -0
  91. package/lib/helpers/indexes/isDefaultIdIndex.js +18 -0
  92. package/lib/helpers/indexes/isIndexEqual.js +95 -0
  93. package/lib/helpers/indexes/isIndexSpecEqual.js +32 -0
  94. package/lib/helpers/indexes/isTextIndex.js +16 -0
  95. package/lib/helpers/indexes/isTimeseriesIndex.js +16 -0
  96. package/lib/helpers/isAsyncFunction.js +9 -0
  97. package/lib/helpers/isBsonType.js +15 -0
  98. package/lib/helpers/isMongooseObject.js +22 -0
  99. package/lib/helpers/isObject.js +16 -0
  100. package/lib/helpers/isPOJO.js +12 -0
  101. package/lib/helpers/isPromise.js +6 -0
  102. package/lib/helpers/isSimpleValidator.js +22 -0
  103. package/lib/helpers/minimize.js +41 -0
  104. package/lib/helpers/model/applyDefaultsToPOJO.js +52 -0
  105. package/lib/helpers/model/applyHooks.js +140 -0
  106. package/lib/helpers/model/applyMethods.js +70 -0
  107. package/lib/helpers/model/applyStaticHooks.js +33 -0
  108. package/lib/helpers/model/applyStatics.js +13 -0
  109. package/lib/helpers/model/castBulkWrite.js +316 -0
  110. package/lib/helpers/model/decorateBulkWriteResult.js +8 -0
  111. package/lib/helpers/model/discriminator.js +265 -0
  112. package/lib/helpers/model/pushNestedArrayPaths.js +15 -0
  113. package/lib/helpers/omitUndefined.js +20 -0
  114. package/lib/helpers/once.js +12 -0
  115. package/lib/helpers/parallelLimit.js +37 -0
  116. package/lib/helpers/path/parentPaths.js +18 -0
  117. package/lib/helpers/path/setDottedPath.js +33 -0
  118. package/lib/helpers/pluralize.js +95 -0
  119. package/lib/helpers/populate/assignRawDocsToIdStructure.js +129 -0
  120. package/lib/helpers/populate/assignVals.js +360 -0
  121. package/lib/helpers/populate/createPopulateQueryFilter.js +97 -0
  122. package/lib/helpers/populate/getModelsMapForPopulate.js +776 -0
  123. package/lib/helpers/populate/getSchemaTypes.js +228 -0
  124. package/lib/helpers/populate/getVirtual.js +103 -0
  125. package/lib/helpers/populate/leanPopulateMap.js +7 -0
  126. package/lib/helpers/populate/lookupLocalFields.js +40 -0
  127. package/lib/helpers/populate/markArraySubdocsPopulated.js +49 -0
  128. package/lib/helpers/populate/modelNamesFromRefPath.js +66 -0
  129. package/lib/helpers/populate/removeDeselectedForeignField.js +31 -0
  130. package/lib/helpers/populate/setPopulatedVirtualValue.js +33 -0
  131. package/lib/helpers/populate/skipPopulateValue.js +10 -0
  132. package/lib/helpers/populate/validateRef.js +19 -0
  133. package/lib/helpers/printJestWarning.js +21 -0
  134. package/lib/helpers/processConnectionOptions.js +65 -0
  135. package/lib/helpers/projection/applyProjection.js +83 -0
  136. package/lib/helpers/projection/hasIncludedChildren.js +41 -0
  137. package/lib/helpers/projection/isDefiningProjection.js +18 -0
  138. package/lib/helpers/projection/isExclusive.js +37 -0
  139. package/lib/helpers/projection/isInclusive.js +39 -0
  140. package/lib/helpers/projection/isNestedProjection.js +8 -0
  141. package/lib/helpers/projection/isPathExcluded.js +40 -0
  142. package/lib/helpers/projection/isPathSelectedInclusive.js +28 -0
  143. package/lib/helpers/projection/isSubpath.js +14 -0
  144. package/lib/helpers/projection/parseProjection.js +33 -0
  145. package/lib/helpers/query/applyGlobalOption.js +29 -0
  146. package/lib/helpers/query/cast$expr.js +287 -0
  147. package/lib/helpers/query/castFilterPath.js +54 -0
  148. package/lib/helpers/query/castUpdate.js +643 -0
  149. package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +103 -0
  150. package/lib/helpers/query/handleImmutable.js +44 -0
  151. package/lib/helpers/query/handleReadPreferenceAliases.js +23 -0
  152. package/lib/helpers/query/hasDollarKeys.js +23 -0
  153. package/lib/helpers/query/isOperator.js +14 -0
  154. package/lib/helpers/query/sanitizeFilter.js +38 -0
  155. package/lib/helpers/query/sanitizeProjection.js +14 -0
  156. package/lib/helpers/query/selectPopulatedFields.js +62 -0
  157. package/lib/helpers/query/trusted.js +13 -0
  158. package/lib/helpers/query/validOps.js +3 -0
  159. package/lib/helpers/schema/addAutoId.js +7 -0
  160. package/lib/helpers/schema/applyBuiltinPlugins.js +12 -0
  161. package/lib/helpers/schema/applyPlugins.js +55 -0
  162. package/lib/helpers/schema/applyReadConcern.js +20 -0
  163. package/lib/helpers/schema/applyWriteConcern.js +39 -0
  164. package/lib/helpers/schema/cleanPositionalOperators.js +12 -0
  165. package/lib/helpers/schema/getIndexes.js +171 -0
  166. package/lib/helpers/schema/getKeysInSchemaOrder.js +28 -0
  167. package/lib/helpers/schema/getPath.js +43 -0
  168. package/lib/helpers/schema/getSubdocumentStrictValue.js +32 -0
  169. package/lib/helpers/schema/handleIdOption.js +20 -0
  170. package/lib/helpers/schema/handleTimestampOption.js +24 -0
  171. package/lib/helpers/schema/idGetter.js +34 -0
  172. package/lib/helpers/schema/merge.js +36 -0
  173. package/lib/helpers/schematype/handleImmutable.js +50 -0
  174. package/lib/helpers/setDefaultsOnInsert.js +158 -0
  175. package/lib/helpers/specialProperties.js +3 -0
  176. package/lib/helpers/symbols.js +20 -0
  177. package/lib/helpers/timers.js +3 -0
  178. package/lib/helpers/timestamps/setDocumentTimestamps.js +26 -0
  179. package/lib/helpers/timestamps/setupTimestamps.js +116 -0
  180. package/lib/helpers/topology/allServersUnknown.js +12 -0
  181. package/lib/helpers/topology/isAtlas.js +31 -0
  182. package/lib/helpers/topology/isSSLError.js +16 -0
  183. package/lib/helpers/update/applyTimestampsToChildren.js +193 -0
  184. package/lib/helpers/update/applyTimestampsToUpdate.js +131 -0
  185. package/lib/helpers/update/castArrayFilters.js +113 -0
  186. package/lib/helpers/update/decorateUpdateWithVersionKey.js +35 -0
  187. package/lib/helpers/update/modifiedPaths.js +33 -0
  188. package/lib/helpers/update/moveImmutableProperties.js +53 -0
  189. package/lib/helpers/update/removeUnusedArrayFilters.js +32 -0
  190. package/lib/helpers/update/updatedPathsByArrayFilter.js +27 -0
  191. package/lib/helpers/updateValidators.js +193 -0
  192. package/lib/index.js +17 -0
  193. package/lib/internal.js +46 -0
  194. package/lib/model.js +5010 -0
  195. package/lib/modifiedPathsSnapshot.js +9 -0
  196. package/lib/mongoose.js +1411 -0
  197. package/lib/options/populateOptions.js +36 -0
  198. package/lib/options/propertyOptions.js +8 -0
  199. package/lib/options/saveOptions.js +16 -0
  200. package/lib/options/schemaArrayOptions.js +78 -0
  201. package/lib/options/schemaBufferOptions.js +38 -0
  202. package/lib/options/schemaDateOptions.js +71 -0
  203. package/lib/options/schemaDocumentArrayOptions.js +68 -0
  204. package/lib/options/schemaMapOptions.js +43 -0
  205. package/lib/options/schemaNumberOptions.js +101 -0
  206. package/lib/options/schemaObjectIdOptions.js +64 -0
  207. package/lib/options/schemaStringOptions.js +138 -0
  208. package/lib/options/schemaSubdocumentOptions.js +66 -0
  209. package/lib/options/schemaTypeOptions.js +244 -0
  210. package/lib/options/schemaUnionOptions.js +32 -0
  211. package/lib/options/virtualOptions.js +164 -0
  212. package/lib/options.js +17 -0
  213. package/lib/plugins/index.js +6 -0
  214. package/lib/plugins/saveSubdocs.js +76 -0
  215. package/lib/plugins/sharding.js +84 -0
  216. package/lib/plugins/trackTransaction.js +84 -0
  217. package/lib/plugins/validateBeforeSave.js +41 -0
  218. package/lib/query.js +5673 -0
  219. package/lib/queryHelpers.js +387 -0
  220. package/lib/schema/array.js +699 -0
  221. package/lib/schema/bigint.js +282 -0
  222. package/lib/schema/boolean.js +332 -0
  223. package/lib/schema/buffer.js +343 -0
  224. package/lib/schema/date.js +467 -0
  225. package/lib/schema/decimal128.js +263 -0
  226. package/lib/schema/documentArray.js +656 -0
  227. package/lib/schema/documentArrayElement.js +137 -0
  228. package/lib/schema/double.js +246 -0
  229. package/lib/schema/index.js +32 -0
  230. package/lib/schema/int32.js +289 -0
  231. package/lib/schema/map.js +201 -0
  232. package/lib/schema/mixed.js +146 -0
  233. package/lib/schema/number.js +510 -0
  234. package/lib/schema/objectId.js +333 -0
  235. package/lib/schema/operators/bitwise.js +38 -0
  236. package/lib/schema/operators/exists.js +12 -0
  237. package/lib/schema/operators/geospatial.js +107 -0
  238. package/lib/schema/operators/helpers.js +32 -0
  239. package/lib/schema/operators/text.js +39 -0
  240. package/lib/schema/operators/type.js +20 -0
  241. package/lib/schema/string.js +733 -0
  242. package/lib/schema/subdocument.js +436 -0
  243. package/lib/schema/symbols.js +5 -0
  244. package/lib/schema/union.js +113 -0
  245. package/lib/schema/uuid.js +305 -0
  246. package/lib/schema.js +3226 -0
  247. package/lib/schemaType.js +1835 -0
  248. package/lib/stateMachine.js +232 -0
  249. package/lib/types/array/index.js +119 -0
  250. package/lib/types/array/isMongooseArray.js +5 -0
  251. package/lib/types/array/methods/index.js +1095 -0
  252. package/lib/types/arraySubdocument.js +207 -0
  253. package/lib/types/buffer.js +294 -0
  254. package/lib/types/decimal128.js +13 -0
  255. package/lib/types/documentArray/index.js +113 -0
  256. package/lib/types/documentArray/isMongooseDocumentArray.js +5 -0
  257. package/lib/types/documentArray/methods/index.js +415 -0
  258. package/lib/types/double.js +13 -0
  259. package/lib/types/index.js +23 -0
  260. package/lib/types/map.js +419 -0
  261. package/lib/types/objectid.js +41 -0
  262. package/lib/types/subdocument.js +464 -0
  263. package/lib/types/uuid.js +13 -0
  264. package/lib/utils.js +1054 -0
  265. package/lib/validOptions.js +42 -0
  266. package/lib/virtualType.js +204 -0
  267. package/package.json +148 -0
  268. package/types/aggregate.d.ts +180 -0
  269. package/types/augmentations.d.ts +9 -0
  270. package/types/callback.d.ts +8 -0
  271. package/types/collection.d.ts +49 -0
  272. package/types/connection.d.ts +297 -0
  273. package/types/cursor.d.ts +67 -0
  274. package/types/document.d.ts +374 -0
  275. package/types/error.d.ts +143 -0
  276. package/types/expressions.d.ts +3053 -0
  277. package/types/helpers.d.ts +32 -0
  278. package/types/index.d.ts +1056 -0
  279. package/types/indexes.d.ts +97 -0
  280. package/types/inferhydrateddoctype.d.ts +115 -0
  281. package/types/inferrawdoctype.d.ts +135 -0
  282. package/types/inferschematype.d.ts +337 -0
  283. package/types/middlewares.d.ts +59 -0
  284. package/types/models.d.ts +1306 -0
  285. package/types/mongooseoptions.d.ts +228 -0
  286. package/types/pipelinestage.d.ts +333 -0
  287. package/types/populate.d.ts +53 -0
  288. package/types/query.d.ts +934 -0
  289. package/types/schemaoptions.d.ts +282 -0
  290. package/types/schematypes.d.ts +654 -0
  291. package/types/session.d.ts +32 -0
  292. package/types/types.d.ts +109 -0
  293. package/types/utility.d.ts +175 -0
  294. package/types/validation.d.ts +39 -0
  295. package/types/virtuals.d.ts +14 -0
@@ -0,0 +1,776 @@
1
+ 'use strict';
2
+
3
+ const MongooseError = require('../../error/index');
4
+ const SkipPopulateValue = require('./skipPopulateValue');
5
+ const clone = require('../clone');
6
+ const get = require('../get');
7
+ const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
8
+ const getConstructorName = require('../getConstructorName');
9
+ const getSchemaTypes = require('./getSchemaTypes');
10
+ const getVirtual = require('./getVirtual');
11
+ const lookupLocalFields = require('./lookupLocalFields');
12
+ const mpath = require('mpath');
13
+ const modelNamesFromRefPath = require('./modelNamesFromRefPath');
14
+ const utils = require('../../utils');
15
+
16
+ const modelSymbol = require('../symbols').modelSymbol;
17
+ const populateModelSymbol = require('../symbols').populateModelSymbol;
18
+ const schemaMixedSymbol = require('../../schema/symbols').schemaMixedSymbol;
19
+ const StrictPopulate = require('../../error/strictPopulate');
20
+
21
+ module.exports = function getModelsMapForPopulate(model, docs, options) {
22
+ let doc;
23
+ const len = docs.length;
24
+ const map = [];
25
+ const modelNameFromQuery = options.model?.modelName || options.model;
26
+ let schema;
27
+ let refPath;
28
+ let modelNames;
29
+ let modelNamesSet;
30
+ const available = {};
31
+
32
+ const modelSchema = model.schema;
33
+
34
+ // Populating a nested path should always be a no-op re: #9073.
35
+ // People shouldn't do this, but apparently they do.
36
+ if (options._localModel != null && options._localModel.schema.nested[options.path]) {
37
+ return [];
38
+ }
39
+
40
+ const _virtualRes = getVirtual(model.schema, options.path);
41
+ const virtual = _virtualRes == null ? null : _virtualRes.virtual;
42
+ if (virtual != null) {
43
+ return _virtualPopulate(model, docs, options, _virtualRes);
44
+ }
45
+
46
+ let allSchemaTypes = getSchemaTypes(model, modelSchema, null, options.path);
47
+ allSchemaTypes = Array.isArray(allSchemaTypes) ? allSchemaTypes : [allSchemaTypes].filter(v => v != null);
48
+
49
+ const isStrictPopulateDisabled = options.strictPopulate === false || options.options?.strictPopulate === false;
50
+ if (!isStrictPopulateDisabled && allSchemaTypes.length === 0 && options._localModel != null) {
51
+ return new StrictPopulate(options._fullPath || options.path);
52
+ }
53
+
54
+ for (let i = 0; i < len; i++) {
55
+ doc = docs[i];
56
+ let justOne = null;
57
+
58
+ if (doc.$__ != null && doc.populated(options.path)) {
59
+ const forceRepopulate = options.forceRepopulate ?? doc.constructor.base.options.forceRepopulate;
60
+ if (forceRepopulate === false) {
61
+ continue;
62
+ }
63
+ }
64
+
65
+ const docSchema = doc?.$__ != null ? doc.$__schema : modelSchema;
66
+ schema = getSchemaTypes(model, docSchema, doc, options.path);
67
+
68
+ // Special case: populating a path that's a DocumentArray unless
69
+ // there's an explicit `ref` or `refPath` re: gh-8946
70
+ if (schema != null &&
71
+ schema.$isMongooseDocumentArray &&
72
+ schema.options.ref == null &&
73
+ schema.options.refPath == null) {
74
+ continue;
75
+ }
76
+ const isUnderneathDocArray = schema?.$parentSchemaDocArray;
77
+ if (isUnderneathDocArray && get(options, 'options.sort') != null) {
78
+ return new MongooseError('Cannot populate with `sort` on path ' + options.path +
79
+ ' because it is a subproperty of a document array');
80
+ }
81
+
82
+ modelNames = null;
83
+ let isRefPath = false;
84
+ let normalizedRefPath = null;
85
+ let schemaOptions = null;
86
+ let modelNamesInOrder = null;
87
+
88
+ if (schema?.instance === 'Embedded') {
89
+ if (schema.options.ref) {
90
+ const data = {
91
+ localField: options.path + '._id',
92
+ foreignField: '_id',
93
+ justOne: true
94
+ };
95
+ const res = _getModelNames(doc, schema, modelNameFromQuery, model);
96
+
97
+ const unpopulatedValue = mpath.get(options.path, doc);
98
+ const id = mpath.get('_id', unpopulatedValue);
99
+ addModelNamesToMap(model, map, available, res.modelNames, options, data, id, doc, schemaOptions, unpopulatedValue);
100
+ }
101
+ // No-op if no `ref` set. See gh-11538
102
+ continue;
103
+ }
104
+
105
+ if (Array.isArray(schema)) {
106
+ const schemasArray = schema;
107
+ for (const _schema of schemasArray) {
108
+ let _modelNames;
109
+ let res;
110
+ try {
111
+ res = _getModelNames(doc, _schema, modelNameFromQuery, model);
112
+ _modelNames = res.modelNames;
113
+ isRefPath = isRefPath || res.isRefPath;
114
+ normalizedRefPath = normalizedRefPath || res.refPath;
115
+ justOne = res.justOne;
116
+ } catch (error) {
117
+ return error;
118
+ }
119
+
120
+ if (isRefPath && !res.isRefPath) {
121
+ continue;
122
+ }
123
+ if (!_modelNames) {
124
+ continue;
125
+ }
126
+ modelNames = modelNames || [];
127
+ modelNamesSet = modelNamesSet || new Set();
128
+ for (const modelName of _modelNames) {
129
+ if (modelNamesSet.has(modelName) === false) {
130
+ modelNamesSet.add(modelName);
131
+ modelNames.push(modelName);
132
+ }
133
+ }
134
+ }
135
+ } else {
136
+ try {
137
+ const res = _getModelNames(doc, schema, modelNameFromQuery, model);
138
+ modelNames = res.modelNames;
139
+ isRefPath = res.isRefPath;
140
+ normalizedRefPath = normalizedRefPath || res.refPath;
141
+ justOne = res.justOne;
142
+ schemaOptions = get(schema, 'options.populate', null);
143
+ // Dedupe, because `refPath` can return duplicates of the same model name,
144
+ // and that causes perf issues.
145
+ if (isRefPath) {
146
+ modelNamesInOrder = modelNames;
147
+ modelNames = Array.from(new Set(modelNames));
148
+ }
149
+ } catch (error) {
150
+ return error;
151
+ }
152
+
153
+ if (!modelNames) {
154
+ continue;
155
+ }
156
+ }
157
+
158
+ const data = {};
159
+ const localField = options.path;
160
+ const foreignField = '_id';
161
+
162
+ // `justOne = null` means we don't know from the schema whether the end
163
+ // result should be an array or a single doc. This can result from
164
+ // populating a POJO using `Model.populate()`
165
+ if ('justOne' in options && options.justOne !== void 0) {
166
+ justOne = options.justOne;
167
+ } else if (schema && !schema[schemaMixedSymbol]) {
168
+ // Skip Mixed types because we explicitly don't do casting on those.
169
+ if (options.path.endsWith('.' + schema.path) || options.path === schema.path) {
170
+ justOne = Array.isArray(schema) ?
171
+ schema.every(schema => !schema.$isMongooseArray) :
172
+ !schema.$isMongooseArray;
173
+ }
174
+ }
175
+
176
+ if (!modelNames) {
177
+ continue;
178
+ }
179
+
180
+ data.isVirtual = false;
181
+ data.justOne = justOne;
182
+ data.localField = localField;
183
+ data.foreignField = foreignField;
184
+
185
+ // Get local fields
186
+ const ret = _getLocalFieldValues(doc, localField, model, options, null, schema);
187
+
188
+ const id = String(utils.getValue(foreignField, doc));
189
+ options._docs[id] = Array.isArray(ret) ? ret.slice() : ret;
190
+
191
+ let match = get(options, 'match', null);
192
+
193
+ const hasMatchFunction = typeof match === 'function';
194
+ if (hasMatchFunction) {
195
+ match = match.call(doc, doc);
196
+ }
197
+ throwOn$where(match);
198
+ data.match = match;
199
+ data.hasMatchFunction = hasMatchFunction;
200
+ data.isRefPath = isRefPath;
201
+ data.modelNamesInOrder = modelNamesInOrder;
202
+
203
+ if (isRefPath) {
204
+ const embeddedDiscriminatorModelNames = _findRefPathForDiscriminators(doc,
205
+ modelSchema, data, options, normalizedRefPath, ret);
206
+
207
+ modelNames = embeddedDiscriminatorModelNames || modelNames;
208
+ }
209
+
210
+ try {
211
+ addModelNamesToMap(model, map, available, modelNames, options, data, ret, doc, schemaOptions);
212
+ } catch (err) {
213
+ return err;
214
+ }
215
+ }
216
+ return map;
217
+
218
+ function _getModelNames(doc, schema, modelNameFromQuery, model) {
219
+ let modelNames;
220
+ let isRefPath = false;
221
+ let justOne = null;
222
+
223
+ const originalSchema = schema;
224
+ if (schema?.instance === 'Array') {
225
+ schema = schema.embeddedSchemaType;
226
+ }
227
+ if (schema?.$isSchemaMap) {
228
+ schema = schema.$__schemaType;
229
+ }
230
+
231
+ const ref = schema?.options?.ref;
232
+ refPath = schema?.options?.refPath;
233
+ if (schema != null &&
234
+ schema[schemaMixedSymbol] &&
235
+ !ref &&
236
+ !refPath &&
237
+ !modelNameFromQuery) {
238
+ return { modelNames: null };
239
+ }
240
+
241
+ if (modelNameFromQuery) {
242
+ modelNames = [modelNameFromQuery]; // query options
243
+ } else if (refPath != null) {
244
+ if (typeof refPath === 'function') {
245
+ const subdocPath = options.path.slice(0, options.path.length - schema.path.length - 1);
246
+ const vals = mpath.get(subdocPath, doc, lookupLocalFields);
247
+ const subdocsBeingPopulated = Array.isArray(vals) ?
248
+ utils.array.flatten(vals) :
249
+ (vals ? [vals] : []);
250
+
251
+ modelNames = new Set();
252
+ for (const subdoc of subdocsBeingPopulated) {
253
+ refPath = refPath.call(subdoc, subdoc, options.path);
254
+ modelNamesFromRefPath(refPath, doc, options.path, modelSchema, options._queryProjection).
255
+ forEach(name => modelNames.add(name));
256
+ }
257
+ modelNames = Array.from(modelNames);
258
+ } else {
259
+ modelNames = modelNamesFromRefPath(refPath, doc, options.path, modelSchema, options._queryProjection);
260
+ }
261
+
262
+ isRefPath = true;
263
+ } else {
264
+ let ref;
265
+ let refPath;
266
+ let schemaForCurrentDoc;
267
+ let discriminatorValue;
268
+ let modelForCurrentDoc = model;
269
+ const discriminatorKey = model.schema.options.discriminatorKey;
270
+
271
+ if (!schema && discriminatorKey && (discriminatorValue = utils.getValue(discriminatorKey, doc))) {
272
+ // `modelNameForFind` is the discriminator value, so we might need
273
+ // find the discriminated model name
274
+ const discriminatorModel = getDiscriminatorByValue(model.discriminators, discriminatorValue) || model;
275
+ if (discriminatorModel != null) {
276
+ modelForCurrentDoc = discriminatorModel;
277
+ } else {
278
+ try {
279
+ modelForCurrentDoc = _getModelFromConn(model.db, discriminatorValue);
280
+ } catch (error) {
281
+ return error;
282
+ }
283
+ }
284
+
285
+ schemaForCurrentDoc = modelForCurrentDoc.schema._getSchema(options.path);
286
+
287
+ if (schemaForCurrentDoc?.embeddedSchemaType) {
288
+ schemaForCurrentDoc = schemaForCurrentDoc.embeddedSchemaType;
289
+ }
290
+ } else {
291
+ schemaForCurrentDoc = schema;
292
+ }
293
+
294
+ if (originalSchema && originalSchema.path.endsWith('.$*')) {
295
+ justOne = !originalSchema.$isMongooseArray && !originalSchema._arrayPath;
296
+ } else if (schemaForCurrentDoc != null) {
297
+ justOne = !schemaForCurrentDoc.$isMongooseArray && !schemaForCurrentDoc._arrayPath;
298
+ }
299
+
300
+ if ((ref = get(schemaForCurrentDoc, 'options.ref')) != null) {
301
+ if (schemaForCurrentDoc != null &&
302
+ typeof ref === 'function' &&
303
+ options.path.endsWith('.' + schemaForCurrentDoc.path)) {
304
+ // Ensure correct context for ref functions: subdoc, not top-level doc. See gh-8469
305
+ modelNames = new Set();
306
+
307
+ const subdocPath = options.path.slice(0, options.path.length - schemaForCurrentDoc.path.length - 1);
308
+ const vals = mpath.get(subdocPath, doc, lookupLocalFields);
309
+ const subdocsBeingPopulated = Array.isArray(vals) ?
310
+ utils.array.flatten(vals) :
311
+ (vals ? [vals] : []);
312
+ for (const subdoc of subdocsBeingPopulated) {
313
+ modelNames.add(handleRefFunction(ref, subdoc));
314
+ }
315
+
316
+ if (subdocsBeingPopulated.length === 0) {
317
+ modelNames = [handleRefFunction(ref, doc)];
318
+ } else {
319
+ modelNames = Array.from(modelNames);
320
+ }
321
+ } else {
322
+ ref = handleRefFunction(ref, doc);
323
+ modelNames = [ref];
324
+ }
325
+ } else if ((schemaForCurrentDoc = get(schema, 'options.refPath')) != null) {
326
+ isRefPath = true;
327
+ if (typeof refPath === 'function') {
328
+ const subdocPath = options.path.slice(0, options.path.length - schemaForCurrentDoc.path.length - 1);
329
+ const vals = mpath.get(subdocPath, doc, lookupLocalFields);
330
+ const subdocsBeingPopulated = Array.isArray(vals) ?
331
+ utils.array.flatten(vals) :
332
+ (vals ? [vals] : []);
333
+
334
+ modelNames = new Set();
335
+ for (const subdoc of subdocsBeingPopulated) {
336
+ refPath = refPath.call(subdoc, subdoc, options.path);
337
+ modelNamesFromRefPath(refPath, doc, options.path, modelSchema, options._queryProjection).
338
+ forEach(name => modelNames.add(name));
339
+ }
340
+ modelNames = Array.from(modelNames);
341
+ } else {
342
+ modelNames = modelNamesFromRefPath(refPath, doc, options.path, modelSchema, options._queryProjection);
343
+ }
344
+ }
345
+ }
346
+
347
+ if (!modelNames) {
348
+ // `Model.populate()` on a POJO with no known local model. Default to using the `Model`
349
+ if (options._localModel == null) {
350
+ modelNames = [model.modelName];
351
+ } else {
352
+ return { modelNames: modelNames, justOne: justOne, isRefPath: isRefPath, refPath: refPath };
353
+ }
354
+ }
355
+
356
+ if (!Array.isArray(modelNames)) {
357
+ modelNames = [modelNames];
358
+ }
359
+
360
+ return { modelNames: modelNames, justOne: justOne, isRefPath: isRefPath, refPath: refPath };
361
+ }
362
+ };
363
+
364
+ /*!
365
+ * ignore
366
+ */
367
+
368
+ function _virtualPopulate(model, docs, options, _virtualRes) {
369
+ const map = [];
370
+ const available = {};
371
+ const virtual = _virtualRes.virtual;
372
+
373
+ for (const doc of docs) {
374
+ let modelNames = null;
375
+ const data = {};
376
+
377
+ // localField and foreignField
378
+ let localField;
379
+ const virtualPrefix = _virtualRes.nestedSchemaPath ?
380
+ _virtualRes.nestedSchemaPath + '.' : '';
381
+ if (typeof options.localField === 'string') {
382
+ localField = options.localField;
383
+ } else if (typeof virtual.options.localField === 'function') {
384
+ localField = virtualPrefix + virtual.options.localField.call(doc, doc);
385
+ } else if (Array.isArray(virtual.options.localField)) {
386
+ localField = virtual.options.localField.map(field => virtualPrefix + field);
387
+ } else {
388
+ localField = virtualPrefix + virtual.options.localField;
389
+ }
390
+ data.count = virtual.options.count;
391
+
392
+ if (virtual.options.skip != null && !Object.hasOwn(options, 'skip')) {
393
+ options.skip = virtual.options.skip;
394
+ }
395
+ if (virtual.options.limit != null && !Object.hasOwn(options, 'limit')) {
396
+ options.limit = virtual.options.limit;
397
+ }
398
+ if (virtual.options.perDocumentLimit != null && !Object.hasOwn(options, 'perDocumentLimit')) {
399
+ options.perDocumentLimit = virtual.options.perDocumentLimit;
400
+ }
401
+ let foreignField = virtual.options.foreignField;
402
+
403
+ if (!localField || !foreignField) {
404
+ return new MongooseError(`Cannot populate virtual \`${options.path}\` on model \`${model.modelName}\`, because options \`localField\` and / or \`foreignField\` are missing`);
405
+ }
406
+
407
+ if (typeof localField === 'function') {
408
+ localField = localField.call(doc, doc);
409
+ }
410
+ if (typeof foreignField === 'function') {
411
+ foreignField = foreignField.call(doc, doc);
412
+ }
413
+
414
+ data.isRefPath = false;
415
+
416
+ // `justOne = null` means we don't know from the schema whether the end
417
+ // result should be an array or a single doc. This can result from
418
+ // populating a POJO using `Model.populate()`
419
+ let justOne = null;
420
+ if ('justOne' in options && options.justOne !== void 0) {
421
+ justOne = options.justOne;
422
+ }
423
+
424
+ // Use the correct target doc/sub-doc for dynamic ref on nested schema. See gh-12363
425
+ if (_virtualRes.nestedSchemaPath && typeof virtual.options.ref === 'function') {
426
+ const subdocs = utils.getValue(_virtualRes.nestedSchemaPath, doc);
427
+ modelNames = Array.isArray(subdocs)
428
+ ? subdocs.flatMap(subdoc => virtual._getModelNamesForPopulate(subdoc))
429
+ : virtual._getModelNamesForPopulate(subdocs);
430
+ } else {
431
+ modelNames = virtual._getModelNamesForPopulate(doc);
432
+ }
433
+ if (virtual.options.refPath) {
434
+ justOne = !!virtual.options.justOne;
435
+ data.isRefPath = true;
436
+ } else if (virtual.options.ref) {
437
+ justOne = !!virtual.options.justOne;
438
+ }
439
+
440
+ data.isVirtual = true;
441
+ data.virtual = virtual;
442
+ data.justOne = justOne;
443
+
444
+ // `match`
445
+ const baseMatch = get(data, 'virtual.options.match', null) ||
446
+ get(data, 'virtual.options.options.match', null);
447
+ let match = get(options, 'match', null) || baseMatch;
448
+
449
+ let hasMatchFunction = typeof match === 'function';
450
+ if (hasMatchFunction) {
451
+ match = match.call(doc, doc, data.virtual);
452
+ }
453
+
454
+ if (Array.isArray(localField) && Array.isArray(foreignField) && localField.length === foreignField.length) {
455
+ match = Object.assign({}, match);
456
+ for (let i = 1; i < localField.length; ++i) {
457
+ match[foreignField[i]] = convertTo_id(mpath.get(localField[i], doc, lookupLocalFields), model.schema);
458
+ hasMatchFunction = true;
459
+ }
460
+
461
+ localField = localField[0];
462
+ foreignField = foreignField[0];
463
+ }
464
+ data.localField = localField;
465
+ data.foreignField = foreignField;
466
+ data.match = match;
467
+ data.hasMatchFunction = hasMatchFunction;
468
+
469
+ throwOn$where(match);
470
+
471
+ // Get local fields
472
+ const ret = _getLocalFieldValues(doc, localField, model, options, virtual);
473
+
474
+ try {
475
+ addModelNamesToMap(model, map, available, modelNames, options, data, ret, doc);
476
+ } catch (err) {
477
+ return err;
478
+ }
479
+ }
480
+
481
+ return map;
482
+ }
483
+
484
+ /*!
485
+ * ignore
486
+ */
487
+
488
+ function addModelNamesToMap(model, map, available, modelNames, options, data, ret, doc, schemaOptions, unpopulatedValue) {
489
+ // `PopulateOptions#connection`: if the model is passed as a string, the
490
+ // connection matters because different connections have different models.
491
+ const connection = options.connection ?? model.db;
492
+
493
+ unpopulatedValue = unpopulatedValue === void 0 ? ret : unpopulatedValue;
494
+ if (Array.isArray(unpopulatedValue)) {
495
+ unpopulatedValue = utils.cloneArrays(unpopulatedValue);
496
+ }
497
+
498
+ if (modelNames == null) {
499
+ return;
500
+ }
501
+
502
+ const flatModelNames = utils.array.flatten(modelNames);
503
+ let k = flatModelNames.length;
504
+ while (k--) {
505
+ let modelName = flatModelNames[k];
506
+ if (modelName == null) {
507
+ continue;
508
+ }
509
+
510
+ let Model;
511
+ if (options.model && options.model[modelSymbol]) {
512
+ Model = options.model;
513
+ } else if (modelName[modelSymbol]) {
514
+ Model = modelName;
515
+ modelName = Model.modelName;
516
+ } else {
517
+ try {
518
+ Model = _getModelFromConn(connection, modelName);
519
+ } catch (err) {
520
+ if (ret !== void 0) {
521
+ throw err;
522
+ }
523
+ Model = null;
524
+ }
525
+ }
526
+
527
+ let ids = ret;
528
+
529
+ const modelNamesForRefPath = data.modelNamesInOrder || modelNames;
530
+ if (data.isRefPath && Array.isArray(ret) && ret.length === modelNamesForRefPath.length) {
531
+ ids = matchIdsToRefPaths(ret, modelNamesForRefPath, modelName);
532
+ }
533
+
534
+ const perDocumentLimit = options.perDocumentLimit == null ?
535
+ get(options, 'options.perDocumentLimit', null) :
536
+ options.perDocumentLimit;
537
+
538
+ if (!available[modelName] || perDocumentLimit != null) {
539
+ const currentOptions = {
540
+ model: Model
541
+ };
542
+ if (data.isVirtual && get(data.virtual, 'options.options')) {
543
+ currentOptions.options = clone(data.virtual.options.options);
544
+ } else if (schemaOptions != null) {
545
+ currentOptions.options = Object.assign({}, schemaOptions);
546
+ }
547
+ utils.merge(currentOptions, options);
548
+
549
+ // Used internally for checking what model was used to populate this
550
+ // path.
551
+ options[populateModelSymbol] = Model;
552
+ currentOptions[populateModelSymbol] = Model;
553
+ available[modelName] = {
554
+ model: Model,
555
+ options: currentOptions,
556
+ match: data.hasMatchFunction ? [data.match] : data.match,
557
+ docs: [doc],
558
+ ids: [ids],
559
+ allIds: [ret],
560
+ unpopulatedValues: [unpopulatedValue],
561
+ localField: new Set([data.localField]),
562
+ foreignField: new Set([data.foreignField]),
563
+ justOne: data.justOne,
564
+ isVirtual: data.isVirtual,
565
+ virtual: data.virtual,
566
+ count: data.count,
567
+ [populateModelSymbol]: Model
568
+ };
569
+ map.push(available[modelName]);
570
+ } else {
571
+ available[modelName].localField.add(data.localField);
572
+ available[modelName].foreignField.add(data.foreignField);
573
+ available[modelName].docs.push(doc);
574
+ available[modelName].ids.push(ids);
575
+ available[modelName].allIds.push(ret);
576
+ available[modelName].unpopulatedValues.push(unpopulatedValue);
577
+ if (data.hasMatchFunction) {
578
+ available[modelName].match.push(data.match);
579
+ }
580
+ }
581
+ }
582
+ }
583
+
584
+ function _getModelFromConn(conn, modelName) {
585
+ /* If this connection has a parent from `useDb()`, bubble up to parent's models */
586
+ if (conn.models[modelName] == null && conn._parent != null) {
587
+ return _getModelFromConn(conn._parent, modelName);
588
+ }
589
+
590
+ return conn.model(modelName);
591
+ }
592
+
593
+ function matchIdsToRefPaths(ids, refPaths, refPathToFind) {
594
+ if (!Array.isArray(refPaths)) {
595
+ return refPaths === refPathToFind
596
+ ? Array.isArray(ids)
597
+ ? utils.array.flatten(ids)
598
+ : [ids]
599
+ : [];
600
+ }
601
+ if (Array.isArray(ids) && Array.isArray(refPaths)) {
602
+ return ids.flatMap((id, index) => matchIdsToRefPaths(id, refPaths[index], refPathToFind));
603
+ }
604
+ return [];
605
+ }
606
+
607
+ /*!
608
+ * ignore
609
+ */
610
+
611
+ function handleRefFunction(ref, doc) {
612
+ if (typeof ref === 'function' && !ref[modelSymbol]) {
613
+ return ref.call(doc, doc);
614
+ }
615
+ return ref;
616
+ }
617
+
618
+ /*!
619
+ * ignore
620
+ */
621
+
622
+ function _getLocalFieldValues(doc, localField, model, options, virtual, schema) {
623
+ // Get Local fields
624
+ const localFieldPathType = model.schema._getPathType(localField);
625
+ const localFieldPath = localFieldPathType === 'real' ?
626
+ model.schema.path(localField) :
627
+ localFieldPathType.schema;
628
+ const localFieldGetters = localFieldPath?.getters || [];
629
+
630
+ localField = localFieldPath?.instance === 'Embedded' ? localField + '._id' : localField;
631
+
632
+ const _populateOptions = get(options, 'options', {});
633
+
634
+ const getters = 'getters' in _populateOptions ?
635
+ _populateOptions.getters :
636
+ get(virtual, 'options.getters', false);
637
+ if (localFieldGetters.length !== 0 && getters) {
638
+ const hydratedDoc = (doc.$__ != null) ? doc : model.hydrate(doc);
639
+ const localFieldValue = utils.getValue(localField, doc);
640
+ if (Array.isArray(localFieldValue)) {
641
+ const localFieldHydratedValue = utils.getValue(localField.split('.').slice(0, -1), hydratedDoc);
642
+ return localFieldValue.map((localFieldArrVal, localFieldArrIndex) =>
643
+ localFieldPath.applyGetters(localFieldArrVal, localFieldHydratedValue[localFieldArrIndex]));
644
+ } else {
645
+ return localFieldPath.applyGetters(localFieldValue, hydratedDoc);
646
+ }
647
+ } else {
648
+ return convertTo_id(mpath.get(localField, doc, lookupLocalFields), schema);
649
+ }
650
+ }
651
+
652
+ /**
653
+ * Retrieve the _id of `val` if a Document or Array of Documents.
654
+ *
655
+ * @param {Array|Document|Any} val
656
+ * @param {Schema} schema
657
+ * @return {Array|Document|Any}
658
+ * @api private
659
+ */
660
+
661
+ function convertTo_id(val, schema) {
662
+ if (val?.$__ != null) {
663
+ return val._doc._id;
664
+ }
665
+ if (val?._id != null && !schema?.$isSchemaMap) {
666
+ return val._id;
667
+ }
668
+
669
+ if (Array.isArray(val)) {
670
+ const rawVal = val.__array ?? val;
671
+ for (let i = 0; i < rawVal.length; ++i) {
672
+ if (rawVal[i]?.$__ != null) {
673
+ rawVal[i] = rawVal[i]._doc._id;
674
+ }
675
+ }
676
+ if (utils.isMongooseArray(val) && val.$schema()) {
677
+ return val.$schema()._castForPopulate(val, val.$parent());
678
+ }
679
+
680
+ return [].concat(val);
681
+ }
682
+
683
+ // `populate('map')` may be an object if populating on a doc that hasn't
684
+ // been hydrated yet
685
+ if (getConstructorName(val) === 'Object' &&
686
+ // The intent here is we should only flatten the object if we expect
687
+ // to get a Map in the end. Avoid doing this for mixed types.
688
+ schema?.[schemaMixedSymbol] == null) {
689
+ const ret = [];
690
+ for (const key of Object.keys(val)) {
691
+ ret.push(val[key]);
692
+ }
693
+ return ret;
694
+ }
695
+ // If doc has already been hydrated, e.g. `doc.populate('map')`
696
+ // then `val` will already be a map
697
+ if (val instanceof Map) {
698
+ return Array.from(val.values());
699
+ }
700
+
701
+ return val;
702
+ }
703
+
704
+ /*!
705
+ * ignore
706
+ */
707
+
708
+ function _findRefPathForDiscriminators(doc, modelSchema, data, options, normalizedRefPath, ret) {
709
+ // Re: gh-8452. Embedded discriminators may not have `refPath`, so clear
710
+ // out embedded discriminator docs that don't have a `refPath` on the
711
+ // populated path.
712
+ if (!data.isRefPath || normalizedRefPath == null) {
713
+ return;
714
+ }
715
+
716
+ const pieces = normalizedRefPath.split('.');
717
+ let cur = '';
718
+ let modelNames = void 0;
719
+ for (let i = 0; i < pieces.length; ++i) {
720
+ const piece = pieces[i];
721
+ cur = cur + (cur.length === 0 ? '' : '.') + piece;
722
+ const schematype = modelSchema.path(cur);
723
+ if (schematype != null &&
724
+ schematype.$isMongooseDocumentArray &&
725
+ schematype.Constructor.discriminators != null &&
726
+ utils.hasOwnKeys(schematype.Constructor.discriminators)) {
727
+ const subdocs = utils.getValue(cur, doc);
728
+ const remnant = options.path.substring(cur.length + 1);
729
+ const discriminatorKey = schematype.Constructor.schema.options.discriminatorKey;
730
+ modelNames = [];
731
+ for (const subdoc of subdocs) {
732
+ const discriminatorName = utils.getValue(discriminatorKey, subdoc);
733
+ const discriminator = schematype.Constructor.discriminators[discriminatorName];
734
+ const discriminatorSchema = discriminator?.schema;
735
+ if (discriminatorSchema == null) {
736
+ continue;
737
+ }
738
+ const _path = discriminatorSchema.path(remnant);
739
+ if (_path == null || _path.options.refPath == null) {
740
+ const docValue = utils.getValue(data.localField.substring(cur.length + 1), subdoc);
741
+ ret.forEach((v, i) => {
742
+ if (v === docValue) {
743
+ ret[i] = SkipPopulateValue(v);
744
+ }
745
+ });
746
+ continue;
747
+ }
748
+ const modelName = utils.getValue(pieces.slice(i + 1).join('.'), subdoc);
749
+ modelNames.push(modelName);
750
+ }
751
+ }
752
+ }
753
+
754
+ return modelNames;
755
+ }
756
+
757
+ /**
758
+ * Throw an error if there are any $where keys
759
+ */
760
+
761
+ function throwOn$where(match) {
762
+ if (match == null) {
763
+ return;
764
+ }
765
+ if (typeof match !== 'object') {
766
+ return;
767
+ }
768
+ for (const key of Object.keys(match)) {
769
+ if (key === '$where') {
770
+ throw new MongooseError('Cannot use $where filter with populate() match');
771
+ }
772
+ if (match[key] != null && typeof match[key] === 'object') {
773
+ throwOn$where(match[key]);
774
+ }
775
+ }
776
+ }