Skip to content

Commit 2a55ba1

Browse files
committed
fix(model): disallow updateMany(update) and fix TypeScript types re updateMany()
Fix Automattic#15190
1 parent 1020947 commit 2a55ba1

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
@@ -3878,6 +3878,10 @@ Model.hydrate = function(obj, projection, options) {
38783878
* res.upsertedId; // null or an id containing a document that had to be upserted.
38793879
* res.upsertedCount; // Number indicating how many documents had to be upserted. Will either be 0 or 1.
38803880
*
3881+
* // Other supported syntaxes
3882+
* await Person.find({ name: /Stark$/ }).updateMany({ isDeleted: true }); // Using chaining syntax
3883+
* await Person.find().updateMany({ isDeleted: true }); // Set `isDeleted` on _all_ Person documents
3884+
*
38813885
* This function triggers the following middleware.
38823886
*
38833887
* - `updateMany()`
@@ -3898,10 +3902,14 @@ Model.hydrate = function(obj, projection, options) {
38983902
* @api public
38993903
*/
39003904

3901-
Model.updateMany = function updateMany(conditions, doc, options) {
3905+
Model.updateMany = function updateMany(conditions, update, options) {
39023906
_checkContext(this, 'updateMany');
39033907

3904-
return _update(this, 'updateMany', conditions, doc, options);
3908+
if (update == null) {
3909+
throw new MongooseError('updateMany `update` parameter cannot be nullish');
3910+
}
3911+
3912+
return _update(this, 'updateMany', conditions, update, options);
39053913
};
39063914

39073915
/**
@@ -3918,6 +3926,10 @@ Model.updateMany = function updateMany(conditions, doc, options) {
39183926
* res.upsertedId; // null or an id containing a document that had to be upserted.
39193927
* res.upsertedCount; // Number indicating how many documents had to be upserted. Will either be 0 or 1.
39203928
*
3929+
* // Other supported syntaxes
3930+
* await Person.findOne({ name: 'Jean-Luc Picard' }).updateOne({ ship: 'USS Enterprise' }); // Using chaining syntax
3931+
* await Person.updateOne({ ship: 'USS Enterprise' }); // Updates first doc's `ship` property
3932+
*
39213933
* This function triggers the following middleware.
39223934
*
39233935
* - `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
@@ -8419,6 +8419,15 @@ describe('Model', function() {
84198419
assert.deepStrictEqual(toDrop, []);
84208420
});
84218421
});
8422+
8423+
it('throws error if calling `updateMany()` with no update param (gh-15190)', async function() {
8424+
const Test = db.model('Test', mongoose.Schema({ foo: String }));
8425+
8426+
assert.throws(
8427+
() => Test.updateMany({ foo: 'bar' }),
8428+
{ message: 'updateMany `update` parameter cannot be nullish' }
8429+
);
8430+
});
84228431
});
84238432

84248433

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
@@ -869,17 +869,20 @@ declare module 'mongoose' {
869869

870870
/** Creates a `updateMany` query: updates all documents that match `filter` with `update`. */
871871
updateMany<ResultDoc = THydratedDocumentType>(
872-
filter?: RootFilterQuery<TRawDocType>,
873-
update?: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
872+
filter: RootFilterQuery<TRawDocType>,
873+
update: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
874874
options?: (mongodb.UpdateOptions & MongooseUpdateQueryOptions<TRawDocType>) | null
875875
): QueryWithHelpers<UpdateWriteOpResult, ResultDoc, TQueryHelpers, TRawDocType, 'updateMany', TInstanceMethods & TVirtuals>;
876876

877877
/** Creates a `updateOne` query: updates the first document that matches `filter` with `update`. */
878878
updateOne<ResultDoc = THydratedDocumentType>(
879-
filter?: RootFilterQuery<TRawDocType>,
880-
update?: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
879+
filter: RootFilterQuery<TRawDocType>,
880+
update: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
881881
options?: (mongodb.UpdateOptions & MongooseUpdateQueryOptions<TRawDocType>) | null
882882
): QueryWithHelpers<UpdateWriteOpResult, ResultDoc, TQueryHelpers, TRawDocType, 'updateOne', TInstanceMethods & TVirtuals>;
883+
updateOne<ResultDoc = THydratedDocumentType>(
884+
update: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline
885+
): QueryWithHelpers<UpdateWriteOpResult, ResultDoc, TQueryHelpers, TRawDocType, 'updateOne', TInstanceMethods & TVirtuals>;
883886

884887
/** Creates a Query, applies the passed conditions, and returns the Query. */
885888
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)