mongoose 5.5.0 → 5.5.4

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
@@ -1120,14 +1120,6 @@ Model.init = function init(callback) {
1120
1120
  return this.$init;
1121
1121
  }
1122
1122
 
1123
- // If `dropDatabase()` is called, this model's collection will not be
1124
- // init-ed. It is sufficiently common to call `dropDatabase()` after
1125
- // `mongoose.connect()` but before creating models that we want to
1126
- // support this. See gh-6967
1127
- this.db.$internalEmitter.once('dropDatabase', () => {
1128
- delete this.$init;
1129
- });
1130
-
1131
1123
  const Promise = PromiseProvider.get();
1132
1124
  const autoIndex = this.schema.options.autoIndex == null ?
1133
1125
  this.db.config.autoIndex :
@@ -2611,7 +2603,8 @@ Model.findByIdAndDelete = function(id, options, callback) {
2611
2603
  *
2612
2604
  * - defaults. Use the `setDefaultsOnInsert` option to override.
2613
2605
  *
2614
- * @param {Object} conditions
2606
+ * @param {Object} filter Replace the first document that matches this filter
2607
+ * @param {Object} [replacement] Replace with this document
2615
2608
  * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
2616
2609
  * @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](http://mongoosejs.com/docs/api.html#query_Query-lean).
2617
2610
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
@@ -2621,18 +2614,24 @@ Model.findByIdAndDelete = function(id, options, callback) {
2621
2614
  * @api public
2622
2615
  */
2623
2616
 
2624
- Model.findOneAndReplace = function(conditions, options, callback) {
2625
- if (arguments.length === 1 && typeof conditions === 'function') {
2626
- const msg = 'Model.findOneAndDelete(): First argument must not be a function.\n\n'
2627
- + ' ' + this.modelName + '.findOneAndDelete(conditions, callback)\n'
2628
- + ' ' + this.modelName + '.findOneAndDelete(conditions)\n'
2629
- + ' ' + this.modelName + '.findOneAndDelete()\n';
2617
+ Model.findOneAndReplace = function(filter, replacement, options, callback) {
2618
+ if (arguments.length === 1 && typeof filter === 'function') {
2619
+ const msg = 'Model.findOneAndReplace(): First argument must not be a function.\n\n'
2620
+ + ' ' + this.modelName + '.findOneAndReplace(conditions, callback)\n'
2621
+ + ' ' + this.modelName + '.findOneAndReplace(conditions)\n'
2622
+ + ' ' + this.modelName + '.findOneAndReplace()\n';
2630
2623
  throw new TypeError(msg);
2631
2624
  }
2632
2625
 
2633
- if (typeof options === 'function') {
2626
+ if (arguments.length === 3 && typeof options === 'function') {
2634
2627
  callback = options;
2635
- options = undefined;
2628
+ options = replacement;
2629
+ replacement = void 0;
2630
+ }
2631
+ if (arguments.length === 2 && typeof replacement === 'function') {
2632
+ callback = replacement;
2633
+ replacement = void 0;
2634
+ options = void 0;
2636
2635
  }
2637
2636
  if (callback) {
2638
2637
  callback = this.$wrapCallback(callback);
@@ -2647,7 +2646,7 @@ Model.findOneAndReplace = function(conditions, options, callback) {
2647
2646
  const mq = new this.Query({}, {}, this, this.collection);
2648
2647
  mq.select(fields);
2649
2648
 
2650
- return mq.findOneAndReplace(conditions, options, callback);
2649
+ return mq.findOneAndReplace(filter, replacement, options, callback);
2651
2650
  };
2652
2651
 
2653
2652
  /**
@@ -2897,6 +2896,11 @@ Model.create = function create(doc, options, callback) {
2897
2896
  }
2898
2897
  }
2899
2898
 
2899
+ // Make sure session is available in middleware
2900
+ if (options.session != null) {
2901
+ toSave.$session(options.session);
2902
+ }
2903
+
2900
2904
  toSave.save(options, callbackWrapper);
2901
2905
  });
2902
2906
  });
@@ -3171,7 +3175,32 @@ Model.$__insertMany = function(arr, options, callback) {
3171
3175
  * console.log(res.insertedCount, res.modifiedCount, res.deletedCount);
3172
3176
  * });
3173
3177
  *
3178
+ * The [supported operations](https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/#db.collection.bulkWrite) are:
3179
+ *
3180
+ * - `insertOne`
3181
+ * - `updateOne`
3182
+ * - `updateMany`
3183
+ * - `deleteOne`
3184
+ * - `deleteMany`
3185
+ * - `replaceOne`
3186
+ *
3174
3187
  * @param {Array} ops
3188
+ * @param {Object} [ops.insertOne.document] The document to insert
3189
+ * @param {Object} [opts.updateOne.filter] Update the first document that matches this filter
3190
+ * @param {Object} [opts.updateOne.update] An object containing [update operators](https://docs.mongodb.com/manual/reference/operator/update/)
3191
+ * @param {Boolean} [opts.updateOne.upsert=false] If true, insert a doc if none match
3192
+ * @param {Object} [opts.updateOne.collation] The [MongoDB collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) to use
3193
+ * @param {Array} [opts.updateOne.arrayFilters] The [array filters](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html) used in `update`
3194
+ * @param {Object} [opts.updateMany.filter] Update all the documents that match this filter
3195
+ * @param {Object} [opts.updateMany.update] An object containing [update operators](https://docs.mongodb.com/manual/reference/operator/update/)
3196
+ * @param {Boolean} [opts.updateMany.upsert=false] If true, insert a doc if no documents match `filter`
3197
+ * @param {Object} [opts.updateMany.collation] The [MongoDB collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) to use
3198
+ * @param {Array} [opts.updateMany.arrayFilters] The [array filters](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html) used in `update`
3199
+ * @param {Object} [opts.deleteOne.filter] Delete the first document that matches this filter
3200
+ * @param {Object} [opts.deleteMany.filter] Delete all documents that match this filter
3201
+ * @param {Object} [opts.replaceOne.filter] Replace the first document that matches this filter
3202
+ * @param {Object} [opts.replaceOne.replacement] The replacement document
3203
+ * @param {Boolean} [opts.replaceOne.upsert=false] If true, insert a doc if no documents match `filter`
3175
3204
  * @param {Object} [options]
3176
3205
  * @param {Boolean} [options.ordered=true] If true, execute writes in order and stop at the first error. If false, execute writes in parallel and continue until all writes have either succeeded or errored.
3177
3206
  * @param {ClientSession} [options.session=null] The session associated with this bulk write. See [transactions docs](/docs/transactions.html).
@@ -3308,9 +3337,17 @@ Model.hydrate = function(obj) {
3308
3337
  * @param {Object} conditions
3309
3338
  * @param {Object} doc
3310
3339
  * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
3340
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
3341
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
3342
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
3343
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3344
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
3345
+ * @param {Function} [callback] params are (error, writeOpResult)
3311
3346
  * @param {Function} [callback]
3312
3347
  * @return {Query}
3313
3348
  * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
3349
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
3350
+ * @see Query docs https://mongoosejs.com/docs/queries.html
3314
3351
  * @api public
3315
3352
  */
3316
3353
 
@@ -3339,10 +3376,15 @@ Model.update = function update(conditions, doc, options, callback) {
3339
3376
  * @param {Object} doc
3340
3377
  * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
3341
3378
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
3379
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
3380
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
3342
3381
  * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3343
- * @param {Function} [callback]
3382
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
3383
+ * @param {Function} [callback] `function(error, res) {}` where `res` has 3 properties: `n`, `nModified`, `ok`.
3344
3384
  * @return {Query}
3385
+ * @see Query docs https://mongoosejs.com/docs/queries.html
3345
3386
  * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
3387
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
3346
3388
  * @api public
3347
3389
  */
3348
3390
 
@@ -3370,10 +3412,15 @@ Model.updateMany = function updateMany(conditions, doc, options, callback) {
3370
3412
  * @param {Object} doc
3371
3413
  * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
3372
3414
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
3415
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
3416
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
3373
3417
  * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3374
- * @param {Function} [callback]
3418
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
3419
+ * @param {Function} [callback] params are (error, writeOpResult)
3375
3420
  * @return {Query}
3421
+ * @see Query docs https://mongoosejs.com/docs/queries.html
3376
3422
  * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
3423
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
3377
3424
  * @api public
3378
3425
  */
3379
3426
 
@@ -3398,8 +3445,14 @@ Model.updateOne = function updateOne(conditions, doc, options, callback) {
3398
3445
  * @param {Object} doc
3399
3446
  * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
3400
3447
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
3448
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
3449
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
3401
3450
  * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3402
- * @param {Function} [callback]
3451
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
3452
+ * @param {Function} [callback] `function(error, res) {}` where `res` has 3 properties: `n`, `nModified`, `ok`.
3453
+ * @return {Query}
3454
+ * @see Query docs https://mongoosejs.com/docs/queries.html
3455
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
3403
3456
  * @return {Query}
3404
3457
  * @api public
3405
3458
  */
@@ -4440,8 +4493,8 @@ function convertTo_id(val) {
4440
4493
  val[i] = val[i]._id;
4441
4494
  }
4442
4495
  }
4443
- if (val.isMongooseArray && val._schema) {
4444
- return val._schema.cast(val, val._parent);
4496
+ if (val.isMongooseArray && val.$schema()) {
4497
+ return val.$schema().cast(val, val.$parent());
4445
4498
  }
4446
4499
 
4447
4500
  return [].concat(val);
@@ -4550,7 +4603,8 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
4550
4603
 
4551
4604
  const collectionOptions = {
4552
4605
  bufferCommands: bufferCommands,
4553
- capped: schema.options.capped
4606
+ capped: schema.options.capped,
4607
+ Promise: model.base.Promise
4554
4608
  };
4555
4609
 
4556
4610
  model.prototype.collection = connection.collection(
package/lib/query.js CHANGED
@@ -3118,16 +3118,17 @@ Query.prototype._findOneAndDelete = wrapThunk(function(callback) {
3118
3118
  *
3119
3119
  * ####Examples
3120
3120
  *
3121
- * A.where().findOneAndReplace(conditions, options, callback) // executes
3122
- * A.where().findOneAndReplace(conditions, options) // return Query
3123
- * A.where().findOneAndReplace(conditions, callback) // executes
3124
- * A.where().findOneAndReplace(conditions) // returns Query
3125
- * A.where().findOneAndReplace(callback) // executes
3126
- * A.where().findOneAndReplace() // returns Query
3121
+ * A.where().findOneAndReplace(filter, replacement, options, callback); // executes
3122
+ * A.where().findOneAndReplace(filter, replacement, options); // return Query
3123
+ * A.where().findOneAndReplace(filter, replacement, callback); // executes
3124
+ * A.where().findOneAndReplace(filter); // returns Query
3125
+ * A.where().findOneAndReplace(callback); // executes
3126
+ * A.where().findOneAndReplace(); // returns Query
3127
3127
  *
3128
3128
  * @method findOneAndReplace
3129
3129
  * @memberOf Query
3130
- * @param {Object} [conditions]
3130
+ * @param {Object} [filter]
3131
+ * @param {Object} [replacement]
3131
3132
  * @param {Object} [options]
3132
3133
  * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
3133
3134
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
@@ -3138,28 +3139,39 @@ Query.prototype._findOneAndDelete = wrapThunk(function(callback) {
3138
3139
  * @api public
3139
3140
  */
3140
3141
 
3141
- Query.prototype.findOneAndReplace = function(conditions, options, callback) {
3142
+ Query.prototype.findOneAndReplace = function(filter, replacement, options, callback) {
3142
3143
  this.op = 'findOneAndReplace';
3143
3144
  this._validate();
3144
3145
 
3145
3146
  switch (arguments.length) {
3146
- case 2:
3147
+ case 3:
3147
3148
  if (typeof options === 'function') {
3148
3149
  callback = options;
3149
- options = {};
3150
+ options = void 0;
3151
+ }
3152
+ break;
3153
+ case 2:
3154
+ if (typeof replacement === 'function') {
3155
+ callback = replacement;
3156
+ replacement = void 0;
3150
3157
  }
3151
3158
  break;
3152
3159
  case 1:
3153
- if (typeof conditions === 'function') {
3154
- callback = conditions;
3155
- conditions = undefined;
3156
- options = undefined;
3160
+ if (typeof filter === 'function') {
3161
+ callback = filter;
3162
+ filter = void 0;
3163
+ replacement = void 0;
3164
+ options = void 0;
3157
3165
  }
3158
3166
  break;
3159
3167
  }
3160
3168
 
3161
- if (mquery.canMerge(conditions)) {
3162
- this.merge(conditions);
3169
+ if (mquery.canMerge(filter)) {
3170
+ this.merge(filter);
3171
+ }
3172
+
3173
+ if (replacement != null) {
3174
+ this._mergeUpdate(replacement);
3163
3175
  }
3164
3176
 
3165
3177
  options && this.setOptions(options);
@@ -3419,12 +3431,7 @@ Query.prototype._findAndModify = function(type, callback) {
3419
3431
  if (error) {
3420
3432
  return callback(error);
3421
3433
  }
3422
- if (castedDoc && castedDoc.toBSON) {
3423
- castedDoc = castedDoc.toBSON();
3424
- }
3425
- _this._collection.findAndModify(castedQuery, castedDoc, opts, _wrapThunkCallback(_this, function(error, res) {
3426
- return cb(error, res ? res.value : res, res);
3427
- }));
3434
+ _legacyFindAndModify.call(_this, castedQuery, castedDoc, opts, cb);
3428
3435
  };
3429
3436
 
3430
3437
  try {
@@ -3433,12 +3440,7 @@ Query.prototype._findAndModify = function(type, callback) {
3433
3440
  callback(error);
3434
3441
  }
3435
3442
  } else {
3436
- if (castedDoc && castedDoc.toBSON) {
3437
- castedDoc = castedDoc.toBSON();
3438
- }
3439
- this._collection.findAndModify(castedQuery, castedDoc, opts, _wrapThunkCallback(_this, function(error, res) {
3440
- return cb(error, res ? res.value : res, res);
3441
- }));
3443
+ _legacyFindAndModify.call(_this, castedQuery, castedDoc, opts, cb);
3442
3444
  }
3443
3445
 
3444
3446
  return this;
@@ -3455,6 +3457,23 @@ function _completeOneLean(doc, res, opts, callback) {
3455
3457
  return callback(null, doc);
3456
3458
  }
3457
3459
 
3460
+
3461
+ /*!
3462
+ * ignore
3463
+ */
3464
+
3465
+ const _legacyFindAndModify = util.deprecate(function(filter, update, opts, cb) {
3466
+ if (update && update.toBSON) {
3467
+ update = update.toBSON();
3468
+ }
3469
+ const collection = this._collection;
3470
+ collection.findAndModify(filter, update, opts, _wrapThunkCallback(this, function(error, res) {
3471
+ return cb(error, res ? res.value : res, res);
3472
+ }));
3473
+ }, 'Mongoose: `findOneAndUpdate()` and `findOneAndDelete()` without the ' +
3474
+ '`useFindAndModify` option set to false are deprecated. See: ' +
3475
+ 'https://mongoosejs.com/docs/deprecations.html#-findandmodify-');
3476
+
3458
3477
  /*!
3459
3478
  * Override mquery.prototype._mergeUpdate to handle mongoose objects in
3460
3479
  * updates.
@@ -3716,9 +3735,16 @@ Query.prototype._replaceOne = wrapThunk(function(callback) {
3716
3735
  * @param {Object} [doc] the update command
3717
3736
  * @param {Object} [options]
3718
3737
  * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
3719
- * @param {Function} [callback] optional, params are (error, writeOpResult)
3738
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3739
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
3740
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
3741
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
3742
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3743
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
3744
+ * @param {Function} [callback] params are (error, writeOpResult)
3720
3745
  * @return {Query} this
3721
3746
  * @see Model.update #model_Model.update
3747
+ * @see Query docs https://mongoosejs.com/docs/queries.html
3722
3748
  * @see update http://docs.mongodb.org/manual/reference/method/db.collection.update/
3723
3749
  * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
3724
3750
  * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
@@ -3776,9 +3802,15 @@ Query.prototype.update = function(conditions, doc, options, callback) {
3776
3802
  * @param {Object} [options]
3777
3803
  * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
3778
3804
  * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3779
- * @param {Function} [callback] optional params are (error, writeOpResult)
3805
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
3806
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
3807
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
3808
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3809
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
3810
+ * @param {Function} [callback] params are (error, writeOpResult)
3780
3811
  * @return {Query} this
3781
3812
  * @see Model.update #model_Model.update
3813
+ * @see Query docs https://mongoosejs.com/docs/queries.html
3782
3814
  * @see update http://docs.mongodb.org/manual/reference/method/db.collection.update/
3783
3815
  * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
3784
3816
  * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
@@ -3837,9 +3869,15 @@ Query.prototype.updateMany = function(conditions, doc, options, callback) {
3837
3869
  * @param {Object} [options]
3838
3870
  * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
3839
3871
  * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3872
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
3873
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
3874
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
3875
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3876
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
3840
3877
  * @param {Function} [callback] params are (error, writeOpResult)
3841
3878
  * @return {Query} this
3842
3879
  * @see Model.update #model_Model.update
3880
+ * @see Query docs https://mongoosejs.com/docs/queries.html
3843
3881
  * @see update http://docs.mongodb.org/manual/reference/method/db.collection.update/
3844
3882
  * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
3845
3883
  * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
@@ -3894,10 +3932,17 @@ Query.prototype.updateOne = function(conditions, doc, options, callback) {
3894
3932
  * @param {Object} [criteria]
3895
3933
  * @param {Object} [doc] the update command
3896
3934
  * @param {Object} [options]
3935
+ * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
3897
3936
  * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3898
- * @param {Function} [callback] optional params are (error, writeOpResult)
3937
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
3938
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
3939
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
3940
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
3941
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
3942
+ * @param {Function} [callback] params are (error, writeOpResult)
3899
3943
  * @return {Query} this
3900
3944
  * @see Model.update #model_Model.update
3945
+ * @see Query docs https://mongoosejs.com/docs/queries.html
3901
3946
  * @see update http://docs.mongodb.org/manual/reference/method/db.collection.update/
3902
3947
  * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
3903
3948
  * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
@@ -146,6 +146,56 @@ SchemaArray.options = { castNonArrays: true };
146
146
  SchemaArray.prototype = Object.create(SchemaType.prototype);
147
147
  SchemaArray.prototype.constructor = SchemaArray;
148
148
 
149
+ /*!
150
+ * ignore
151
+ */
152
+
153
+ SchemaArray._checkRequired = SchemaType.prototype.checkRequired;
154
+
155
+ /**
156
+ * Override the function the required validator uses to check whether an array
157
+ * passes the `required` check.
158
+ *
159
+ * ####Example:
160
+ *
161
+ * // Require non-empty array to pass `required` check
162
+ * mongoose.Schema.Types.Array.checkRequired(v => Array.isArray(v) && v.length);
163
+ *
164
+ * const M = mongoose.model({ arr: { type: Array, required: true } });
165
+ * new M({ arr: [] }).validateSync(); // `null`, validation fails!
166
+ *
167
+ * @param {Function} fn
168
+ * @return {Function}
169
+ * @function checkRequired
170
+ * @static
171
+ * @api public
172
+ */
173
+
174
+ SchemaArray.checkRequired = SchemaType.checkRequired;
175
+
176
+ /**
177
+ * Check if the given value satisfies the `required` validator.
178
+ *
179
+ * @param {Any} value
180
+ * @param {Document} doc
181
+ * @return {Boolean}
182
+ * @api public
183
+ */
184
+
185
+ SchemaArray.prototype.checkRequired = function checkRequired(value, doc) {
186
+ if (SchemaType._isRef(this, value, doc, true)) {
187
+ return !!value;
188
+ }
189
+
190
+ // `require('util').inherits()` does **not** copy static properties, and
191
+ // plugins like mongoose-float use `inherits()` for pre-ES6.
192
+ const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
193
+ this.constructor.checkRequired() :
194
+ SchemaArray.checkRequired();
195
+
196
+ return _checkRequired(value);
197
+ };
198
+
149
199
  /**
150
200
  * Adds an enum validator if this is an array of strings. Equivalent to
151
201
  * `SchemaString.prototype.enum()`
@@ -13,6 +13,8 @@ const util = require('util');
13
13
  const utils = require('../utils');
14
14
  const getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByValue;
15
15
 
16
+ const arrayParentSymbol = require('../helpers/symbols').arrayParentSymbol;
17
+
16
18
  let MongooseDocumentArray;
17
19
  let Subdocument;
18
20
 
@@ -207,8 +209,8 @@ DocumentArray.prototype.doValidate = function(array, fn, scope, options) {
207
209
  // If you set the array index directly, the doc might not yet be
208
210
  // a full fledged mongoose subdoc, so make it into one.
209
211
  if (!(doc instanceof Subdocument)) {
210
- doc = array[i] = new _this.casterConstructor(doc, array, undefined,
211
- undefined, i);
212
+ const Constructor = getConstructor(_this, array[i]);
213
+ doc = array[i] = new Constructor(doc, array, undefined, undefined, i);
212
214
  }
213
215
 
214
216
  doc.$__validate(callback);
@@ -255,8 +257,8 @@ DocumentArray.prototype.doValidateSync = function(array, scope) {
255
257
  // If you set the array index directly, the doc might not yet be
256
258
  // a full fledged mongoose subdoc, so make it into one.
257
259
  if (!(doc instanceof Subdocument)) {
258
- doc = array[i] = new this.casterConstructor(doc, array, undefined,
259
- undefined, i);
260
+ const Constructor = getConstructor(this, array[i]);
261
+ doc = array[i] = new Constructor(doc, array, undefined, undefined, i);
260
262
  }
261
263
 
262
264
  const subdocValidateError = doc.validateSync();
@@ -290,15 +292,16 @@ DocumentArray.prototype.getDefault = function(scope) {
290
292
  }
291
293
 
292
294
  ret = new MongooseDocumentArray(ret, this.path, scope);
293
- const _parent = ret._parent;
294
- ret._parent = null;
295
+ const _parent = ret[arrayParentSymbol];
296
+ ret[arrayParentSymbol] = null;
295
297
 
296
298
  for (let i = 0; i < ret.length; ++i) {
297
- ret[i] = new this.Constructor(ret[i], ret, undefined,
299
+ const Constructor = getConstructor(this, ret[i]);
300
+ ret[i] = new Constructor(ret[i], ret, undefined,
298
301
  undefined, i);
299
302
  }
300
303
 
301
- ret._parent = _parent;
304
+ ret[arrayParentSymbol] = _parent;
302
305
 
303
306
  return ret;
304
307
  };
@@ -349,30 +352,19 @@ DocumentArray.prototype.cast = function(value, doc, init, prev, options) {
349
352
  continue;
350
353
  }
351
354
 
352
- let Constructor = this.casterConstructor;
353
- if (Constructor.discriminators &&
354
- Constructor.schema &&
355
- Constructor.schema.options &&
356
- typeof value[i][Constructor.schema.options.discriminatorKey] === 'string') {
357
- if (Constructor.discriminators[value[i][Constructor.schema.options.discriminatorKey]]) {
358
- Constructor = Constructor.discriminators[value[i][Constructor.schema.options.discriminatorKey]];
359
- } else {
360
- const constructorByValue = getDiscriminatorByValue(Constructor, value[i][Constructor.schema.options.discriminatorKey]);
361
- if (constructorByValue) {
362
- Constructor = constructorByValue;
363
- }
364
- }
365
- }
355
+ const Constructor = getConstructor(this, value[i]);
366
356
 
367
357
  // Check if the document has a different schema (re gh-3701)
368
358
  if ((value[i].$__) &&
369
- value[i].schema !== Constructor.schema) {
359
+ !(value[i] instanceof Constructor)) {
370
360
  value[i] = value[i].toObject({ transform: false, virtuals: false });
371
361
  }
372
362
 
373
363
  if (value[i] instanceof Subdocument) {
374
364
  // Might not have the correct index yet, so ensure it does.
375
- value[i].$setIndex(i);
365
+ if (value[i].__index == null) {
366
+ value[i].$setIndex(i);
367
+ }
376
368
  } else if (value[i] != null) {
377
369
  if (init) {
378
370
  if (doc) {
@@ -417,6 +409,30 @@ DocumentArray.prototype.cast = function(value, doc, init, prev, options) {
417
409
  return value;
418
410
  };
419
411
 
412
+ /*!
413
+ * Find the correct subdoc constructor, taking into account discriminators
414
+ */
415
+
416
+ function getConstructor(docArray, subdoc) {
417
+ let Constructor = docArray.casterConstructor;
418
+ const schema = Constructor.schema;
419
+ const discriminatorKey = schema.options.discriminatorKey;
420
+ const discriminatorValue = subdoc[discriminatorKey];
421
+ if (Constructor.discriminators && typeof discriminatorValue === 'string') {
422
+ if (Constructor.discriminators[discriminatorValue]) {
423
+ Constructor = Constructor.discriminators[discriminatorValue];
424
+ } else {
425
+ const constructorByValue = getDiscriminatorByValue(Constructor,
426
+ discriminatorValue);
427
+ if (constructorByValue) {
428
+ Constructor = constructorByValue;
429
+ }
430
+ }
431
+ }
432
+
433
+ return Constructor;
434
+ }
435
+
420
436
  /*!
421
437
  * ignore
422
438
  */
@@ -432,12 +448,12 @@ DocumentArray.prototype.clone = function() {
432
448
  */
433
449
 
434
450
  function _clearListeners(arr) {
435
- if (arr == null || arr._parent == null) {
451
+ if (arr == null || arr[arrayParentSymbol] == null) {
436
452
  return;
437
453
  }
438
454
 
439
455
  for (const key in arr._handlers) {
440
- arr._parent.removeListener(key, arr._handlers[key]);
456
+ arr[arrayParentSymbol].removeListener(key, arr._handlers[key]);
441
457
  }
442
458
  }
443
459
 
package/lib/schema.js CHANGED
@@ -1049,11 +1049,12 @@ Schema.prototype.setupTimestamp = function(timestamps) {
1049
1049
 
1050
1050
  _setTimestampsOnUpdate[symbols.builtInMiddleware] = true;
1051
1051
 
1052
- this.pre('findOneAndUpdate', _setTimestampsOnUpdate);
1053
- this.pre('replaceOne', _setTimestampsOnUpdate);
1054
- this.pre('update', _setTimestampsOnUpdate);
1055
- this.pre('updateOne', _setTimestampsOnUpdate);
1056
- this.pre('updateMany', _setTimestampsOnUpdate);
1052
+ const opts = { query: true, model: false };
1053
+ this.pre('findOneAndUpdate', opts, _setTimestampsOnUpdate);
1054
+ this.pre('replaceOne', opts, _setTimestampsOnUpdate);
1055
+ this.pre('update', opts, _setTimestampsOnUpdate);
1056
+ this.pre('updateOne', opts, _setTimestampsOnUpdate);
1057
+ this.pre('updateMany', opts, _setTimestampsOnUpdate);
1057
1058
 
1058
1059
  function _setTimestampsOnUpdate(next) {
1059
1060
  const now = this.model.base.now();