Skip to content

Commit 8d61a7d

Browse files
committed
Merge branch '8.0' into vkarpov15/gh-13897
2 parents c5b16fe + f923f6c commit 8d61a7d

File tree

124 files changed

+2394
-2881
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+2394
-2881
lines changed

.eslintrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ module.exports = {
2323
'**/*.md/*.ts',
2424
'**/*.md/*.typescript'
2525
],
26+
parserOptions: {
27+
project: './tsconfig.json'
28+
},
2629
extends: [
2730
'plugin:@typescript-eslint/eslint-recommended',
2831
'plugin:@typescript-eslint/recommended'

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
- name: Setup node
2828
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
2929
with:
30-
node-version: 14
30+
node-version: 18
3131

3232
- run: npm install
3333

@@ -39,7 +39,7 @@ jobs:
3939
strategy:
4040
fail-fast: false
4141
matrix:
42-
node: [14, 16, 18, 20]
42+
node: [16, 18, 20]
4343
os: [ubuntu-20.04, ubuntu-22.04]
4444
mongodb: [4.4.18, 5.0.14, 6.0.4]
4545
include:
@@ -108,7 +108,7 @@ jobs:
108108
- name: Setup Deno
109109
uses: denoland/setup-deno@v1
110110
with:
111-
deno-version: v1.34.x
111+
deno-version: v1.36.x
112112
- run: deno --version
113113
- run: npm install
114114
- name: Run Deno tests

.github/workflows/tsd.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
- name: Setup node
2828
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
2929
with:
30-
node-version: 14
30+
node-version: 18
3131

3232
- run: npm install
3333

docs/middleware.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ In query middleware functions, `this` refers to the query.
4848
* [find](api/query.html#query_Query-find)
4949
* [findOne](api/query.html#query_Query-findOne)
5050
* [findOneAndDelete](api/query.html#query_Query-findOneAndDelete)
51-
* [findOneAndRemove](api/query.html#query_Query-findOneAndRemove)
5251
* [findOneAndReplace](api/query.html#query_Query-findOneAndReplace)
5352
* [findOneAndUpdate](api/query.html#query_Query-findOneAndUpdate)
5453
* [remove](api/model.html#model_Model-remove)
@@ -81,7 +80,6 @@ Here are the possible strings that can be passed to `pre()`
8180
* find
8281
* findOne
8382
* findOneAndDelete
84-
* findOneAndRemove
8583
* findOneAndReplace
8684
* findOneAndUpdate
8785
* init

docs/migrating_to_8.md

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
# Migrating from 7.x to 8.x
2+
3+
<style>
4+
ul > li {
5+
padding: 4px 0px;
6+
}
7+
</style>
8+
9+
There are several backwards-breaking changes
10+
you should be aware of when migrating from Mongoose 7.x to Mongoose 8.x.
11+
12+
If you're still on Mongoose 6.x or earlier, please read the [Mongoose 6.x to 7.x migration guide](migrating_to_7.html) and upgrade to Mongoose 7.x first before upgrading to Mongoose 8.
13+
14+
* [Removed `rawResult` option for `findOneAndUpdate()`](#removed-rawresult-option-for-findoneandupdate)
15+
* [`Document.prototype.deleteOne()` now returns a query](#document-prototype-deleteone-now-returns-a-query)
16+
* [MongoDB Node Driver 6.0](#mongodb-node-driver-6)
17+
* [Removed `findOneAndRemove()`](#removed-findoneandremove)
18+
* [Removed `count()`](#removed-count)
19+
* [Removed id Setter](#removed-id-setter)
20+
* [`null` is valid for non-required string enums](#null-is-valid-for-non-required-string-enums)
21+
* [Apply minimize when `save()` updates an existing document](#apply-minimize-when-save-updates-an-existing-document)
22+
* [Apply base schema paths before discriminator paths](#apply-base-schema-paths-before-discriminator-paths)
23+
* [Removed `overwrite` option for `findOneAndUpdate()`](#removed-overwrite-option-for-findoneandupdate)
24+
* [Changed behavior for `findOneAndUpdate()` with `orFail()` and upsert](#changed-behavior-for-findoneandupdate-with-orfail-and-upsert)
25+
* [`create()` waits until all saves are done before throwing any error](#create-waits-until-all-saves-are-done-before-throwing-any-error)
26+
* [`Model.validate()` returns copy of object](#model-validate-returns-copy-of-object)
27+
* [Allow `null` For Optional Fields in TypeScript](#allow-null-for-optional-fields-in-typescript)
28+
* [Infer `distinct()` return types from schema](#infer-distinct-return-types-from-schema)
29+
30+
<h2 id="removed-rawresult-option-for-findoneandupdate"><a href="#removed-rawresult-option-for-findoneandupdate">Removed <code>rawResult</code> option for <code>findOneAndUpdate()</code></a></h2>
31+
32+
The `rawResult` option for `findOneAndUpdate()`, `findOneAndReplace()`, and `findOneAndDelete()` has been replaced by the `includeResultMetadata` option.
33+
34+
```javascript
35+
const filter = { name: 'Will Riker' };
36+
const update = { age: 29 };
37+
38+
const res = await Character.findOneAndUpdate(filter, update, {
39+
new: true,
40+
upsert: true,
41+
// Replace `rawResult: true` with `includeResultMetadata: true`
42+
includeResultMetadata: true
43+
});
44+
```
45+
46+
`includeResultMetadata` in Mongoose 8 behaves identically to `rawResult`.
47+
48+
<h2 id="document-prototype-deleteone-now-returns-a-query"><a href="#document-prototype-deleteone-now-returns-a-query"><code>Document.prototype.deleteOne</code> now returns a query</a></h2>
49+
50+
In Mongoose 7, `doc.deleteOne()` returned a promise that resolved to `doc`.
51+
In Mongoose 8, `doc.deleteOne()` returns a query for easier chaining, as well as consistency with `doc.updateOne()`.
52+
53+
```javascript
54+
const numberOne = await Character.findOne({ name: 'Will Riker' });
55+
56+
// In Mongoose 7, q is a Promise that resolves to `numberOne`
57+
// In Mongoose 8, q is a Query.
58+
const q = numberOne.deleteOne();
59+
60+
// In Mongoose 7, `res === numberOne`
61+
// In Mongoose 8, `res` is a `DeleteResult`.
62+
const res = await q;
63+
```
64+
65+
<h2 id="mongodb-node-driver-6"><a href="#mongodb-node-driver-6">MongoDB Node Driver 6</a></h2>
66+
67+
Mongoose 8 uses [v6.x of the MongoDB Node driver](https://github.com/mongodb/node-mongodb-native/blob/main/HISTORY.md#600-2023-08-28).
68+
There's a few noteable changes in MongoDB Node driver v6 that affect Mongoose:
69+
70+
1. The `ObjectId` constructor no longer accepts strings of length 12. In Mongoose 7, `new mongoose.Types.ObjectId('12charstring')` was perfectly valid. In Mongoose 8, `new mongoose.Types.ObjectId('12charstring')` throws an error.
71+
72+
<h2 id="removed-findoneandremove"><a href="#removed-findoneandremove">Removed <code>findOneAndRemove()</code></a></h2>
73+
74+
In Mongoose 7, `findOneAndRemove()` was an alias for `findOneAndDelete()` that Mongoose supported for backwards compatibility.
75+
Mongoose 8 no longer supports `findOneAndRemove()`.
76+
Use `findOneAndDelete()` instead.
77+
78+
<h2 id="removed-count"><a href="#removed-count">Removed <code>count()</code></a></h2>
79+
80+
`Model.count()` and `Query.prototype.count()` were removed in Mongoose 8. Use `Model.countDocuments()` and `Query.prototype.countDocuments()` instead.
81+
82+
<h2 id="removed-id-setter"><a href="#removed-id-setter">Removed id Setter</a></h2>
83+
84+
In Mongoose 7.4, Mongoose introduced an `id` setter that made `doc.id = '0'.repeat(24)` equivalent to `doc._id = '0'.repeat(24)`.
85+
In Mongoose 8, that setter is now removed.
86+
87+
<h2 id="null-is-valid-for-non-required-string-enums"><a href="#null-is-valid-for-non-required-string-enums"><code>null</code> is valid for non-required string enums</a></h2>
88+
89+
Before Mongoose 8, setting a string path with an `enum` to `null` would lead to a validation error, even if that path wasn't `required`.
90+
In Mongoose 8, it is valid to set a string path to `null` if `required` is not set, even with `enum`.
91+
92+
```javascript
93+
const schema = new Schema({
94+
status: {
95+
type: String,
96+
enum: ['on', 'off']
97+
}
98+
});
99+
const Test = mongoose.model('Test', schema);
100+
101+
// Works fine in Mongoose 8
102+
// Throws a `ValidationError` in Mongoose 7
103+
await Test.create({ status: null });
104+
```
105+
106+
<h2 id="apply-minimize-when-save-updates-an-existing-document"><a href="#apply-minimize-when-save-updates-an-existing-document">Apply minimize when <code>save()</code> updates an existing document</a></h2>
107+
108+
In Mongoose 7, Mongoose would only apply minimize when saving a new document, not when updating an existing document.
109+
110+
```javascript
111+
const schema = new Schema({
112+
nested: {
113+
field1: Number
114+
}
115+
});
116+
const Test = mongoose.model('Test', schema);
117+
118+
// Both Mongoose 7 and Mongoose 8 strip out empty objects when saving
119+
// a new document in MongoDB by default
120+
const { _id } = await Test.create({ nested: {} });
121+
let rawDoc = await Test.findById(_id).lean();
122+
rawDoc.nested; // undefined
123+
124+
// Mongoose 8 will also strip out empty objects when saving an
125+
// existing document in MongoDB
126+
const doc = await Test.findById(_id);
127+
doc.nested = {};
128+
doc.markModified('nested');
129+
await doc.save();
130+
131+
let rawDoc = await Test.findById(_id).lean();
132+
rawDoc.nested; // undefined in Mongoose 8, {} in Mongoose 7
133+
```
134+
135+
<h2 id="apply-base-schema-paths-before-discriminator-paths"><a href="#apply-base-schema-paths-before-discriminator-paths">Apply base schema paths before discriminator paths</a></h2>
136+
137+
This means that, in Mongoose 8, getters and setters on discriminator paths run *after* getters and setters on base paths.
138+
In Mongoose 7, getters and setters on discriminator paths ran *before* getters and setters on base paths.
139+
140+
```javascript
141+
142+
const schema = new Schema({
143+
name: {
144+
type: String,
145+
get(v) {
146+
console.log('Base schema getter');
147+
return v;
148+
}
149+
}
150+
});
151+
152+
const Test = mongoose.model('Test', schema);
153+
const D = Test.discriminator('D', new Schema({
154+
otherProp: {
155+
type: String,
156+
get(v) {
157+
console.log('Discriminator schema getter');
158+
return v;
159+
}
160+
}
161+
}));
162+
163+
const doc = new D({ name: 'test', otherProp: 'test' });
164+
// In Mongoose 8, prints "Base schema getter" followed by "Discriminator schema getter"
165+
// In Mongoose 7, prints "Discriminator schema getter" followed by "Base schema getter"
166+
console.log(doc.toObject({ getters: true }));
167+
```
168+
169+
<h2 id="removed-overwrite-option-for-findoneandupdate"><a href="#removed-overwrite-option-for-findoneandupdate">Removed <code>overwrite</code> option for <code>findOneAndUpdate()</code></a></h2>
170+
171+
Mongoose 7 and earlier supported an `overwrite` option for `findOneAndUpdate()`, `updateOne()`, and `update()`.
172+
Before Mongoose 7, `overwrite` would skip wrapping the `update` parameter in `$set`, which meant that `findOneAndUpdate()` and `update()` would overwrite the matched document.
173+
In Mongoose 7, setting `overwrite` would convert `findOneAndUpdate()` to `findOneAndReplace()` and `updateOne()` to `replaceOne()` to retain backwards compatibility.
174+
175+
In Mongoose 8, the `overwrite` option is no longer supported.
176+
If you want to overwrite the entire document, use `findOneAndReplace()` or `replaceOne()`.
177+
178+
<h2 id="changed-behavior-for-findoneandupdate-with-orfail-and-upsert"><a href="#changed-behavior-for-findoneandupdate-with-orfail-and-upsert">Changed behavior for <code>findOneAndUpdate()</code> with <code>orFail()</code> and upsert</a></h2>
179+
180+
In Mongoose 7, `findOneAndUpdate(filter, update, { upsert: true }).orFail()` would throw a `DocumentNotFoundError` if a new document was upserted.
181+
In other words, `findOneAndUpdate().orFail()` always threw an error if no document was found, even if a new document was upserted.
182+
183+
In Mongoose 8, `findOneAndUpdate(filter, update, { upsert: true }).orFail()` always succeeds.
184+
`findOneAndUpdate().orFail()` now throws a `DocumentNotFoundError` if there's no document returned, rather than if no document was found.
185+
186+
<h2 id="create-waits-until-all-saves-are-done-before-throwing-any-error"><a href="#create-waits-until-all-saves-are-done-before-throwing-any-error"><code>create()</code> waits until all saves are done before throwing any error</a></h2>
187+
188+
In Mongoose 7, `create()` would immediately throw if any `save()` threw an error by default.
189+
Mongoose 8 instead waits for all `save()` calls to finish before throwing the first error that occurred.
190+
So `create()` will throw the same error in both Mongoose 7 and Mongoose 8, Mongoose 8 just may take longer to throw the error.
191+
192+
```javascript
193+
const schema = new Schema({
194+
name: {
195+
type: String,
196+
enum: ['Badger', 'Mushroom']
197+
}
198+
});
199+
schema.pre('save', async function() {
200+
await new Promise(resolve => setTimeout(resolve, 1000));
201+
});
202+
const Test = mongoose.model('Test', schema);
203+
204+
const err = await Test.create([
205+
{ name: 'Badger' },
206+
{ name: 'Mushroom' },
207+
{ name: 'Cow' }
208+
]).then(() => null, err => err);
209+
err; // ValidationError
210+
211+
// In Mongoose 7, there would be 0 documents, because `Test.create()`
212+
// would throw before 'Badger' and 'Mushroom' are inserted
213+
// In Mongoose 8, there will be 2 documents. `Test.create()` waits until
214+
// 'Badger' and 'Mushroom' are inserted before throwing.
215+
await Test.countDocuments();
216+
```
217+
218+
<h2 id="model-validate-returns-copy-of-object"><a href="#model-validate-returns-copy-of-object"><code>Model.validate()</code> returns copy of object</a></h2>
219+
220+
In Mongoose 7, `Model.validate()` would potentially modify the passed in object.
221+
Mongoose 8 instead copies the passed in object first.
222+
223+
```javascript
224+
const schema = new Schema({ answer: Number });
225+
const Test = mongoose.model('Test', schema);
226+
227+
const obj = { answer: '42' };
228+
const res = Test.validate(obj);
229+
230+
typeof obj.answer; // 'string' in Mongoose 8, 'number' in Mongoose 7
231+
typeof res.answer; // 'number' in both Mongoose 7 and Mongoose 8
232+
```
233+
234+
<h2 id="allow-null-for-optional-fields-in-typescript"><a href="#allow-null-for-optional-fields-in-typescript">Allow <code>null</code> For Optional Fields in TypeScript</a></h2>
235+
236+
In Mongoose 8, automatically inferred schema types in TypeScript allow `null` for optional fields.
237+
In Mongoose 7, optional fields only allowed `undefined`, not `null`.
238+
239+
```typescript
240+
const schema = new Schema({ name: String });
241+
const TestModel = model('Test', schema);
242+
243+
const doc = new TestModel();
244+
245+
// In Mongoose 8, this type is `string | null | undefined`.
246+
// In Mongoose 7, this type is `string | undefined`
247+
doc.name;
248+
```
249+
250+
<h2 id="infer-distinct-return-types-from-schema"><a href="#infer-distinct-return-types-from-schema">Infer <code>distinct()</code> return types from schema</a></h2>
251+
252+
```ts
253+
interface User {
254+
name: string;
255+
email: string;
256+
avatar?: string;
257+
}
258+
const schema = new Schema<User>({
259+
name: { type: String, required: true },
260+
email: { type: String, required: true },
261+
avatar: String
262+
});
263+
264+
// Works in Mongoose 8. Compile error in Mongoose 7.
265+
const names: string[] = await MyModel.distinct('name');
266+
```

docs/models.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ If you attempt to `save()` a document from a View, you will get an error from th
193193

194194
## Yet more
195195

196-
The [API docs](api/model.html#model_Model) cover many additional methods available like [count](api/model.html#model_Model-count), [mapReduce](api/model.html#model_Model-mapReduce), [aggregate](api/model.html#model_Model-aggregate), and [more](api/model.html#model_Model-findOneAndRemove).
196+
The [API docs](api/model.html#model_Model) cover many additional methods available like [count](api/model.html#model_Model-count), [mapReduce](api/model.html#model_Model-mapReduce), [aggregate](api/model.html#model_Model-aggregate), and more.
197197

198198
## Next Up
199199

docs/queries.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Each of these functions returns a
1414
* [`Model.findByIdAndUpdate()`](api.html#model_Model-findByIdAndUpdate)
1515
* [`Model.findOne()`](api.html#model_Model-findOne)
1616
* [`Model.findOneAndDelete()`](api.html#model_Model-findOneAndDelete)
17-
* [`Model.findOneAndRemove()`](api.html#model_Model-findOneAndRemove)
1817
* [`Model.findOneAndReplace()`](api.html#model_Model-findOneAndReplace)
1918
* [`Model.findOneAndUpdate()`](api.html#model_Model-findOneAndUpdate)
2019
* [`Model.replaceOne()`](api.html#model_Model-replaceOne)

docs/source/api.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,30 @@ const files = [
1515
'lib/document.js',
1616
'lib/model.js',
1717
'lib/query.js',
18-
'lib/cursor/QueryCursor.js',
18+
'lib/cursor/queryCursor.js',
1919
'lib/aggregate.js',
20-
'lib/cursor/AggregationCursor.js',
21-
'lib/schematype.js',
22-
'lib/virtualtype.js',
20+
'lib/cursor/aggregationCursor.js',
21+
'lib/schemaType.js',
22+
'lib/virtualType.js',
2323
'lib/error/index.js',
2424
'lib/schema/array.js',
25-
'lib/schema/documentarray.js',
26-
'lib/schema/SubdocumentPath.js',
25+
'lib/schema/documentArray.js',
26+
'lib/schema/subdocument.js',
2727
'lib/schema/boolean.js',
2828
'lib/schema/buffer.js',
2929
'lib/schema/number.js',
30-
'lib/schema/objectid.js',
30+
'lib/schema/objectId.js',
3131
'lib/schema/string.js',
32-
'lib/options/SchemaTypeOptions.js',
33-
'lib/options/SchemaArrayOptions.js',
34-
'lib/options/SchemaBufferOptions.js',
35-
'lib/options/SchemaDateOptions.js',
36-
'lib/options/SchemaNumberOptions.js',
37-
'lib/options/SchemaObjectIdOptions.js',
38-
'lib/options/SchemaStringOptions.js',
39-
'lib/types/DocumentArray/methods/index.js',
32+
'lib/options/schemaTypeOptions.js',
33+
'lib/options/schemaArrayOptions.js',
34+
'lib/options/schemaBufferOptions.js',
35+
'lib/options/schemaDateOptions.js',
36+
'lib/options/schemaNumberOptions.js',
37+
'lib/options/schemaObjectIdOptions.js',
38+
'lib/options/schemaStringOptions.js',
39+
'lib/types/documentArray/methods/index.js',
4040
'lib/types/subdocument.js',
41-
'lib/types/ArraySubdocument.js',
41+
'lib/types/arraySubdocument.js',
4242
'lib/types/buffer.js',
4343
'lib/types/decimal128.js',
4444
'lib/types/map.js',

0 commit comments

Comments
 (0)