mongoose 7.4.4 → 7.5.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.
package/lib/document.js CHANGED
@@ -4091,6 +4091,14 @@ function applyGetters(self, json, options) {
4091
4091
  if (ii === last) {
4092
4092
  const val = self.$get(path);
4093
4093
  branch[part] = clone(val, options);
4094
+ if (Array.isArray(branch[part]) && schema.paths[path].$embeddedSchemaType) {
4095
+ for (let i = 0; i < branch[part].length; ++i) {
4096
+ branch[part][i] = schema.paths[path].$embeddedSchemaType.applyGetters(
4097
+ branch[part][i],
4098
+ self
4099
+ );
4100
+ }
4101
+ }
4094
4102
  } else if (v == null) {
4095
4103
  if (part in cur) {
4096
4104
  branch[part] = v;
@@ -9,6 +9,7 @@ const MongooseError = require('../../error/mongooseError');
9
9
  const Collection = require('mongodb').Collection;
10
10
  const ObjectId = require('../../types/objectid');
11
11
  const getConstructorName = require('../../helpers/getConstructorName');
12
+ const internalToObjectOptions = require('../../options').internalToObjectOptions;
12
13
  const stream = require('stream');
13
14
  const util = require('util');
14
15
 
@@ -377,7 +378,7 @@ function format(obj, sub, color, shell) {
377
378
  }
378
379
 
379
380
  const clone = require('../../helpers/clone');
380
- let x = clone(obj, { transform: false });
381
+ let x = clone(obj, internalToObjectOptions);
381
382
  const constructorName = getConstructorName(x);
382
383
 
383
384
  if (constructorName === 'Binary') {
@@ -14,6 +14,24 @@ const schemaMixedSymbol = require('../../schema/symbols').schemaMixedSymbol;
14
14
  const setDottedPath = require('../path/setDottedPath');
15
15
  const utils = require('../../utils');
16
16
 
17
+ const mongodbUpdateOperators = new Set([
18
+ '$currentDate',
19
+ '$inc',
20
+ '$min',
21
+ '$max',
22
+ '$mul',
23
+ '$rename',
24
+ '$set',
25
+ '$setOnInsert',
26
+ '$unset',
27
+ '$addToSet',
28
+ '$pop',
29
+ '$pull',
30
+ '$push',
31
+ '$pullAll',
32
+ '$bit'
33
+ ]);
34
+
17
35
  /**
18
36
  * Casts an update op based on the given schema
19
37
  *
@@ -58,7 +76,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
58
76
  while (i--) {
59
77
  const op = ops[i];
60
78
  // if overwrite is set, don't do any of the special $set stuff
61
- if (op[0] !== '$' && !overwrite) {
79
+ if (!mongodbUpdateOperators.has(op) && !overwrite) {
62
80
  // fix up $set sugar
63
81
  if (!ret.$set) {
64
82
  if (obj.$set) {
@@ -88,7 +106,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
88
106
  if (val &&
89
107
  typeof val === 'object' &&
90
108
  !Buffer.isBuffer(val) &&
91
- (!overwrite || hasDollarKey)) {
109
+ (!overwrite || mongodbUpdateOperators.has(op))) {
92
110
  walkUpdatePath(schema, val, op, options, context, filter);
93
111
  } else if (overwrite && ret && typeof ret === 'object') {
94
112
  walkUpdatePath(schema, ret, '$set', options, context, filter);
@@ -540,7 +558,7 @@ function castUpdateVal(schema, val, op, $conditional, context, path) {
540
558
  return Boolean(val);
541
559
  }
542
560
 
543
- if (/^\$/.test($conditional)) {
561
+ if (mongodbUpdateOperators.has($conditional)) {
544
562
  return schema.castForQuery(
545
563
  $conditional,
546
564
  val,
package/lib/model.js CHANGED
@@ -1481,9 +1481,7 @@ Model.syncIndexes = async function syncIndexes(options) {
1481
1481
  };
1482
1482
 
1483
1483
  /**
1484
- * Does a dry-run of Model.syncIndexes(), meaning that
1485
- * the result of this function would be the result of
1486
- * Model.syncIndexes().
1484
+ * Does a dry-run of `Model.syncIndexes()`, returning the indexes that `syncIndexes()` would drop and create if you were to run `syncIndexes()`.
1487
1485
  *
1488
1486
  * @param {Object} [options]
1489
1487
  * @returns {Promise} which contains an object, {toDrop, toCreate}, which
@@ -3498,6 +3496,10 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
3498
3496
  const validOpIndexes = validOps;
3499
3497
  validOps = validOps.sort().map(index => ops[index]);
3500
3498
 
3499
+ if (validOps.length === 0) {
3500
+ return resolve(getDefaultBulkwriteResult());
3501
+ }
3502
+
3501
3503
  this.$__collection.bulkWrite(validOps, options, (error, res) => {
3502
3504
  if (error) {
3503
3505
  if (validationErrors.length > 0) {
@@ -4081,13 +4083,13 @@ Model.aggregate = function aggregate(pipeline, options) {
4081
4083
  * }
4082
4084
  *
4083
4085
  * @param {Object} obj
4084
- * @param {Array|String} pathsToValidate
4086
+ * @param {Object|Array|String} pathsOrOptions
4085
4087
  * @param {Object} [context]
4086
4088
  * @return {Promise|undefined}
4087
4089
  * @api public
4088
4090
  */
4089
4091
 
4090
- Model.validate = async function validate(obj, pathsToValidate, context) {
4092
+ Model.validate = async function validate(obj, pathsOrOptions, context) {
4091
4093
  if ((arguments.length < 3) || (arguments.length === 3 && typeof arguments[2] === 'function')) {
4092
4094
  // For convenience, if we're validating a document or an object, make `context` default to
4093
4095
  // the model so users don't have to always pass `context`, re: gh-10132, gh-10346
@@ -4104,9 +4106,20 @@ Model.validate = async function validate(obj, pathsToValidate, context) {
4104
4106
  }
4105
4107
  let paths = Object.keys(schema.paths);
4106
4108
 
4107
- if (pathsToValidate != null) {
4108
- const _pathsToValidate = typeof pathsToValidate === 'string' ? new Set(pathsToValidate.split(' ')) : new Set(pathsToValidate);
4109
+ if (pathsOrOptions != null) {
4110
+ const _pathsToValidate = typeof pathsOrOptions === 'string' ? new Set(pathsOrOptions.split(' ')) : Array.isArray(pathsOrOptions) ? new Set(pathsOrOptions) : new Set(paths);
4109
4111
  paths = paths.filter(p => {
4112
+ if (pathsOrOptions.pathsToSkip) {
4113
+ if (Array.isArray(pathsOrOptions.pathsToSkip)) {
4114
+ if (pathsOrOptions.pathsToSkip.find(x => x == p)) {
4115
+ return false;
4116
+ }
4117
+ } else if (typeof pathsOrOptions.pathsToSkip == 'string') {
4118
+ if (pathsOrOptions.pathsToSkip.includes(p)) {
4119
+ return false;
4120
+ }
4121
+ }
4122
+ }
4110
4123
  const pieces = p.split('.');
4111
4124
  let cur = pieces[0];
4112
4125
 
package/lib/query.js CHANGED
@@ -1683,6 +1683,15 @@ const printRawResultDeprecationWarning = util.deprecate(
1683
1683
  'The `rawResult` option for Mongoose queries is deprecated. Use `includeResultMetadata: false` as a replacement for `rawResult: true`.'
1684
1684
  );
1685
1685
 
1686
+ /*!
1687
+ * ignore
1688
+ */
1689
+
1690
+ const printOverwriteDeprecationWarning = util.deprecate(
1691
+ function printOverwriteDeprecationWarning() {},
1692
+ 'The `overwrite` option for `findOneAndUpdate()` is deprecated. use `findOneAndReplace()` instead.'
1693
+ );
1694
+
1686
1695
  /**
1687
1696
  * Sets the [`explain` option](https://www.mongodb.com/docs/manual/reference/method/cursor.explain/),
1688
1697
  * which makes this query return detailed execution stats instead of the actual
@@ -3283,6 +3292,10 @@ Query.prototype.findOneAndUpdate = function(filter, doc, options) {
3283
3292
 
3284
3293
  Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
3285
3294
  // For backwards compability with Mongoose 6 re: #13550
3295
+
3296
+ if (this._mongooseOptions.overwrite != null) {
3297
+ printOverwriteDeprecationWarning();
3298
+ }
3286
3299
  if (this._mongooseOptions.overwrite) {
3287
3300
  this.op = 'findOneAndReplace';
3288
3301
  return this._findOneAndReplace();
@@ -3587,9 +3600,6 @@ Query.prototype.findOneAndReplace = function(filter, replacement, options) {
3587
3600
  }
3588
3601
 
3589
3602
  if (replacement != null) {
3590
- if (hasDollarKeys(replacement)) {
3591
- throw new Error('The replacement document must not contain atomic operators.');
3592
- }
3593
3603
  this._mergeUpdate(replacement);
3594
3604
  }
3595
3605
 
@@ -17,6 +17,7 @@ const geospatial = require('./operators/geospatial');
17
17
  const getConstructor = require('../helpers/discriminator/getConstructor');
18
18
  const handleIdOption = require('../helpers/schema/handleIdOption');
19
19
  const internalToObjectOptions = require('../options').internalToObjectOptions;
20
+ const isExclusive = require('../helpers/projection/isExclusive');
20
21
  const utils = require('../utils');
21
22
  const InvalidSchemaOptionError = require('../error/invalidSchemaOption');
22
23
 
@@ -178,7 +179,8 @@ SubdocumentPath.prototype.cast = function(val, doc, init, priorVal, options) {
178
179
  subdoc = new Constructor(void 0, selected, doc, false, { defaults: false });
179
180
  delete subdoc.$__.defaults;
180
181
  subdoc.$init(val);
181
- applyDefaults(subdoc, selected);
182
+ const exclude = isExclusive(selected);
183
+ applyDefaults(subdoc, selected, exclude);
182
184
  } else {
183
185
  options = Object.assign({}, options, { priorDoc: priorVal });
184
186
  if (Object.keys(val).length === 0) {
@@ -289,13 +289,6 @@ SchemaArray.prototype.applyGetters = function(value, scope) {
289
289
  }
290
290
 
291
291
  const ret = SchemaType.prototype.applyGetters.call(this, value, scope);
292
- if (Array.isArray(ret)) {
293
- const rawValue = utils.isMongooseArray(ret) ? ret.__array : ret;
294
- const len = rawValue.length;
295
- for (let i = 0; i < len; ++i) {
296
- rawValue[i] = this.caster.applyGetters(rawValue[i], scope);
297
- }
298
- }
299
292
  return ret;
300
293
  };
301
294
 
package/lib/schema.js CHANGED
@@ -2045,6 +2045,12 @@ Schema.prototype.index = function(fields, options) {
2045
2045
  if (options.expires) {
2046
2046
  utils.expires(options);
2047
2047
  }
2048
+ for (const key in fields) {
2049
+ if (this.aliases[key]) {
2050
+ fields[this.aliases[key]] = fields[key];
2051
+ delete fields[key];
2052
+ }
2053
+ }
2048
2054
 
2049
2055
  for (const field of Object.keys(fields)) {
2050
2056
  if (fields[field] === 'ascending' || fields[field] === 'asc') {
@@ -90,6 +90,9 @@ function MongooseArray(values, path, doc, schematype) {
90
90
  if (mongooseArrayMethods.hasOwnProperty(prop)) {
91
91
  return mongooseArrayMethods[prop];
92
92
  }
93
+ if (typeof prop === 'string' && numberRE.test(prop) && schematype?.$embeddedSchemaType != null) {
94
+ return schematype.$embeddedSchemaType.applyGetters(__array[prop], doc);
95
+ }
93
96
 
94
97
  return __array[prop];
95
98
  },
package/lib/utils.js CHANGED
@@ -640,7 +640,10 @@ exports.getValue = function(path, obj, map) {
640
640
  const mapGetterOptions = Object.freeze({ getters: false });
641
641
 
642
642
  function getValueLookup(obj, part) {
643
- const _from = obj?._doc || obj;
643
+ let _from = obj?._doc || obj;
644
+ if (_from != null && _from.isMongooseArrayProxy) {
645
+ _from = _from.__array;
646
+ }
644
647
  return _from instanceof Map ?
645
648
  _from.get(part, mapGetterOptions) :
646
649
  _from[part];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "7.4.4",
4
+ "version": "7.5.0",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -21,7 +21,7 @@
21
21
  "dependencies": {
22
22
  "bson": "^5.4.0",
23
23
  "kareem": "2.5.1",
24
- "mongodb": "5.7.0",
24
+ "mongodb": "5.8.1",
25
25
  "mpath": "0.9.0",
26
26
  "mquery": "5.0.0",
27
27
  "ms": "2.1.3",
@@ -215,14 +215,16 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
215
215
  PathValueType extends 'decimal128' | 'Decimal128' | typeof Schema.Types.Decimal128 ? Types.Decimal128 :
216
216
  IfEquals<PathValueType, Schema.Types.Decimal128> extends true ? Types.Decimal128 :
217
217
  IfEquals<PathValueType, Types.Decimal128> extends true ? Types.Decimal128 :
218
- PathValueType extends 'uuid' | 'UUID' | typeof Schema.Types.UUID ? Buffer :
219
- IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
220
- PathValueType extends MapConstructor ? Map<string, ResolvePathType<Options['of']>> :
221
- IfEquals<PathValueType, typeof Schema.Types.Map> extends true ? Map<string, ResolvePathType<Options['of']>> :
222
- PathValueType extends ArrayConstructor ? any[] :
223
- PathValueType extends typeof Schema.Types.Mixed ? any:
224
- IfEquals<PathValueType, ObjectConstructor> extends true ? any:
225
- IfEquals<PathValueType, {}> extends true ? any:
226
- PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
227
- PathValueType extends Record<string, any> ? ObtainDocumentType<PathValueType, any, { typeKey: TypeKey }> :
228
- unknown;
218
+ IfEquals<PathValueType, Schema.Types.BigInt> extends true ? bigint :
219
+ PathValueType extends 'bigint' | 'BigInt' | typeof Schema.Types.BigInt ? bigint :
220
+ PathValueType extends 'uuid' | 'UUID' | typeof Schema.Types.UUID ? Buffer :
221
+ IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
222
+ PathValueType extends MapConstructor ? Map<string, ResolvePathType<Options['of']>> :
223
+ IfEquals<PathValueType, typeof Schema.Types.Map> extends true ? Map<string, ResolvePathType<Options['of']>> :
224
+ PathValueType extends ArrayConstructor ? any[] :
225
+ PathValueType extends typeof Schema.Types.Mixed ? any:
226
+ IfEquals<PathValueType, ObjectConstructor> extends true ? any:
227
+ IfEquals<PathValueType, {}> extends true ? any:
228
+ PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
229
+ PathValueType extends Record<string, any> ? ObtainDocumentType<PathValueType, any, { typeKey: TypeKey }> :
230
+ unknown;
@@ -28,6 +28,7 @@ declare module 'mongoose' {
28
28
  | PipelineStage.ReplaceWith
29
29
  | PipelineStage.Sample
30
30
  | PipelineStage.Search
31
+ | PipelineStage.SearchMeta
31
32
  | PipelineStage.Set
32
33
  | PipelineStage.SetWindowFields
33
34
  | PipelineStage.Skip
@@ -239,6 +240,20 @@ declare module 'mongoose' {
239
240
  }
240
241
  }
241
242
 
243
+ export interface SearchMeta {
244
+ /** [`$searchMeta` reference](https://www.mongodb.com/docs/atlas/atlas-search/query-syntax/#mongodb-pipeline-pipe.-searchMeta) */
245
+ $searchMeta: {
246
+ index?: string;
247
+ highlight?: {
248
+ /** [`highlightPath` reference](https://docs.atlas.mongodb.com/atlas-search/path-construction/#multiple-field-search) */
249
+ path: string | string[] | { value: string, multi: string };
250
+ maxCharsToExamine?: number;
251
+ maxNumPassages?: number;
252
+ };
253
+ [operator: string]: any;
254
+ }
255
+ }
256
+
242
257
  export interface Set {
243
258
  /** [`$set` reference](https://www.mongodb.com/docs/manual/reference/operator/aggregation/set/) */
244
259
  $set: Record<string, AnyExpression | any>
@@ -311,6 +311,14 @@ declare module 'mongoose' {
311
311
  enum(vals: string[] | number[]): this;
312
312
  }
313
313
 
314
+ class BigInt extends SchemaType {
315
+ /** This schema type's name, to defend against minifiers that mangle function names. */
316
+ static schemaName: 'BigInt';
317
+
318
+ /** Default options for this SchemaType */
319
+ defaultOptions: Record<string, any>;
320
+ }
321
+
314
322
  class Boolean extends SchemaType {
315
323
  /** This schema type's name, to defend against minifiers that mangle function names. */
316
324
  static schemaName: 'Boolean';