Skip to content

Commit 75e1dd8

Browse files
committed
Merge branch '7.x'
2 parents 8330f1e + 3cfd3f6 commit 75e1dd8

File tree

5 files changed

+47
-10
lines changed

5 files changed

+47
-10
lines changed

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
* fix: fix missing Aggregate re-exports for ESM #14886 [wongsean](https://github.com/wongsean)
55
* types(document): add generic param to depopulate() to allow updating properties #14891 #14876
66

7+
6.13.2 / 2024-09-12
8+
===================
9+
* fix(document): make set() respect merge option on deeply nested objects #14870 #14878
10+
711
8.6.2 / 2024-09-11
812
==================
913
* fix: make set merge deeply nested objects #14870 #14861 [ianHeydoc](https://github.com/ianHeydoc)
@@ -114,6 +118,7 @@
114118
==================
115119
* feat(model): add throwOnValidationError option for opting into getting MongooseBulkWriteError if all valid operations succeed in bulkWrite() and insertMany() #14599 #14587 #14572 #13410
116120

121+
<<<<<<< HEAD
117122
8.4.3 / 2024-06-17
118123
==================
119124
* fix: remove 0x flamegraph files from release
@@ -126,6 +131,11 @@
126131
* fix(connection): fix up some inconsistencies in operation-end event and add to docs #14659 #14648
127132
* types: avoid inferring Boolean, Buffer, ObjectId as Date in schema definitions under certain circumstances #14667 #14630
128133
* docs: add note about parallelism in transations #14647 [fiws](https://github.com/fiws)
134+
=======
135+
6.13.1 / 2024-09-06
136+
===================
137+
* fix: remove empty $and, $or, $not that were made empty by scrict mode #14749 #13086 [0x0a0d](https://github.com/0x0a0d)
138+
>>>>>>> 7.x
129139

130140
6.13.0 / 2024-06-06
131141
===================
@@ -629,7 +639,7 @@
629639
==================
630640
* perf: speed up mapOfSubdocs benchmark by 4x by avoiding unnecessary O(n^2) loop in getPathsToValidate() #13614
631641
* feat: upgrade to MongoDB Node.js driver 5.7.0 #13591
632-
* feat: add `id` setter which allows modifying `_id` by setting `id` (Note this change was reverted in Mongoose 8) #13517
642+
* BREAKING CHANGE: add `id` setter which allows modifying `_id` by setting `id` (Note this change was originally shipped as a `feat`, but later reverted in Mongoose 8 due to compatibility issues) #13517
633643
* feat: support generating custom cast error message with a function #13608 #3162
634644
* feat(query): support MongoDB driver's includeResultMetadata option for findOneAndUpdate #13584 #13539
635645
* feat(connection): add Connection.prototype.removeDb() for removing a related connection #13580 #11821

docs/middleware.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ In document middleware functions, `this` refers to the document. To access the m
3131

