Skip to content

Commit

Permalink
Merge branch '5.11' into gh-8108
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Oct 23, 2020
2 parents 649172d + 5e9a95f commit 59f7332
Show file tree
Hide file tree
Showing 23 changed files with 493 additions and 99 deletions.
8 changes: 8 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
5.10.10 / 2020-10-23
====================
* fix(schema): handle merging schemas from separate Mongoose module instances when schema has a virtual #9471
* fix(connection): make connection.then(...) resolve to a connection instance #9497 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
* fix(aggregate): when using $search with discriminators, add `$match` as the 2nd stage in pipeline rather than 1st #9487
* fix(query): cast $nor within $elemMatch #9479
* docs(connection): add note about 'error' event versus 'disconnected' event #9488 [tareqdayya](https://github.com/tareqdayya)

5.10.9 / 2020-10-09
===================
* fix(update): strip out unused array filters to avoid "filter was not used in the update" error #9468
Expand Down
8 changes: 6 additions & 2 deletions docs/connections.pug
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ block content
});
```

Note that the `error` event in the code above does not fire when mongoose loses
connection after the initial connection was established. You can listen to the
`disconnected` event for that purpose.

<h3 id="options"><a href="#options">Options</a></h3>

The `connect` method also accepts an `options` object which will be passed
Expand All @@ -158,8 +162,8 @@ block content
Mongoose passes options to the driver without modification, modulo a few
exceptions that are explained below.

* `bufferCommands` - This is a mongoose-specific option (not passed to the MongoDB driver) that disables [mongoose's buffering mechanism](http://mongoosejs.com/docs/faq.html#callback_never_executes)
* `user`/`pass` - The username and password for authentication. These options are mongoose-specific, they are equivalent to the MongoDB driver's `auth.user` and `auth.password` options.
* `bufferCommands` - This is a mongoose-specific option (not passed to the MongoDB driver) that disables [Mongoose's buffering mechanism](http://mongoosejs.com/docs/faq.html#callback_never_executes)
* `user`/`pass` - The username and password for authentication. These options are Mongoose-specific, they are equivalent to the MongoDB driver's `auth.user` and `auth.password` options.
* `autoIndex` - By default, mongoose will automatically build indexes defined in your schema when it connects. This is great for development, but not ideal for large production deployments, because index builds can cause performance degradation. If you set `autoIndex` to false, mongoose will not automatically build indexes for **any** model associated with this connection.
* `dbName` - Specifies which database to connect to and overrides any database specified in the connection string. This is useful if you are unable to specify a default database in the connection string like with [some `mongodb+srv` syntax connections](https://stackoverflow.com/questions/48917591/fail-to-connect-mongoose-to-atlas/48917626#48917626).

Expand Down
24 changes: 12 additions & 12 deletions docs/faq.pug
Original file line number Diff line number Diff line change
Expand Up @@ -311,26 +311,26 @@ block content
<a href="#callback_never_executes">**Q**</a>. My `save()` callback never executes. What am I doing wrong?

**A**. All `collection` actions (insert, remove, queries, etc.) are queued
until the `connection` opens. It is likely that an error occurred while
attempting to connect. Try adding an error handler to your connection.
until Mongoose successfully connects to MongoDB. It is likely you haven't called Mongoose's
`connect()` or `createConnection()` function yet.

```javascript
// if connecting on the default mongoose connection
mongoose.connect(..);
mongoose.connection.on('error', handleError);

// if connecting on a separate connection
const conn = mongoose.createConnection(..);
conn.on('error', handleError);
```
In Mongoose 5.11, there is a `bufferTimeoutMS` option (set to 10000 by default) that configures how long
Mongoose will allow an operation to stay buffered before throwing an error.

If you want to opt out of mongoose's buffering mechanism across your entire
If you want to opt out of Mongoose's buffering mechanism across your entire
application, set the global `bufferCommands` option to false:

```javascript
mongoose.set('bufferCommands', false);
```

Instead of opting out of Mongoose's buffering mechanism, you may want to instead reduce `bufferTimeoutMS`
to make Mongoose only buffer for a short time.

```javascript
// If an operation is buffered for more than 500ms, throw an error.
mongoose.set('bufferTimeoutMS', 500);
```

<hr id="creating_connections" />

Expand Down
11 changes: 11 additions & 0 deletions docs/guide.pug
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ block content
- [autoIndex](#autoIndex)
- [autoCreate](#autoCreate)
- [bufferCommands](#bufferCommands)
- [bufferTimeoutMS](#bufferTimeoutMS)
- [capped](#capped)
- [collection](#collection)
- [id](#id)
Expand Down Expand Up @@ -503,6 +504,16 @@ block content
const schema = new Schema({..}, { bufferCommands: false });
```

<h3 id="bufferTimeoutMS"><a href="#bufferTimeoutMS">option: bufferTimeoutMS</a></h3>

If `bufferCommands` is on, this option sets the maximum amount of time Mongoose buffering will wait before
throwing an error. If not specified, Mongoose will use 10000 (10 seconds).

```javascript
// If an operation is buffered for more than 1 second, throw an error.
const schema = new Schema({..}, { bufferTimeoutMS: 1000 });
```

