Skip to content

Commit fa05375

Browse files
authored
Merge pull request Automattic#15199 from Automattic/vkarpov15/Automatticgh-15190
fix(model): disallow `updateMany(update)` and fix TypeScript types re: `updateMany()`
2 parents 3e4ba3f + acbb613 commit fa05375

File tree

7 files changed

+51
-13
lines changed

7 files changed

+51
-13
lines changed

lib/model.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3982,6 +3982,10 @@ Model.hydrate = function(obj, projection, options) {
39823982
* res.upsertedId; // null or an id containing a document that had to be upserted.
39833983
* res.upsertedCount; // Number indicating how many documents had to be upserted. Will either be 0 or 1.
39843984
*
3985+
* // Other supported syntaxes
3986+
* await Person.find({ name: /Stark$/ }).updateMany({ isDeleted: true }); // Using chaining syntax
3987+
* await Person.find().updateMany({ isDeleted: true }); // Set `isDeleted` on _all_ Person documents
3988+
*
39853989
* This function triggers the following middleware.
39863990
*
39873991
* - `updateMany()`
@@ -4002,10 +4006,14 @@ Model.hydrate = function(obj, projection, options) {
40024006
* @api public
40034007
*/
40044008

4005-
Model.updateMany = function updateMany(conditions, doc, options) {
4009+
Model.updateMany = function updateMany(conditions, update, options) {
40064010
_checkContext(this, 'updateMany');
40074011

4008-
return _update(this, 'updateMany', conditions, doc, options);
4012+
if (update == null) {
4013+
throw new MongooseError('updateMany `update` parameter cannot be nullish');
4014+
}
4015+
4016+
return _update(this, 'updateMany', conditions, update, options);
40094017
};
40104018

40114019
/**
@@ -4022,6 +4030,10 @@ Model.updateMany = function updateMany(conditions, doc, options) {
40224030
* res.upsertedId; // null or an id containing a document that had to be upserted.
40234031
* res.upsertedCount; // Number indicating how many documents had to be upserted. Will either be 0 or 1.
40244032
*
4033+
* // Other supported syntaxes
4034+
* await Person.findOne({ name: 'Jean-Luc Picard' }).updateOne({ ship: 'USS Enterprise' }); // Using chaining syntax
4035+
* await Person.updateOne({ ship: 'USS Enterprise' }); // Updates first doc's `ship` property
4036+
*
40254037
* This function triggers the following middleware.
40264038
*
40274039
* - `updateOne()`

lib/query.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3992,6 +3992,10 @@ Query.prototype._replaceOne = async function _replaceOne() {
39923992
* res.n; // Number of documents matched
39933993
* res.nModified; // Number of documents modified
39943994
*
3995+
* // Other supported syntaxes
3996+
* await Person.find({ name: /Stark$/ }).updateMany({ isDeleted: true }); // Using chaining syntax
3997+
* await Person.find().updateMany({ isDeleted: true }); // Set `isDeleted` on _all_ Person documents
3998+
*
39953999
* This function triggers the following middleware.
39964000
*
39974001
* - `updateMany()`
@@ -4062,6 +4066,10 @@ Query.prototype.updateMany = function(conditions, doc, options, callback) {
40624066
* res.upsertedCount; // Number of documents that were upserted
40634067
* res.upsertedId; // Identifier of the inserted document (if an upsert took place)
40644068
*
4069+
* // Other supported syntaxes
4070+
* await Person.findOne({ name: 'Jean-Luc Picard' }).updateOne({ ship: 'USS Enterprise' }); // Using chaining syntax
4071+
* await Person.updateOne({ ship: 'USS Enterprise' }); // Updates first doc's `ship` property
4072+
*
40654073
* This function triggers the following middleware.
40664074
*
40674075
* - `updateOne()`

test/model.middleware.preposttypes.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ describe('pre/post hooks, type of this', function() {
288288
await Doc.findOneAndReplace({}, { data: 'valueRep' }).exec();
289289
await Doc.findOneAndUpdate({}, { data: 'valueUpd' }).exec();
290290
await Doc.replaceOne({}, { data: 'value' }).exec();
291-
await Doc.updateOne({ data: 'value' }).exec();
292-
await Doc.updateMany({ data: 'value' }).exec();
291+
await Doc.updateOne({}, { data: 'value' }).exec();
292+
await Doc.updateMany({}, { data: 'value' }).exec();
293293

294294
// MongooseQueryOrDocumentMiddleware, use Query
295295
await Doc.deleteOne({}).exec(); await Doc.create({ data: 'value' });

test/model.test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8505,6 +8505,15 @@ describe('Model', function() {
85058505
});
85068506
});
85078507

8508+
it('throws error if calling `updateMany()` with no update param (gh-15190)', async function() {
8509+
const Test = db.model('Test', mongoose.Schema({ foo: String }));
8510+
8511+
assert.throws(
8512+
() => Test.updateMany({ foo: 'bar' }),
8513+
{ message: 'updateMany `update` parameter cannot be nullish' }
8514+
);
8515+
});
8516+
85088517
describe('insertOne() (gh-14843)', function() {
85098518
it('should insert a new document', async function() {
85108519
const userSchema = new Schema({

test/query.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1962,7 +1962,7 @@ describe('Query', function() {
19621962
});
19631963

19641964
schema.pre('deleteOne', { document: true, query: false }, async function() {
1965-
await this.constructor.updateOne({ isDeleted: true });
1965+
await this.updateOne({ isDeleted: true });
19661966
this.$isDeleted(true);
19671967
});
19681968

types/models.d.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -883,17 +883,20 @@ declare module 'mongoose' {
883883

884884
/** Creates a `updateMany` query: updates all documents that match `filter` with `update`. */
885885
updateMany<ResultDoc = THydratedDocumentType>(
886-
filter?: RootFilterQuery<TRawDocType>,
887-
update?: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
886+
filter: RootFilterQuery<TRawDocType>,
887+
update: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
888888
options?: (mongodb.UpdateOptions & MongooseUpdateQueryOptions<TRawDocType>) | null
889889
): QueryWithHelpers<UpdateWriteOpResult, ResultDoc, TQueryHelpers, TRawDocType, 'updateMany', TInstanceMethods & TVirtuals>;
890890

891891
/** Creates a `updateOne` query: updates the first document that matches `filter` with `update`. */
892892
updateOne<ResultDoc = THydratedDocumentType>(
893-
filter?: RootFilterQuery<TRawDocType>,
894-
update?: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
893+
filter: RootFilterQuery<TRawDocType>,
894+
update: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
895895
options?: (mongodb.UpdateOptions & MongooseUpdateQueryOptions<TRawDocType>) | null
896896
): QueryWithHelpers<UpdateWriteOpResult, ResultDoc, TQueryHelpers, TRawDocType, 'updateOne', TInstanceMethods & TVirtuals>;
897+
updateOne<ResultDoc = THydratedDocumentType>(
898+
update: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline
899+
): QueryWithHelpers<UpdateWriteOpResult, ResultDoc, TQueryHelpers, TRawDocType, 'updateOne', TInstanceMethods & TVirtuals>;
897900

898901
/** Creates a Query, applies the passed conditions, and returns the Query. */
899902
where<ResultDoc = THydratedDocumentType>(

types/query.d.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -850,20 +850,26 @@ declare module 'mongoose' {
850850
* the `multi` option.
851851
*/
852852
updateMany(
853-
filter?: RootFilterQuery<RawDocType>,
854-
update?: UpdateQuery<RawDocType> | UpdateWithAggregationPipeline,
853+
filter: RootFilterQuery<RawDocType>,
854+
update: UpdateQuery<RawDocType> | UpdateWithAggregationPipeline,
855855
options?: QueryOptions<DocType> | null
856856
): QueryWithHelpers<UpdateWriteOpResult, DocType, THelpers, RawDocType, 'updateMany', TDocOverrides>;
857+
updateMany(
858+
update: UpdateQuery<RawDocType> | UpdateWithAggregationPipeline
859+
): QueryWithHelpers<UpdateWriteOpResult, DocType, THelpers, RawDocType, 'updateMany', TDocOverrides>;
857860

858861
/**
859862
* Declare and/or execute this query as an updateOne() operation. Same as
860863
* `update()`, except it does not support the `multi` or `overwrite` options.
861864
*/
862865
updateOne(
863-
filter?: RootFilterQuery<RawDocType>,
864-
update?: UpdateQuery<RawDocType> | UpdateWithAggregationPipeline,
866+
filter: RootFilterQuery<RawDocType>,
867+
update: UpdateQuery<RawDocType> | UpdateWithAggregationPipeline,
865868
options?: QueryOptions<DocType> | null
866869
): QueryWithHelpers<UpdateWriteOpResult, DocType, THelpers, RawDocType, 'updateOne', TDocOverrides>;
870+
updateOne(
871+
update: UpdateQuery<RawDocType> | UpdateWithAggregationPipeline
872+
): QueryWithHelpers<UpdateWriteOpResult, DocType, THelpers, RawDocType, 'updateOne', TDocOverrides>;
867873

868874
/**
869875
* Sets the specified number of `mongod` servers, or tag set of `mongod` servers,

0 commit comments

Comments
 (0)