3232
* [validate](api/document.html#document_Document-validate)
3333
* [save](api/model.html#model_Model-save)
34-
* [remove](api/model.html#model_Model-remove)
3534
* [updateOne](api/document.html#document_Document-updateOne)
3635
* [deleteOne](api/model.html#model_Model-deleteOne)
3736
* [init](api/document.html#document_Document-init) (note: init hooks are [synchronous](#synchronous))
@@ -50,7 +49,6 @@ In query middleware functions, `this` refers to the query.
5049
* [findOneAndDelete](api/query.html#query_Query-findOneAndDelete)
5150
* [findOneAndReplace](api/query.html#query_Query-findOneAndReplace)
5251
* [findOneAndUpdate](api/query.html#query_Query-findOneAndUpdate)
53-
* [remove](api/model.html#model_Model-remove)
5452
* [replaceOne](api/query.html#query_Query-replaceOne)
5553
* [updateOne](api/query.html#query_Query-updateOne)
5654
* [updateMany](api/query.html#query_Query-updateMany)
@@ -87,7 +85,6 @@ Here are the possible strings that can be passed to `pre()`
8785
* findOneAndUpdate
8886
* init
8987
* insertMany
90-
* remove
9188
* replaceOne
9289
* save
9390
* update
@@ -400,11 +397,11 @@ Mongoose has both query and document hooks for `deleteOne()`.
400397
```javascript
401398
schema.pre('deleteOne', function() { console.log('Removing!'); });
402399

403-
// Does **not** print "Removing!". Document middleware for `remove` is not executed by default
400+
// Does **not** print "Removing!". Document middleware for `deleteOne` is not executed by default
404401
await doc.deleteOne();
405402

406403
// Prints "Removing!"
407-
Model.remove();
404+
await Model.deleteOne();
408405
```
409406

410407
You can pass options to [`Schema.pre()`](api.html#schema_Schema-pre)
@@ -418,8 +415,8 @@ schema.pre('deleteOne', { document: true, query: false }, function() {
418415
console.log('Deleting doc!');
419416
});
420417

421-
// Only query middleware. This will get called when you do `Model.remove()`
422-
// but not `doc.remove()`.
418+
// Only query middleware. This will get called when you do `Model.deleteOne()`
419+
// but not `doc.deleteOne()`.
423420
schema.pre('deleteOne', { query: true, document: false }, function() {
424421
console.log('Deleting!');
425422
});

docs/subdocs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ doc.child;
3838
```
3939

4040
<ul class="toc">
41-
<li><a href="#what-is-a-subdocument-">What is a Subdocument?</a></li>
41+
<li><a href="#what-is-a-subdocument">What is a Subdocument?</a></li>
4242
<li><a href="#subdocuments-versus-nested-paths">Subdocuments versus Nested Paths</a></li>
4343
<li><a href="#subdocument-defaults">Subdocument Defaults</a></li>
4444
<li><a href="#finding-a-subdocument">Finding a Subdocument</a></li>

lib/cast.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,27 @@ module.exports = function cast(schema, obj, options, context) {
6565
if (!Array.isArray(val)) {
6666
throw new CastError('Array', val, path);
6767
}
68-
for (let k = 0; k < val.length; ++k) {
68+
for (let k = val.length - 1; k >= 0; k--) {
6969
if (val[k] == null || typeof val[k] !== 'object') {
7070
throw new CastError('Object', val[k], path + '.' + k);
7171
}
72+
const beforeCastKeysLength = Object.keys(val[k]).length;
7273
const discriminatorValue = val[k][schema.options.discriminatorKey];
7374
if (discriminatorValue == null) {
7475
val[k] = cast(schema, val[k], options, context);
7576
} else {
7677
const discriminatorSchema = getSchemaDiscriminatorByValue(context.schema, discriminatorValue);
7778
val[k] = cast(discriminatorSchema ? discriminatorSchema : schema, val[k], options, context);
7879
}
80+
81+
if (Object.keys(val[k]).length === 0 && beforeCastKeysLength !== 0) {
82+
val.splice(k, 1);
83+
}
84+
}
85+
86+
// delete empty: {$or: []} -> {}
87+
if (val.length === 0) {
88+
delete obj[path];
7989
}
8090
} else if (path === '$where') {
8191
type = typeof val;

test/docs/cast.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,26 @@ describe('Cast Tutorial', function() {
137137
// acquit:ignore:end
138138
});
139139

140+
it('strictQuery removes casted empty objects', async function() {
141+
mongoose.deleteModel('Character');
142+
const schema = new mongoose.Schema({ name: String, age: Number }, {
143+
strictQuery: true
144+
});
145+
Character = mongoose.model('Character', schema);
146+
147+
const query = Character.findOne({
148+
$or: [{ notInSchema: { $lt: 'not a number' } }],
149+
$and: [{ name: 'abc' }, { age: { $gt: 18 } }, { notInSchema: { $lt: 'not a number' } }],
150+
$nor: [{}] // should be kept
151+
});
152+
153+
await query.exec();
154+
query.getFilter(); // Empty object `{}`, Mongoose removes `notInSchema`
155+
// acquit:ignore:start
156+
assert.deepEqual(query.getFilter(), { $and: [{ name: 'abc' }, { age: { $gt: 18 } }], $nor: [{}] });
157+
// acquit:ignore:end
158+
});
159+
140160
it('implicit in', async function() {
141161
// Normally wouldn't find anything because `name` is a string, but
142162
// Mongoose automatically inserts `$in`

0 commit comments

Comments
 (0)