<h3 id="capped"><a href="#capped">option: capped</a></h3>

Mongoose supports MongoDBs [capped](http://www.mongodb.org/display/DOCS/Capped+Collections)
Expand Down
5 changes: 1 addition & 4 deletions index.pug
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,6 @@ html(lang='en')
<a rel="sponsored" href="https://www.turtlebet.com/fi/kaikki-nettikasinot.html">
<img class="sponsor" src="https://images.opencollective.com/turtlebet-nettikasinot/4799a27/logo/256.png" style="height: 100px">
</a>
<a rel="sponsored" href="https://casinomatcher.com/ca/">
<img class="sponsor" src="https://images.opencollective.com/casinomatcher-com/31fbd0d/logo/256.png" style="height: 100px">
</a>
<a rel="sponsored" href="https://netticasinohex.com/kasinot/">
<img class="sponsor" src="https://images.opencollective.com/netticasinohex-com/71d7417/logo/256.png" style="height: 100px">
</a>
Expand Down Expand Up @@ -355,7 +352,7 @@ html(lang='en')
<a rel="sponsored" href="https://onlinecasinoguide.co.nz/">
<img class="sponsor" src="https://images.opencollective.com/onlinecasinoguide-co-nz/b16a388/logo/256.png" style="height: 100px">
</a>
<a rel="sponsored" href="https://casino-academia.com/">
<a rel="sponsored" href="https://casino-academia.jp/">
<img class="sponsor" src="https://images.opencollective.com/casinoacademia/90fc970/logo/256.png" style="height: 100px">
</a>
<a rel="sponsored" href="https://nettikasinolista.com/">
Expand Down
8 changes: 8 additions & 0 deletions lib/aggregate.js
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,14 @@ function prepareDiscriminatorPipeline(aggregate) {
originalPipeline[0].$geoNear.query =
originalPipeline[0].$geoNear.query || {};
originalPipeline[0].$geoNear.query[discriminatorKey] = discriminatorValue;
} else if (originalPipeline[0] && originalPipeline[0].$search) {
if (originalPipeline[1] && originalPipeline[1].$match != null) {
originalPipeline[1].$match[discriminatorKey] = originalPipeline[1].$match[discriminatorKey] || discriminatorValue;
} else {
const match = {};
match[discriminatorKey] = discriminatorValue;
originalPipeline.splice(1, 0, { $match: match });
}
} else {
const match = {};
match[discriminatorKey] = discriminatorValue;
Expand Down
40 changes: 40 additions & 0 deletions lib/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,23 @@ Collection.prototype.addQueue = function(name, args) {
return this;
};

/**
* Removes a queued method
*
* @param {String} name name of the method to queue
* @param {Array} args arguments to pass to the method when executed
* @api private
*/

Collection.prototype.removeQueue = function(name, args) {
const index = this.queue.findIndex(v => v[0] === name && v[1] === args);
if (index === -1) {
return false;
}
this.queue.splice(index, 1);
return true;
};

/**
* Executes all queued methods and clears the queue.
*
Expand Down Expand Up @@ -281,6 +298,29 @@ Collection.prototype._shouldBufferCommands = function _shouldBufferCommands() {
return true;
};

/*!
* ignore
*/

Collection.prototype._getBufferTimeoutMS = function _getBufferTimeoutMS() {
const conn = this.conn;
const opts = this.opts;

if (opts.bufferTimeoutMS != null) {
return opts.bufferTimeoutMS;
}
if (opts && opts.schemaUserProvidedOptions != null && opts.schemaUserProvidedOptions.bufferTimeoutMS != null) {
return opts.schemaUserProvidedOptions.bufferTimeoutMS;
}
if (conn.config.bufferTimeoutMS != null) {
return conn.config.bufferTimeoutMS;
}
if (conn.base != null && conn.base.get('bufferTimeoutMS') != null) {
return conn.base.get('bufferTimeoutMS');
}
return 10000;
};

/*!
* Module exports.
*/
Expand Down
3 changes: 2 additions & 1 deletion lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ Connection.prototype.onOpen = function() {
* @param {String} uri The URI to connect with.
* @param {Object} [options] Passed on to http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html#connect
* @param {Boolean} [options.bufferCommands=true] Mongoose specific option. Set to false to [disable buffering](http://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
* @param {Number} [options.bufferTimeoutMS=true] Mongoose specific option. If `bufferCommands` is true, Mongoose will throw an error after `bufferTimeoutMS` if the operation is still buffered.
* @param {String} [options.dbName] The name of the database we want to use. If not provided, use database name from connection string.
* @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
* @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
Expand Down Expand Up @@ -812,7 +813,7 @@ Connection.prototype.openUri = function(uri, options, callback) {
throw err;
});
this.then = function(resolve, reject) {
return this.$initialConnection.then(resolve, reject);
return this.$initialConnection.then(() => resolve(_this), reject);
};
this.catch = function(reject) {
return this.$initialConnection.catch(reject);
Expand Down
105 changes: 83 additions & 22 deletions lib/cursor/QueryCursor.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,40 +350,101 @@ function _next(ctx, cb) {
}

if (ctx.cursor) {
return ctx.cursor.next(function(error, doc) {
if (error) {
return callback(error);
}
if (!doc) {
if (ctx.query._mongooseOptions.populate && !ctx._pop) {
ctx._pop = helpers.preparePopulationOptionsMQ(ctx.query,
ctx.query._mongooseOptions);
ctx._pop.__noPromise = true;
}
if (ctx.query._mongooseOptions.populate && ctx.options.batchSize > 1) {
if (ctx._batchDocs && ctx._batchDocs.length) {
// Return a cached populated doc
return _nextDoc(ctx, ctx._batchDocs.shift(), ctx._pop, callback);
} else if (ctx._batchExhausted) {
// Internal cursor reported no more docs. Act the same here
return callback(null, null);
} else {
// Request as many docs as batchSize, to populate them also in batch
ctx._batchDocs = [];
return ctx.cursor.next(_onNext.bind({ ctx, callback }));
}
} else {
return ctx.cursor.next(function(error, doc) {
if (error) {
return callback(error);
}
if (!doc) {
return callback(null, null);
}

const opts = ctx.query._mongooseOptions;
if (!opts.populate) {
return opts.lean ?
callback(null, doc) :
_create(ctx, doc, null, callback);
}

const pop = helpers.preparePopulationOptionsMQ(ctx.query,
ctx.query._mongooseOptions);
pop.__noPromise = true;
ctx.query.model.populate(doc, pop, function(err, doc) {
if (err) {
return callback(err);
if (!ctx.query._mongooseOptions.populate) {
return _nextDoc(ctx, doc, null, callback);
}
return opts.lean ?
callback(null, doc) :
_create(ctx, doc, pop, callback);

ctx.query.model.populate(doc, ctx._pop, function(err, doc) {
if (err) {
return callback(err);
}
return _nextDoc(ctx, doc, ctx._pop, callback);
});
});
});
}
} else {
ctx.once('cursor', function() {
_next(ctx, cb);
});
}
}

/*!
* ignore
*/

function _onNext(error, doc) {
if (error) {
return this.callback(error);
}
if (!doc) {
this.ctx._batchExhausted = true;
return _populateBatch.call(this);
}

this.ctx._batchDocs.push(doc);

if (this.ctx._batchDocs.length < this.ctx.options.batchSize) {
this.ctx.cursor.next(_onNext.bind(this));
} else {
_populateBatch.call(this);
}
}

/*!
* ignore
*/

function _populateBatch() {
if (!this.ctx._batchDocs.length) {
return this.callback(null, null);
}
const _this = this;
this.ctx.query.model.populate(this.ctx._batchDocs, this.ctx._pop, function(err) {
if (err) {
return _this.callback(err);
}

_nextDoc(_this.ctx, _this.ctx._batchDocs.shift(), _this.ctx._pop, _this.callback);
});
}

/*!
* ignore
*/

function _nextDoc(ctx, doc, pop, callback) {
return ctx.query._mongooseOptions.lean ?
callback(null, doc) :
_create(ctx, doc, pop, callback);
}

/*!
* ignore
*/
Expand Down
25 changes: 24 additions & 1 deletion lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,16 @@ Document.prototype.$set = function $set(path, val, type, options) {

if (pathType === 'nested' && val) {
if (typeof val === 'object' && val != null) {
const hasPriorVal = this.$__.savedState != null && this.$__.savedState.hasOwnProperty(path);
if (this.$__.savedState != null && !this.isNew && !this.$__.savedState.hasOwnProperty(path)) {
this.$__.savedState[path] = this.$__getValue(path);

const keys = Object.keys(this.$__.savedState[path]);
for (const key of keys) {
this.$__.savedState[path + '.' + key] = this.$__.savedState[path][key];
}
}

if (!merge) {
this.$__setValue(path, null);
cleanModifiedSubpaths(this, path);
Expand All @@ -1055,7 +1065,12 @@ Document.prototype.$set = function $set(path, val, type, options) {
for (const key of keys) {
this.$set(path + '.' + key, val[key], constructing);
}
this.markModified(path);

if (hasPriorVal && utils.deepEqual(this.$__.savedState[path], val)) {
this.unmarkModified(path);
} else {
this.markModified(path);
}
cleanModifiedSubpaths(this, path, { skipDocArrays: true });
return this;
}
Expand Down Expand Up @@ -1301,6 +1316,14 @@ Document.prototype.$set = function $set(path, val, type, options) {

if (shouldSet) {
this.$__set(pathToMark, path, constructing, parts, schema, val, priorVal);

if (this.$__.savedState != null) {
if (!this.isNew && !this.$__.savedState.hasOwnProperty(path)) {
this.$__.savedState[path] = priorVal;
} else if (this.$__.savedState.hasOwnProperty(path) && utils.deepEqual(val, this.$__.savedState[path])) {
this.unmarkModified(path);
}
}
}

if (schema.$isSingleNested && (this.isDirectModified(path) || val == null)) {
Expand Down
Loading

0 comments on commit 59f7332

Please sign in to comment.