mongoose 8.8.4 → 8.9.1

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/model.js CHANGED
@@ -436,6 +436,7 @@ Model.prototype.$__handleSave = function(options, callback) {
436
436
  Model.prototype.$__save = function(options, callback) {
437
437
  this.$__handleSave(options, (error, result) => {
438
438
  if (error) {
439
+ error = this.$__schema._transformDuplicateKeyError(error);
439
440
  const hooks = this.$__schema.s.hooks;
440
441
  return hooks.execPost('save:error', this, [this], { error: error }, (error) => {
441
442
  callback(error, this);
@@ -2230,7 +2231,7 @@ Model.$where = function $where() {
2230
2231
  /**
2231
2232
  * Issues a mongodb findOneAndUpdate command.
2232
2233
  *
2233
- * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes if `callback` is passed else a Query object is returned.
2234
+ * Finds a matching document, updates it according to the `update` arg, passing any `options`. A Query object is returned.
2234
2235
  *
2235
2236
  * #### Example:
2236
2237
  *
@@ -3356,7 +3357,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
3356
3357
  let error;
3357
3358
  [res, error] = await this.$__collection.bulkWrite(validOps, options).
3358
3359
  then(res => ([res, null])).
3359
- catch(err => ([null, err]));
3360
+ catch(error => ([null, error]));
3360
3361
 
3361
3362
  if (error) {
3362
3363
  if (validationErrors.length > 0) {
@@ -3642,7 +3643,11 @@ Model.castObject = function castObject(obj, options) {
3642
3643
  options = options || {};
3643
3644
  const ret = {};
3644
3645
 
3645
- const schema = this.schema;
3646
+ let schema = this.schema;
3647
+ const discriminatorKey = schema.options.discriminatorKey;
3648
+ if (schema.discriminators != null && obj != null && obj[discriminatorKey] != null) {
3649
+ schema = getSchemaDiscriminatorByValue(schema, obj[discriminatorKey]) || schema;
3650
+ }
3646
3651
  const paths = Object.keys(schema.paths);
3647
3652
 
3648
3653
  for (const path of paths) {
@@ -3991,7 +3996,7 @@ function _update(model, op, conditions, doc, options) {
3991
3996
  /**
3992
3997
  * Performs [aggregations](https://www.mongodb.com/docs/manual/aggregation/) on the models collection.
3993
3998
  *
3994
- * If a `callback` is passed, the `aggregate` is executed and a `Promise` is returned. If a callback is not passed, the `aggregate` itself is returned.
3999
+ * The `aggregate` itself is returned.
3995
4000
  *
3996
4001
  * This function triggers the following middleware.
3997
4002
  *
@@ -4046,10 +4051,6 @@ Model.aggregate = function aggregate(pipeline, options) {
4046
4051
  aggregate.option(options);
4047
4052
  }
4048
4053
 
4049
- if (typeof callback === 'undefined') {
4050
- return aggregate;
4051
- }
4052
-
4053
4054
  return aggregate;
4054
4055
  };
4055
4056
 
@@ -4199,6 +4200,7 @@ Model.validate = async function validate(obj, pathsOrOptions, context) {
4199
4200
  * - options: optional query options like sort, limit, etc
4200
4201
  * - justOne: optional boolean, if true Mongoose will always set `path` to a document, or `null` if no document was found. If false, Mongoose will always set `path` to an array, which will be empty if no documents are found. Inferred from schema by default.
4201
4202
  * - strictPopulate: optional boolean, set to `false` to allow populating paths that aren't in the schema.
4203
+ * - forceRepopulate: optional boolean, defaults to `true`. Set to `false` to prevent Mongoose from repopulating paths that are already populated
4202
4204
  *
4203
4205
  * #### Example:
4204
4206
  *
@@ -4235,7 +4237,7 @@ Model.validate = async function validate(obj, pathsOrOptions, context) {
4235
4237
  * @param {Boolean} [options.strictPopulate=true] Set to false to allow populating paths that aren't defined in the given model's schema.
4236
4238
  * @param {Object} [options.options=null] Additional options like `limit` and `lean`.
4237
4239
  * @param {Function} [options.transform=null] Function that Mongoose will call on every populated document that allows you to transform the populated document.
4238
- * @param {Function} [callback(err,doc)] Optional callback, executed upon completion. Receives `err` and the `doc(s)`.
4240
+ * @param {Boolean} [options.forceRepopulate=true] Set to `false` to prevent Mongoose from repopulating paths that are already populated
4239
4241
  * @return {Promise}
4240
4242
  * @api public
4241
4243
  */
@@ -4245,67 +4247,34 @@ Model.populate = async function populate(docs, paths) {
4245
4247
  if (typeof paths === 'function' || typeof arguments[2] === 'function') {
4246
4248
  throw new MongooseError('Model.populate() no longer accepts a callback');
4247
4249
  }
4248
- const _this = this;
4249
4250
  // normalized paths
4250
4251
  paths = utils.populate(paths);
4251
- // data that should persist across subPopulate calls
4252
- const cache = {};
4253
4252
 
4254
- return new Promise((resolve, reject) => {
4255
- _populate(_this, docs, paths, cache, (err, res) => {
4256
- if (err) {
4257
- return reject(err);
4258
- }
4259
- resolve(res);
4260
- });
4261
- });
4262
- };
4263
-
4264
- /**
4265
- * Populate helper
4266
- *
4267
- * @param {Model} model the model to use
4268
- * @param {Document|Array} docs Either a single document or array of documents to populate.
4269
- * @param {Object} paths
4270
- * @param {never} cache Unused
4271
- * @param {Function} [callback] Optional callback, executed upon completion. Receives `err` and the `doc(s)`.
4272
- * @return {Function}
4273
- * @api private
4274
- */
4275
-
4276
- function _populate(model, docs, paths, cache, callback) {
4277
- let pending = paths.length;
4278
4253
  if (paths.length === 0) {
4279
- return callback(null, docs);
4254
+ return docs;
4280
4255
  }
4256
+
4281
4257
  // each path has its own query options and must be executed separately
4258
+ const promises = [];
4282
4259
  for (const path of paths) {
4283
- populate(model, docs, path, next);
4260
+ promises.push(_populatePath(this, docs, path));
4284
4261
  }
4262
+ await Promise.all(promises);
4285
4263
 
4286
- function next(err) {
4287
- if (err) {
4288
- return callback(err, null);
4289
- }
4290
- if (--pending) {
4291
- return;
4292
- }
4293
- callback(null, docs);
4294
- }
4295
- }
4264
+ return docs;
4265
+ };
4296
4266
 
4297
4267
  /*!
4298
- * Populates `docs`
4268
+ * Populates `docs` for a single `populateOptions` instance.
4299
4269
  */
4300
4270
  const excludeIdReg = /\s?-_id\s?/;
4301
4271
  const excludeIdRegGlobal = /\s?-_id\s?/g;
4302
4272
 
4303
- function populate(model, docs, options, callback) {
4304
- const populateOptions = options;
4305
- if (options.strictPopulate == null) {
4306
- if (options._localModel != null && options._localModel.schema._userProvidedOptions.strictPopulate != null) {
4307
- populateOptions.strictPopulate = options._localModel.schema._userProvidedOptions.strictPopulate;
4308
- } else if (options._localModel != null && model.base.options.strictPopulate != null) {
4273
+ async function _populatePath(model, docs, populateOptions) {
4274
+ if (populateOptions.strictPopulate == null) {
4275
+ if (populateOptions._localModel != null && populateOptions._localModel.schema._userProvidedOptions.strictPopulate != null) {
4276
+ populateOptions.strictPopulate = populateOptions._localModel.schema._userProvidedOptions.strictPopulate;
4277
+ } else if (populateOptions._localModel != null && model.base.options.strictPopulate != null) {
4309
4278
  populateOptions.strictPopulate = model.base.options.strictPopulate;
4310
4279
  } else if (model.base.options.strictPopulate != null) {
4311
4280
  populateOptions.strictPopulate = model.base.options.strictPopulate;
@@ -4317,15 +4286,12 @@ function populate(model, docs, options, callback) {
4317
4286
  docs = [docs];
4318
4287
  }
4319
4288
  if (docs.length === 0 || docs.every(utils.isNullOrUndefined)) {
4320
- return callback();
4289
+ return;
4321
4290
  }
4322
4291
 
4323
4292
  const modelsMap = getModelsMapForPopulate(model, docs, populateOptions);
4324
-
4325
4293
  if (modelsMap instanceof MongooseError) {
4326
- return immediate(function() {
4327
- callback(modelsMap);
4328
- });
4294
+ throw modelsMap;
4329
4295
  }
4330
4296
  const len = modelsMap.length;
4331
4297
  let vals = [];
@@ -4335,7 +4301,6 @@ function populate(model, docs, options, callback) {
4335
4301
  return undefined !== item;
4336
4302
  }
4337
4303
 
4338
- let _remaining = len;
4339
4304
  let hasOne = false;
4340
4305
  const params = [];
4341
4306
  for (let i = 0; i < len; ++i) {
@@ -4366,7 +4331,6 @@ function populate(model, docs, options, callback) {
4366
4331
  // Ensure that we set to 0 or empty array even
4367
4332
  // if we don't actually execute a query to make sure there's a value
4368
4333
  // and we know this path was populated for future sets. See gh-7731, gh-8230
4369
- --_remaining;
4370
4334
  _assign(model, [], mod, assignmentOpts);
4371
4335
  continue;
4372
4336
  }
@@ -4397,64 +4361,50 @@ function populate(model, docs, options, callback) {
4397
4361
  } else if (mod.options.limit != null) {
4398
4362
  assignmentOpts.originalLimit = mod.options.limit;
4399
4363
  }
4400
- params.push([mod, match, select, assignmentOpts, _next]);
4364
+ params.push([mod, match, select, assignmentOpts]);
4401
4365
  }
4402
4366
  if (!hasOne) {
4403
4367
  // If models but no docs, skip further deep populate.
4404
4368
  if (modelsMap.length !== 0) {
4405
- return callback();
4369
+ return;
4406
4370
  }
4407
- // If no models to populate but we have a nested populate,
4408
- // keep trying, re: gh-8946
4371
+ // If no models and no docs to populate but we have a nested populate,
4372
+ // probably a case of unnecessarily populating a non-ref path re: gh-8946
4409
4373
  if (populateOptions.populate != null) {
4410
4374
  const opts = utils.populate(populateOptions.populate).map(pop => Object.assign({}, pop, {
4411
4375
  path: populateOptions.path + '.' + pop.path
4412
4376
  }));
4413
- model.populate(docs, opts).then(res => { callback(null, res); }, err => { callback(err); });
4414
- return;
4377
+ return model.populate(docs, opts);
4415
4378
  }
4416
- return callback();
4379
+ return;
4417
4380
  }
4418
4381
 
4382
+ const promises = [];
4419
4383
  for (const arr of params) {
4420
- _execPopulateQuery.apply(null, arr);
4421
- }
4422
- function _next(err, valsFromDb) {
4423
- if (err != null) {
4424
- return callback(err, null);
4425
- }
4426
- vals = vals.concat(valsFromDb);
4427
- if (--_remaining === 0) {
4428
- _done();
4429
- }
4384
+ promises.push(_execPopulateQuery.apply(null, arr).then(valsFromDb => { vals = vals.concat(valsFromDb); }));
4430
4385
  }
4431
4386
 
4432
- function _done() {
4433
- for (const arr of params) {
4434
- const mod = arr[0];
4435
- const assignmentOpts = arr[3];
4436
- for (const val of vals) {
4437
- mod.options._childDocs.push(val);
4438
- }
4439
- try {
4440
- _assign(model, vals, mod, assignmentOpts);
4441
- } catch (err) {
4442
- return callback(err);
4443
- }
4444
- }
4387
+ await Promise.all(promises);
4445
4388
 
4446
- for (const arr of params) {
4447
- removeDeselectedForeignField(arr[0].foreignField, arr[0].options, vals);
4389
+ for (const arr of params) {
4390
+ const mod = arr[0];
4391
+ const assignmentOpts = arr[3];
4392
+ for (const val of vals) {
4393
+ mod.options._childDocs.push(val);
4448
4394
  }
4449
- for (const arr of params) {
4450
- const mod = arr[0];
4451
- if (mod.options && mod.options.options && mod.options.options._leanTransform) {
4452
- for (const doc of vals) {
4453
- mod.options.options._leanTransform(doc);
4454
- }
4395
+ _assign(model, vals, mod, assignmentOpts);
4396
+ }
4397
+
4398
+ for (const arr of params) {
4399
+ removeDeselectedForeignField(arr[0].foreignField, arr[0].options, vals);
4400
+ }
4401
+ for (const arr of params) {
4402
+ const mod = arr[0];
4403
+ if (mod.options && mod.options.options && mod.options.options._leanTransform) {
4404
+ for (const doc of vals) {
4405
+ mod.options.options._leanTransform(doc);
4455
4406
  }
4456
4407
  }
4457
- callback();
4458
4408
  }
4459
4409
  }
4460
4410
 
@@ -4462,7 +4412,7 @@ function populate(model, docs, options, callback) {
4462
4412
  * ignore
4463
4413
  */
4464
4414
 
4465
- function _execPopulateQuery(mod, match, select, assignmentOpts, callback) {
4415
+ function _execPopulateQuery(mod, match, select) {
4466
4416
  let subPopulate = clone(mod.options.populate);
4467
4417
  const queryOptions = Object.assign({
4468
4418
  skip: mod.options.skip,
@@ -4528,15 +4478,12 @@ function _execPopulateQuery(mod, match, select, assignmentOpts, callback) {
4528
4478
  query.populate(subPopulate);
4529
4479
  }
4530
4480
 
4531
- query.exec().then(
4481
+ return query.exec().then(
4532
4482
  docs => {
4533
4483
  for (const val of docs) {
4534
4484
  leanPopulateMap.set(val, mod.model);
4535
4485
  }
4536
- callback(null, docs);
4537
- },
4538
- err => {
4539
- callback(err);
4486
+ return docs;
4540
4487
  }
4541
4488
  );
4542
4489
  }
@@ -4934,6 +4881,23 @@ Model.inspect = function() {
4934
4881
  return `Model { ${this.modelName} }`;
4935
4882
  };
4936
4883
 
4884
+ /**
4885
+ * Return the MongoDB namespace for this model as a string. The namespace is the database name, followed by '.', followed by the collection name.
4886
+ *
4887
+ * #### Example:
4888
+ *
4889
+ * const conn = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb');
4890
+ * const TestModel = conn.model('Test', mongoose.Schema({ name: String }));
4891
+ *
4892
+ * TestModel.namespace(); // 'mydb.tests'
4893
+ *
4894
+ * @api public
4895
+ */
4896
+
4897
+ Model.namespace = function namespace() {
4898
+ return this.db.name + '.' + this.collection.collectionName;
4899
+ };
4900
+
4937
4901
  if (util.inspect.custom) {
4938
4902
  // Avoid Node deprecation warning DEP0079
4939
4903
  Model[util.inspect.custom] = Model.inspect;
package/lib/mongoose.js CHANGED
@@ -245,7 +245,7 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
245
245
  * @api public
246
246
  */
247
247
 
248
- Mongoose.prototype.set = function(key, value) {
248
+ Mongoose.prototype.set = function getsetOptions(key, value) {
249
249
  const _mongoose = this instanceof Mongoose ? this : mongoose;
250
250
 
251
251
  if (arguments.length === 1 && typeof key !== 'object') {
@@ -376,7 +376,7 @@ Mongoose.prototype.get = Mongoose.prototype.set;
376
376
  * @api public
377
377
  */
378
378
 
379
- Mongoose.prototype.createConnection = function(uri, options) {
379
+ Mongoose.prototype.createConnection = function createConnection(uri, options) {
380
380
  const _mongoose = this instanceof Mongoose ? this : mongoose;
381
381
 
382
382
  const Connection = _mongoose.__driver.Connection;
@@ -427,7 +427,6 @@ Mongoose.prototype.createConnection = function(uri, options) {
427
427
  * @param {Number} [options.socketTimeoutMS=0] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. `socketTimeoutMS` defaults to 0, which means Node.js will not time out the socket due to inactivity. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
428
428
  * @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0`, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
429
429
  * @param {Boolean} [options.autoCreate=false] Set to `true` to make Mongoose automatically call `createCollection()` on every model created on this connection.
430
- * @param {Function} [callback]
431
430
  * @see Mongoose#createConnection https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.createConnection()
432
431
  * @api public
433
432
  * @return {Promise} resolves to `this` if connection succeeded
@@ -479,12 +478,11 @@ Mongoose.prototype.disconnect = async function disconnect() {
479
478
  *
480
479
  * @param {Object} [options] see the [mongodb driver options](https://mongodb.github.io/node-mongodb-native/4.9/classes/MongoClient.html#startSession)
481
480
  * @param {Boolean} [options.causalConsistency=true] set to false to disable causal consistency
482
- * @param {Function} [callback]
483
481
  * @return {Promise<ClientSession>} promise that resolves to a MongoDB driver `ClientSession`
484
482
  * @api public
485
483
  */
486
484
 
487
- Mongoose.prototype.startSession = function() {
485
+ Mongoose.prototype.startSession = function startSession() {
488
486
  const _mongoose = this instanceof Mongoose ? this : mongoose;
489
487
 
490
488
  return _mongoose.connection.startSession.apply(_mongoose.connection, arguments);
@@ -498,7 +496,7 @@ Mongoose.prototype.startSession = function() {
498
496
  * @api public
499
497
  */
500
498
 
501
- Mongoose.prototype.pluralize = function(fn) {
499
+ Mongoose.prototype.pluralize = function pluralize(fn) {
502
500
  const _mongoose = this instanceof Mongoose ? this : mongoose;
503
501
 
504
502
  if (arguments.length > 0) {
@@ -561,7 +559,7 @@ Mongoose.prototype.pluralize = function(fn) {
561
559
  * @api public
562
560
  */
563
561
 
564
- Mongoose.prototype.model = function(name, schema, collection, options) {
562
+ Mongoose.prototype.model = function model(name, schema, collection, options) {
565
563
  const _mongoose = this instanceof Mongoose ? this : mongoose;
566
564
 
567
565
  if (typeof schema === 'string') {
@@ -572,7 +570,7 @@ Mongoose.prototype.model = function(name, schema, collection, options) {
572
570
  if (arguments.length === 1) {
573
571
  const model = _mongoose.models[name];
574
572
  if (!model) {
575
- throw new MongooseError.MissingSchemaError(name);
573
+ throw new _mongoose.Error.MissingSchemaError(name);
576
574
  }
577
575
  return model;
578
576
  }
@@ -581,7 +579,7 @@ Mongoose.prototype.model = function(name, schema, collection, options) {
581
579
  schema = new Schema(schema);
582
580
  }
583
581
  if (schema && !(schema instanceof Schema)) {
584
- throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
582
+ throw new _mongoose.Error('The 2nd parameter to `mongoose.model()` should be a ' +
585
583
  'schema or a POJO');
586
584
  }
587
585
 
@@ -632,7 +630,7 @@ Mongoose.prototype.model = function(name, schema, collection, options) {
632
630
  * ignore
633
631
  */
634
632
 
635
- Mongoose.prototype._model = function(name, schema, collection, options) {
633
+ Mongoose.prototype._model = function _model(name, schema, collection, options) {
636
634
  const _mongoose = this instanceof Mongoose ? this : mongoose;
637
635
 
638
636
  let model;
@@ -707,7 +705,7 @@ Mongoose.prototype._model = function(name, schema, collection, options) {
707
705
  * @return {Mongoose} this
708
706
  */
709
707
 
710
- Mongoose.prototype.deleteModel = function(name) {
708
+ Mongoose.prototype.deleteModel = function deleteModel(name) {
711
709
  const _mongoose = this instanceof Mongoose ? this : mongoose;
712
710
 
713
711
  _mongoose.connection.deleteModel(name);
@@ -726,7 +724,7 @@ Mongoose.prototype.deleteModel = function(name) {
726
724
  * @return {Array}
727
725
  */
728
726
 
729
- Mongoose.prototype.modelNames = function() {
727
+ Mongoose.prototype.modelNames = function modelNames() {
730
728
  const _mongoose = this instanceof Mongoose ? this : mongoose;
731
729
 
732
730
  const names = Object.keys(_mongoose.models);
@@ -740,7 +738,7 @@ Mongoose.prototype.modelNames = function() {
740
738
  * @api private
741
739
  */
742
740
 
743
- Mongoose.prototype._applyPlugins = function(schema, options) {
741
+ Mongoose.prototype._applyPlugins = function _applyPlugins(schema, options) {
744
742
  const _mongoose = this instanceof Mongoose ? this : mongoose;
745
743
 
746
744
  options = options || {};
@@ -763,7 +761,7 @@ Mongoose.prototype._applyPlugins = function(schema, options) {
763
761
  * @api public
764
762
  */
765
763
 
766
- Mongoose.prototype.plugin = function(fn, opts) {
764
+ Mongoose.prototype.plugin = function plugin(fn, opts) {
767
765
  const _mongoose = this instanceof Mongoose ? this : mongoose;
768
766
 
769
767
  _mongoose.plugins.push([fn, opts]);
@@ -987,6 +985,7 @@ Mongoose.prototype.VirtualType = VirtualType;
987
985
  * - [ObjectId](https://mongoosejs.com/docs/schematypes.html#objectids)
988
986
  * - [Map](https://mongoosejs.com/docs/schematypes.html#maps)
989
987
  * - [Subdocument](https://mongoosejs.com/docs/schematypes.html#schemas)
988
+ * - [Int32](https://mongoosejs.com/docs/schematypes.html#int32)
990
989
  *
991
990
  * Using this exposed access to the `ObjectId` type, we can construct ids on demand.
992
991
  *
@@ -1072,7 +1071,7 @@ Mongoose.prototype.ObjectId = SchemaTypes.ObjectId;
1072
1071
  * @api public
1073
1072
  */
1074
1073
 
1075
- Mongoose.prototype.isValidObjectId = function(v) {
1074
+ Mongoose.prototype.isValidObjectId = function isValidObjectId(v) {
1076
1075
  const _mongoose = this instanceof Mongoose ? this : mongoose;
1077
1076
  return _mongoose.Types.ObjectId.isValid(v);
1078
1077
  };
@@ -1104,7 +1103,7 @@ Mongoose.prototype.isValidObjectId = function(v) {
1104
1103
  * @api public
1105
1104
  */
1106
1105
 
1107
- Mongoose.prototype.isObjectIdOrHexString = function(v) {
1106
+ Mongoose.prototype.isObjectIdOrHexString = function isObjectIdOrHexString(v) {
1108
1107
  return isBsonType(v, 'ObjectId') || (typeof v === 'string' && objectIdHexRegexp.test(v));
1109
1108
  };
1110
1109
 
@@ -1116,7 +1115,7 @@ Mongoose.prototype.isObjectIdOrHexString = function(v) {
1116
1115
  * @param {Boolean} options.continueOnError `false` by default. If set to `true`, mongoose will not throw an error if one model syncing failed, and will return an object where the keys are the names of the models, and the values are the results/errors for each model.
1117
1116
  * @return {Promise} Returns a Promise, when the Promise resolves the value is a list of the dropped indexes.
1118
1117
  */
1119
- Mongoose.prototype.syncIndexes = function(options) {
1118
+ Mongoose.prototype.syncIndexes = function syncIndexes(options) {
1120
1119
  const _mongoose = this instanceof Mongoose ? this : mongoose;
1121
1120
  return _mongoose.connection.syncIndexes(options);
1122
1121
  };
@@ -1138,6 +1137,7 @@ Mongoose.prototype.syncIndexes = function(options) {
1138
1137
 
1139
1138
  Mongoose.prototype.Decimal128 = SchemaTypes.Decimal128;
1140
1139
 
1140
+
1141
1141
  /**
1142
1142
  * The Mongoose Mixed [SchemaType](https://mongoosejs.com/docs/schematypes.html). Used for
1143
1143
  * declaring paths in your schema that Mongoose's change tracking, casting,
@@ -1190,8 +1190,8 @@ Mongoose.prototype.Number = SchemaTypes.Number;
1190
1190
  * @api public
1191
1191
  */
1192
1192
 
1193
- Mongoose.prototype.Error = require('./error/index');
1194
- Mongoose.prototype.MongooseError = require('./error/mongooseError');
1193
+ Mongoose.prototype.Error = MongooseError;
1194
+ Mongoose.prototype.MongooseError = MongooseError;
1195
1195
 
1196
1196
  /**
1197
1197
  * Mongoose uses this function to get the current time when setting
@@ -1216,7 +1216,7 @@ Mongoose.prototype.now = function now() { return new Date(); };
1216
1216
  * @api public
1217
1217
  */
1218
1218
 
1219
- Mongoose.prototype.CastError = require('./error/cast');
1219
+ Mongoose.prototype.CastError = MongooseError.CastError;
1220
1220
 
1221
1221
  /**
1222
1222
  * The constructor used for schematype options
package/lib/query.js CHANGED
@@ -2381,6 +2381,7 @@ Query.prototype._find = async function _find() {
2381
2381
  _completeManyLean(_this.model.schema, docs, null, completeManyOptions) :
2382
2382
  _this._completeMany(docs, fields, userProvidedFields, completeManyOptions);
2383
2383
  }
2384
+
2384
2385
  const pop = helpers.preparePopulationOptionsMQ(_this, mongooseOptions);
2385
2386
 
2386
2387
  if (mongooseOptions.lean) {
@@ -3196,7 +3197,6 @@ Query.prototype.deleteMany = function(filter, options) {
3196
3197
  /**
3197
3198
  * Execute a `deleteMany()` query
3198
3199
  *
3199
- * @param {Function} callback
3200
3200
  * @method _deleteMany
3201
3201
  * @instance
3202
3202
  * @memberOf Query
@@ -3489,13 +3489,6 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
3489
3489
  * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
3490
3490
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
3491
3491
  *
3492
- * #### Callback Signature
3493
- *
3494
- * function(error, doc) {
3495
- * // error: any errors that occurred
3496
- * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
3497
- * }
3498
- *
3499
3492
  * #### Example:
3500
3493
  *
3501
3494
  * A.where().findOneAndDelete(conditions, options) // return Query
@@ -3586,13 +3579,6 @@ Query.prototype._findOneAndDelete = async function _findOneAndDelete() {
3586
3579
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
3587
3580
  * - `includeResultMetadata`: if true, returns the full [ModifyResult from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html) rather than just the document
3588
3581
  *
3589
- * #### Callback Signature
3590
- *
3591
- * function(error, doc) {
3592
- * // error: any errors that occurred
3593
- * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
3594
- * }
3595
- *
3596
3582
  * #### Example:
3597
3583
  *
3598
3584
  * A.where().findOneAndReplace(filter, replacement, options); // return Query
@@ -4024,7 +4010,6 @@ Query.prototype._replaceOne = async function _replaceOne() {
4024
4010
  * @param {Boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
4025
4011
  * @param {Boolean} [options.overwriteDiscriminatorKey=false] Mongoose removes discriminator key updates from `update` by default, set `overwriteDiscriminatorKey` to `true` to allow updating the discriminator key
4026
4012
  * @param {Boolean} [options.overwriteImmutable=false] Mongoose removes updated immutable properties from `update` by default (excluding $setOnInsert). Set `overwriteImmutable` to `true` to allow updating immutable properties using other update operators.
4027
- * @param {Function} [callback] params are (error, writeOpResult)
4028
4013
  * @return {Query} this
4029
4014
  * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4030
4015
  * @see Query docs https://mongoosejs.com/docs/queries.html
@@ -4095,7 +4080,6 @@ Query.prototype.updateMany = function(conditions, doc, options, callback) {
4095
4080
  * @param {Boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
4096
4081
  * @param {Boolean} [options.overwriteDiscriminatorKey=false] Mongoose removes discriminator key updates from `update` by default, set `overwriteDiscriminatorKey` to `true` to allow updating the discriminator key
4097
4082
  * @param {Boolean} [options.overwriteImmutable=false] Mongoose removes updated immutable properties from `update` by default (excluding $setOnInsert). Set `overwriteImmutable` to `true` to allow updating immutable properties using other update operators.
4098
- * @param {Function} [callback] params are (error, writeOpResult)
4099
4083
  * @return {Query} this
4100
4084
  * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4101
4085
  * @see Query docs https://mongoosejs.com/docs/queries.html
@@ -4162,7 +4146,6 @@ Query.prototype.updateOne = function(conditions, doc, options, callback) {
4162
4146
  * @param {Object} [options.writeConcern=null] sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](https://mongoosejs.com/docs/guide.html#writeConcern)
4163
4147
  * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
4164
4148
  * @param {Boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
4165
- * @param {Function} [callback] params are (error, writeOpResult)
4166
4149
  * @return {Query} this
4167
4150
  * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4168
4151
  * @see Query docs https://mongoosejs.com/docs/queries.html
@@ -4466,6 +4449,8 @@ Query.prototype.exec = async function exec(op) {
4466
4449
  } else {
4467
4450
  error = err;
4468
4451
  }
4452
+
4453
+ error = this.model.schema._transformDuplicateKeyError(error);
4469
4454
  }
4470
4455
 
4471
4456
  res = await _executePostHooks(this, res, error);
@@ -4762,12 +4747,13 @@ Query.prototype._castUpdate = function _castUpdate(obj) {
4762
4747
  */
4763
4748
 
4764
4749
  Query.prototype.populate = function() {
4750
+ const args = Array.from(arguments);
4765
4751
  // Bail when given no truthy arguments
4766
- if (!Array.from(arguments).some(Boolean)) {
4752
+ if (!args.some(Boolean)) {
4767
4753
  return this;
4768
4754
  }
4769
4755
 
4770
- const res = utils.populate.apply(null, arguments);
4756
+ const res = utils.populate.apply(null, args);
4771
4757
 
4772
4758
  // Propagate readConcern and readPreference and lean from parent query,
4773
4759
  // unless one already specified
@@ -4,6 +4,7 @@
4
4
  * Module dependencies
5
5
  */
6
6
 
7
+ const PopulateOptions = require('./options/populateOptions');
7
8
  const checkEmbeddedDiscriminatorKeyProjection =
8
9
  require('./helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection');
9
10
  const get = require('./helpers/get');
@@ -13,32 +14,6 @@ const isDefiningProjection = require('./helpers/projection/isDefiningProjection'
13
14
  const clone = require('./helpers/clone');
14
15
  const isPathSelectedInclusive = require('./helpers/projection/isPathSelectedInclusive');
15
16
 
16
- /**
17
- * Prepare a set of path options for query population.
18
- *
19
- * @param {Query} query
20
- * @param {Object} options
21
- * @return {Array}
22
- */
23
-
24
- exports.preparePopulationOptions = function preparePopulationOptions(query, options) {
25
- const _populate = query.options.populate;
26
- const pop = Object.keys(_populate).reduce((vals, key) => vals.concat([_populate[key]]), []);
27
-
28
- // lean options should trickle through all queries
29
- if (options.lean != null) {
30
- pop
31
- .filter(p => (p && p.options && p.options.lean) == null)
32
- .forEach(makeLean(options.lean));
33
- }
34
-
35
- pop.forEach(opts => {
36
- opts._localModel = query.model;
37
- });
38
-
39
- return pop;
40
- };
41
-
42
17
  /**
43
18
  * Prepare a set of path options for query population. This is the MongooseQuery
44
19
  * version
@@ -73,12 +48,18 @@ exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query,
73
48
  }
74
49
 
75
50
  const projection = query._fieldsForExec();
76
- pop.forEach(p => {
77
- p._queryProjection = projection;
78
- });
79
- pop.forEach(opts => {
80
- opts._localModel = query.model;
81
- });
51
+ for (let i = 0; i < pop.length; ++i) {
52
+ if (pop[i] instanceof PopulateOptions) {
53
+ pop[i] = new PopulateOptions({
54
+ ...pop[i],
55
+ _queryProjection: projection,
56
+ _localModel: query.model
57
+ });
58
+ } else {
59
+ pop[i]._queryProjection = projection;
60
+ pop[i]._localModel = query.model;
61
+ }
62
+ }
82
63
 
83
64
  return pop;
84
65
  };
@@ -81,12 +81,12 @@ SchemaBigInt.setters = [];
81
81
  SchemaBigInt.get = SchemaType.get;
82
82
 
83
83
  /**
84
- * Get/set the function used to cast arbitrary values to booleans.
84
+ * Get/set the function used to cast arbitrary values to bigints.
85
85
  *
86
86
  * #### Example:
87
87
  *
88
88
  * // Make Mongoose cast empty string '' to false.
89
- * const original = mongoose.Schema.BigInt.cast();
89
+ * const original = mongoose.Schema.Types.BigInt.cast();
90
90
  * mongoose.Schema.BigInt.cast(v => {
91
91
  * if (v === '') {
92
92
  * return false;