Skip to content

Commit 66915ea

Browse files
committed
Merge branch 'master' into vkarpov15/gh-15671
2 parents 8fb36bf + daa978d commit 66915ea

File tree

5 files changed

+53
-18
lines changed

5 files changed

+53
-18
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,29 @@ View all 400+ [contributors](https://github.com/Automattic/mongoose/graphs/contr
4242

4343
First install [Node.js](http://nodejs.org/) and [MongoDB](https://www.mongodb.org/downloads). Then:
4444

45+
Then install the `mongoose` package using your preferred package manager:
46+
47+
### Using npm
48+
4549
```sh
4650
npm install mongoose
4751
```
52+
### Using pnpm
53+
54+
```sh
55+
pnpm add mongoose
56+
```
57+
### Using Yarn
58+
59+
```sh
60+
yarn add mongoose
61+
```
62+
### Using Bun
63+
64+
```sh
65+
bun add mongoose
66+
```
67+
4868

4969
Mongoose 6.8.0 also includes alpha support for [Deno](https://deno.land/).
5070

lib/helpers/query/castUpdate.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,13 @@ function walkUpdatePath(schema, obj, op, options, context, filter, prefix) {
379379
(utils.isObject(val) && Object.keys(val).length === 0);
380380
}
381381
} else {
382-
const checkPath = (key === '$each' || key === '$or' || key === '$and' || key === '$in') ?
383-
prefix : prefix + key;
382+
const isModifier = (key === '$each' || key === '$or' || key === '$and' || key === '$in');
383+
if (isModifier && !prefix) {
384+
throw new MongooseError('Invalid update: Unexpected modifier "' + key + '" as a key in operator. '
385+
+ 'Did you mean something like { $addToSet: { fieldName: { $each: [...] } } }? '
386+
+ 'Modifiers such as "$each", "$or", "$and", "$in" must appear under a valid field path.');
387+
}
388+
const checkPath = isModifier ? prefix : prefix + key;
384389
schematype = schema._getSchema(checkPath);
385390

386391
// You can use `$setOnInsert` with immutable keys

lib/helpers/update/castArrayFilters.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ const updatedPathsByArrayFilter = require('./updatedPathsByArrayFilter');
77

88
module.exports = function castArrayFilters(query) {
99
const arrayFilters = query.options.arrayFilters;
10+
if (!Array.isArray(arrayFilters)) {
11+
return;
12+
}
1013
const update = query.getUpdate();
1114
const schema = query.schema;
1215
const updatedPathsByFilter = updatedPathsByArrayFilter(update);
@@ -29,10 +32,6 @@ module.exports = function castArrayFilters(query) {
2932
};
3033

3134
function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilter, query) {
32-
if (!Array.isArray(arrayFilters)) {
33-
return;
34-
}
35-
3635
// Map to store discriminator values for embedded documents in the array filters.
3736
// This is used to handle cases where array filters target specific embedded document types.
3837
const discriminatorValueMap = {};
Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
'use strict';
22

3-
const modifiedPaths = require('./modifiedPaths');
4-
53
/**
64
* Decorate the update with a version key, if necessary
75
* @api private
@@ -12,15 +10,26 @@ module.exports = function decorateUpdateWithVersionKey(update, options, versionK
1210
return;
1311
}
1412

15-
const updatedPaths = modifiedPaths(update);
16-
if (!updatedPaths[versionKey]) {
17-
if (options.overwrite) {
13+
if (options.overwrite) {
14+
if (!hasKey(update, versionKey)) {
1815
update[versionKey] = 0;
19-
} else {
20-
if (!update.$setOnInsert) {
21-
update.$setOnInsert = {};
22-
}
23-
update.$setOnInsert[versionKey] = 0;
2416
}
17+
} else if (
18+
!hasKey(update, versionKey) &&
19+
!hasKey(update?.$set, versionKey) &&
20+
!hasKey(update?.$inc, versionKey) &&
21+
!hasKey(update?.$setOnInsert, versionKey)
22+
) {
23+
if (!update.$setOnInsert) {
24+
update.$setOnInsert = {};
25+
}
26+
update.$setOnInsert[versionKey] = 0;
2527
}
2628
};
29+
30+
function hasKey(obj, key) {
31+
if (obj == null || typeof obj !== 'object') {
32+
return false;
33+
}
34+
return Object.prototype.hasOwnProperty.call(obj, key);
35+
}

test/model.updateOne.test.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3195,8 +3195,10 @@ describe('model: updateOne: ', function() {
31953195
const Model = db.model('Test', schema);
31963196

31973197
await Model.create({ tags: [] });
3198-
// This is a no-op, but should not cause an error
3199-
await Model.updateOne({}, { $addToSet: { $each: ['test'] } });
3198+
await assert.rejects(
3199+
Model.updateOne({}, { $addToSet: { $each: ['test'] } }),
3200+
/Modifiers such as "\$each", "\$or", "\$and", "\$in" must appear under a valid field path/
3201+
);
32003202
});
32013203
});
32023204

0 commit comments

Comments
 (0)