Skip to content

Commit 53f6fc0

Browse files
Merge branch 'Automattic:master' into docs-union-schema-type
2 parents c2dabd0 + ee6a377 commit 53f6fc0

File tree

9 files changed

+60
-34
lines changed

9 files changed

+60
-34
lines changed

docs/connections.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,15 +208,13 @@ for (let i = 0; i < 3; ++i) {
208208
}
209209
```
210210

211-
## Callback {#callback}
211+
## Using Promises and Async/Await {#promises-async-await}
212212

213-
The `connect()` function also accepts a callback parameter and returns a
214-
[promise](promises.html).
213+
The `connect()` function returns a [promise](promises.html).
215214

216215
```javascript
217-
mongoose.connect(uri, options, function(error) {
218-
// Check error in initial connection. There is no 2nd param to the callback.
219-
});
216+
// Using async/await. The `mongoose.connect()` promise resolves to mongoose instance.
217+
await mongoose.connect(uri, options);
220218

221219
// Or using promises
222220
mongoose.connect(uri, options).then(

docs/faq.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,13 @@ For more debugging options (streams, callbacks), see the ['debug' option under `
254254

255255
<hr id="callback_never_executes" />
256256

257-
<a class="anchor" href="#callback_never_executes">**Q**</a>. My `save()` callback never executes. What am I doing wrong?
257+
<a class="anchor" href="#callback_never_executes">**Q**</a>. My `save()` operation never completes. What am I doing wrong?
258258

259259
**A**. All `collection` actions (insert, remove, queries, etc.) are queued
260260
until Mongoose successfully connects to MongoDB. It is likely you haven't called Mongoose's
261261
`connect()` or `createConnection()` function yet.
262262

263-
In Mongoose 5.11, there is a `bufferTimeoutMS` option (set to 10000 by default) that configures how long
263+
Mongoose connections support a `bufferTimeoutMS` option (set to 10000 by default) that configures how long
264264
Mongoose will allow an operation to stay buffered before throwing an error.
265265

266266
If you want to opt out of Mongoose's buffering mechanism across your entire
@@ -408,28 +408,28 @@ mind that populate() will execute a separate query for each document.
408408

409409
<a class="anchor" href="#duplicate-query">**Q**</a>. My query/update seems to execute twice. Why is this happening?
410410

411-
**A**. The most common cause of duplicate queries is **mixing callbacks and promises with queries**.
412-
That's because passing a callback to a query function, like `find()` or `updateOne()`,
413-
immediately executes the query, and calling [`then()`](https://masteringjs.io/tutorials/fundamentals/then)
414-
executes the query again.
415-
416-
Mixing promises and callbacks can lead to duplicate entries in arrays.
417-
For example, the below code inserts 2 entries into the `tags` array, **not* just 1.
411+
**A**. The most common cause of duplicate queries is **executing the same query object twice**.
412+
Calling [`then()`](https://masteringjs.io/tutorials/fundamentals/then) or `await` on the same query object
413+
multiple times will execute the query multiple times.
418414

419415
```javascript
420416
const BlogPost = mongoose.model('BlogPost', new Schema({
421417
title: String,
422418
tags: [String]
423419
}));
424420

425-
// Because there's both `await` **and** a callback, this `updateOne()` executes twice
426-
// and thus pushes the same string into `tags` twice.
427-
const update = { $push: { tags: ['javascript'] } };
428-
await BlogPost.updateOne({ title: 'Introduction to Promises' }, update, (err, res) => {
429-
console.log(res);
430-
});
421+
// This will throw 'Query was already executed' error
422+
const query = BlogPost.findOne({ title: 'Introduction to Promises' });
423+
await query;
424+
await query; // Error! Query already executed
425+
426+
// To execute the same query twice, use clone()
427+
await query.clone(); // Works
431428
```
432429

430+
Note: Mongoose v7+ no longer supports callbacks. If you're seeing duplicate queries in older code,
431+
it may be due to mixing callbacks and promises, which is no longer possible in current versions.
432+
433433
<hr id="add_something" />
434434

435435
**Something to add?**

docs/guide.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,10 +1059,12 @@ schema.path('name').validate(function(value) {
10591059
});
10601060
const M = mongoose.model('Person', schema);
10611061
const m = new M({ name: null });
1062-
m.validate(function(err) {
1062+
try {
1063+
await m.validate();
1064+
} catch (err) {
10631065
console.log(err); // Will tell you that null is not allowed.
1064-
});
1065-
m.save(); // Succeeds despite being invalid
1066+
}
1067+
await m.save(); // Succeeds despite being invalid
10661068
```
10671069

10681070
## option: versionKey {#versionKey}

docs/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fluffy.speak(); // "Meow name is fluffy"
8888
```
8989

9090
We have talking kittens! But we still haven't saved anything to MongoDB.
91-
Each document can be saved to the database by calling its [save](api/model.html#model_Model-save) method. The first argument to the callback will be an error if any occurred.
91+
Each document can be saved to the database by calling its [save](api/model.html#model_Model-save) method.
9292

9393
```javascript
9494
await fluffy.save();
@@ -111,7 +111,7 @@ await Kitten.find({ name: /^fluff/ });
111111
```
112112

113113
This performs a search for all documents with a name property that begins
114-
with "fluff" and returns the result as an array of kittens to the callback.
114+
with "fluff" and returns the result as an array of kittens.
115115

116116
## Congratulations
117117

docs/middleware.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,11 @@ schema.pre('save', async function() {
217217
// later...
218218

219219
// Changes will not be persisted to MongoDB because a pre hook errored out
220-
myDoc.save(function(err) {
220+
try {
221+
await myDoc.save();
222+
} catch (err) {
221223
console.log(err.message); // something went wrong
222-
});
224+
}
223225
```
224226

225227
Calling `next()` multiple times is a no-op. If you call `next()` with an

docs/queries.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@ Each of these functions returns a
2020
* [`Model.updateMany()`](api.html#model_Model-updateMany)
2121
* [`Model.updateOne()`](api.html#model_Model-updateOne)
2222

23-
A mongoose query can be executed in one of two ways. First, if you
24-
pass in a `callback` function, Mongoose will execute the query asynchronously
25-
and pass the results to the `callback`.
26-
27-
A query also has a `.then()` function, and thus can be used as a promise.
23+
Mongoose queries can be executed by using `await`, or by using `.then()` to handle the promise returned by the query.
2824

2925
<ul class="toc">
3026
<li><a href="#executing">Executing</a></li>

lib/schema.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,10 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
16941694
`\`${name}\` is not a valid type within the array \`${path}\`.` +
16951695
'See https://bit.ly/mongoose-schematypes for a list of valid schema types.');
16961696
}
1697+
1698+
if (name === 'Union' && typeof cast === 'object') {
1699+
cast.parentSchema = this;
1700+
}
16971701
}
16981702

16991703
return new MongooseTypes.Array(path, cast || MongooseTypes.Mixed, obj, options);

test/schema.union.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,28 @@ describe('Union', function() {
134134
const doc2FromDb = await TestModel.collection.findOne({ _id: doc2._id });
135135
assert.strictEqual(doc2FromDb.test, 'bbb');
136136
});
137+
138+
it('handles arrays of unions (gh-15718)', async function() {
139+
const schema = new Schema({
140+
arr: [{
141+
type: 'Union',
142+
of: [Number, Date]
143+
}]
144+
});
145+
const TestModel = db.model('Test', schema);
146+
147+
const numValue = 42;
148+
const dateValue = new Date('2025-06-01');
149+
150+
const doc = new TestModel({
151+
arr: [numValue, dateValue]
152+
});
153+
154+
await doc.save();
155+
156+
const found = await TestModel.collection.findOne({ _id: doc._id });
157+
assert.strictEqual(found.arr.length, 2);
158+
assert.strictEqual(found.arr[0], numValue);
159+
assert.strictEqual(new Date(found.arr[1]).valueOf(), dateValue.valueOf());
160+
});
137161
});

types/models.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ declare module 'mongoose' {
2020
name: string | number,
2121
schema: Schema<T, U>,
2222
value?: string | number | ObjectId | DiscriminatorOptions
23-
): U;
23+
): Model<U>;
2424
}
2525

2626
export type MongooseBulkWriteResult = mongodb.BulkWriteResult & {

0 commit comments

Comments
 (0)