diff --git a/lib/model.js b/lib/model.js index 3635f93b9f..abc120182e 100644 --- a/lib/model.js +++ b/lib/model.js @@ -3982,6 +3982,10 @@ Model.hydrate = function(obj, projection, options) { * res.upsertedId; // null or an id containing a document that had to be upserted. * res.upsertedCount; // Number indicating how many documents had to be upserted. Will either be 0 or 1. * + * // Other supported syntaxes + * await Person.find({ name: /Stark$/ }).updateMany({ isDeleted: true }); // Using chaining syntax + * await Person.find().updateMany({ isDeleted: true }); // Set `isDeleted` on _all_ Person documents + * * This function triggers the following middleware. * * - `updateMany()` @@ -4002,10 +4006,14 @@ Model.hydrate = function(obj, projection, options) { * @api public */ -Model.updateMany = function updateMany(conditions, doc, options) { +Model.updateMany = function updateMany(conditions, update, options) { _checkContext(this, 'updateMany'); - return _update(this, 'updateMany', conditions, doc, options); + if (update == null) { + throw new MongooseError('updateMany `update` parameter cannot be nullish'); + } + + return _update(this, 'updateMany', conditions, update, options); }; /** @@ -4022,6 +4030,10 @@ Model.updateMany = function updateMany(conditions, doc, options) { * res.upsertedId; // null or an id containing a document that had to be upserted. * res.upsertedCount; // Number indicating how many documents had to be upserted. Will either be 0 or 1. * + * // Other supported syntaxes + * await Person.findOne({ name: 'Jean-Luc Picard' }).updateOne({ ship: 'USS Enterprise' }); // Using chaining syntax + * await Person.updateOne({ ship: 'USS Enterprise' }); // Updates first doc's `ship` property + * * This function triggers the following middleware. * * - `updateOne()` diff --git a/lib/query.js b/lib/query.js index 067a6e020e..7ea8403b40 100644 --- a/lib/query.js +++ b/lib/query.js @@ -3992,6 +3992,10 @@ Query.prototype._replaceOne = async function _replaceOne() { * res.n; // Number of documents matched * res.nModified; // Number of documents modified * + * // Other supported syntaxes + * await Person.find({ name: /Stark$/ }).updateMany({ isDeleted: true }); // Using chaining syntax + * await Person.find().updateMany({ isDeleted: true }); // Set `isDeleted` on _all_ Person documents + * * This function triggers the following middleware. * * - `updateMany()` @@ -4062,6 +4066,10 @@ Query.prototype.updateMany = function(conditions, doc, options, callback) { * res.upsertedCount; // Number of documents that were upserted * res.upsertedId; // Identifier of the inserted document (if an upsert took place) * + * // Other supported syntaxes + * await Person.findOne({ name: 'Jean-Luc Picard' }).updateOne({ ship: 'USS Enterprise' }); // Using chaining syntax + * await Person.updateOne({ ship: 'USS Enterprise' }); // Updates first doc's `ship` property + * * This function triggers the following middleware. * * - `updateOne()` diff --git a/test/model.middleware.preposttypes.test.js b/test/model.middleware.preposttypes.test.js index 952bc90100..93a42f8dc1 100644 --- a/test/model.middleware.preposttypes.test.js +++ b/test/model.middleware.preposttypes.test.js @@ -288,8 +288,8 @@ describe('pre/post hooks, type of this', function() { await Doc.findOneAndReplace({}, { data: 'valueRep' }).exec(); await Doc.findOneAndUpdate({}, { data: 'valueUpd' }).exec(); await Doc.replaceOne({}, { data: 'value' }).exec(); - await Doc.updateOne({ data: 'value' }).exec(); - await Doc.updateMany({ data: 'value' }).exec(); + await Doc.updateOne({}, { data: 'value' }).exec(); + await Doc.updateMany({}, { data: 'value' }).exec(); // MongooseQueryOrDocumentMiddleware, use Query await Doc.deleteOne({}).exec(); await Doc.create({ data: 'value' }); diff --git a/test/model.test.js b/test/model.test.js index da870125e0..6fb12c9d2f 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -8505,6 +8505,15 @@ describe('Model', function() { }); }); + it('throws error if calling `updateMany()` with no update param (gh-15190)', async function() { + const Test = db.model('Test', mongoose.Schema({ foo: String })); + + assert.throws( + () => Test.updateMany({ foo: 'bar' }), + { message: 'updateMany `update` parameter cannot be nullish' } + ); + }); + describe('insertOne() (gh-14843)', function() { it('should insert a new document', async function() { const userSchema = new Schema({ diff --git a/test/query.test.js b/test/query.test.js index bca5f706cf..13b5b677b7 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -1962,7 +1962,7 @@ describe('Query', function() { }); schema.pre('deleteOne', { document: true, query: false }, async function() { - await this.constructor.updateOne({ isDeleted: true }); + await this.updateOne({ isDeleted: true }); this.$isDeleted(true); }); diff --git a/types/models.d.ts b/types/models.d.ts index 8f5a94a059..a81d95f7fa 100644 --- a/types/models.d.ts +++ b/types/models.d.ts @@ -883,17 +883,20 @@ declare module 'mongoose' { /** Creates a `updateMany` query: updates all documents that match `filter` with `update`. */ updateMany( - filter?: RootFilterQuery, - update?: UpdateQuery | UpdateWithAggregationPipeline, + filter: RootFilterQuery, + update: UpdateQuery | UpdateWithAggregationPipeline, options?: (mongodb.UpdateOptions & MongooseUpdateQueryOptions) | null ): QueryWithHelpers; /** Creates a `updateOne` query: updates the first document that matches `filter` with `update`. */ updateOne( - filter?: RootFilterQuery, - update?: UpdateQuery | UpdateWithAggregationPipeline, + filter: RootFilterQuery, + update: UpdateQuery | UpdateWithAggregationPipeline, options?: (mongodb.UpdateOptions & MongooseUpdateQueryOptions) | null ): QueryWithHelpers; + updateOne( + update: UpdateQuery | UpdateWithAggregationPipeline + ): QueryWithHelpers; /** Creates a Query, applies the passed conditions, and returns the Query. */ where( diff --git a/types/query.d.ts b/types/query.d.ts index fbebf1b646..78df823f5c 100644 --- a/types/query.d.ts +++ b/types/query.d.ts @@ -850,20 +850,26 @@ declare module 'mongoose' { * the `multi` option. */ updateMany( - filter?: RootFilterQuery, - update?: UpdateQuery | UpdateWithAggregationPipeline, + filter: RootFilterQuery, + update: UpdateQuery | UpdateWithAggregationPipeline, options?: QueryOptions | null ): QueryWithHelpers; + updateMany( + update: UpdateQuery | UpdateWithAggregationPipeline + ): QueryWithHelpers; /** * Declare and/or execute this query as an updateOne() operation. Same as * `update()`, except it does not support the `multi` or `overwrite` options. */ updateOne( - filter?: RootFilterQuery, - update?: UpdateQuery | UpdateWithAggregationPipeline, + filter: RootFilterQuery, + update: UpdateQuery | UpdateWithAggregationPipeline, options?: QueryOptions | null ): QueryWithHelpers; + updateOne( + update: UpdateQuery | UpdateWithAggregationPipeline + ): QueryWithHelpers; /** * Sets the specified number of `mongod` servers, or tag set of `mongod` servers,