Skip to content

Commit a0aaa82

Browse files
authored
Merge branch 'master' into gh6750
2 parents 8af7c86 + 88457b0 commit a0aaa82

13 files changed

+233
-81
lines changed

docs/schematypes.jade

+8-8
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ block content
174174
* `trim`: boolean, whether to always call `.trim()` on the value
175175
* `match`: RegExp, creates a [validator](./validation.html) that checks if the value matches the given regular expression
176176
* `enum`: Array, creates a [validator](./validation.html) that checks if the value is in the given array.
177-
* `minlength`: Number, creates a [validator](./validation.html) that checks if the value length is not less then the given number
178-
* `maxlength`: Number, creates a [validator](./validation.html) that checks if the value length is not greater then the given number
177+
* `minlength`: Number, creates a [validator](./validation.html) that checks if the value length is not less than the given number
178+
* `maxlength`: Number, creates a [validator](./validation.html) that checks if the value length is not greater than the given number
179179

180180
<h5>Number</h5>
181181

@@ -266,7 +266,7 @@ block content
266266
console.log(mongoose.Schema.Types.Boolean.convertToFalse);
267267

268268
mongoose.Schema.Types.Boolean.convertToFalse.add('nay');
269-
console.log(new M({ b: 'nay' }).b); // true
269+
console.log(new M({ b: 'nay' }).b); // false
270270
```
271271

272272
<h4 id="arrays">Arrays</h4>
@@ -278,10 +278,10 @@ block content
278278

279279
```javascript
280280
var ToySchema = new Schema({ name: String });
281-
var ToyBox = new Schema({
281+
var ToyBoxSchema = new Schema({
282282
toys: [ToySchema],
283283
buffers: [Buffer],
284-
string: [String],
284+
strings: [String],
285285
numbers: [Number]
286286
// ... etc
287287
});
@@ -290,14 +290,14 @@ block content
290290
Arrays are special because they implicitly have a default value of `[]` (empty array).
291291

292292
```javascript
293-
var Toy = mongoose.model('Test', ToySchema);
294-
console.log((new Toy()).toys); // []
293+
var ToyBox = mongoose.model('ToyBox', ToyBoxSchema);
294+
console.log((new ToyBox()).toys); // []
295295
```
296296

297297
To overwrite this default, you need to set the default value to `undefined`
298298

299299
```javascript
300-
var ToySchema = new Schema({
300+
var ToyBoxSchema = new Schema({
301301
toys: {
302302
type: [ToySchema],
303303
default: undefined

docs/transactions.jade

+11
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ block content
4646
[require:transactions.*save]
4747
```
4848

49+
## With the Aggregation Framework
50+
51+
The `Model.aggregate()` function also supports transactions. Mongoose
52+
aggregations have a [`session()` helper](/docs/api.html#aggregate_Aggregate-session)
53+
that sets the [`session` option](/docs/api.html#aggregate_Aggregate-option).
54+
Below is an example of executing an aggregation within a transaction.
55+
56+
```javascript
57+
[require:transactions.*aggregate]
58+
```
59+
4960
block append layout
5061
script.
5162
_native.init("CK7DT53U", {

lib/aggregate.js

+22
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,27 @@ Aggregate.prototype.hint = function(value) {
633633
return this;
634634
};
635635

636+
/**
637+
* Sets the session for this aggregation. Useful for [transactions](/docs/transactions.html).
638+
*
639+
* ####Example:
640+
*
641+
* const session = await Model.startSession();
642+
* await Model.aggregate(..).session(session);
643+
*
644+
* @param {ClientSession} session
645+
* @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
646+
*/
647+
648+
Aggregate.prototype.session = function(session) {
649+
if (session == null) {
650+
delete this.options.session;
651+
return;
652+
}
653+
this.options.session = session;
654+
return this;
655+
};
656+
636657
/**
637658
* Lets you set arbitrary options, for middleware or plugins.
638659
*
@@ -645,6 +666,7 @@ Aggregate.prototype.hint = function(value) {
645666
* @param [options.maxTimeMS] number limits the time this aggregation will run, see [MongoDB docs on `maxTimeMS`](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/)
646667
* @param [options.allowDiskUse] boolean if true, the MongoDB server will use the hard drive to store data during this aggregation
647668
* @param [options.collation] object see [`Aggregate.prototype.collation()`](./docs/api.html#aggregate_Aggregate-collation)
669+
* @param [options.session] ClientSession see [`Aggregate.prototype.session()`](./docs/api.html#aggregate_Aggregate-session)
648670
* @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
649671
* @return {Aggregate} this
650672
* @api public

lib/connection.js

+7
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,13 @@ Connection.prototype.openUri = function(uri, options, callback) {
413413
options = null;
414414
}
415415

416+
if (['string', 'number'].indexOf(typeof options) !== -1) {
417+
throw new MongooseError('Mongoose 5.x no longer supports ' +
418+
'`mongoose.connect(host, dbname, port)` or ' +
419+
'`mongoose.createConnection(host, dbname, port)`. See ' +
420+
'http://mongoosejs.com/docs/connections.html for supported connection syntax');
421+
}
422+
416423
const Promise = PromiseProvider.get();
417424
const _this = this;
418425

lib/document.js

+11
Original file line numberDiff line numberDiff line change
@@ -2757,6 +2757,17 @@ Document.prototype.populate = function populate() {
27572757
populateOptions.path = nestedPath + '.' + populateOptions.path;
27582758
});
27592759
}
2760+
2761+
// Use `$session()` by default if the document has an associated session
2762+
// See gh-6754
2763+
if (this.$session() != null) {
2764+
const session = this.$session();
2765+
paths.forEach(path => {
2766+
path.options = path.options || {};
2767+
path.options.session = session;
2768+
});
2769+
}
2770+
27602771
topLevelModel.populate(this, paths, fn);
27612772
}
27622773

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
/*!
4+
* Apply query middleware
5+
*
6+
* @param {Query} query constructor
7+
* @param {Model} model
8+
*/
9+
10+
module.exports = function applyQueryMiddleware(Query, model) {
11+
const kareemOptions = {
12+
useErrorHandlers: true,
13+
numCallbackParams: 1,
14+
nullResultByDefault: true
15+
};
16+
17+
// `update()` thunk has a different name because `_update` was already taken
18+
Query.prototype._execUpdate = model.hooks.createWrapper('update',
19+
Query.prototype._execUpdate, null, kareemOptions);
20+
21+
[
22+
'count',
23+
'countDocuments',
24+
'estimatedDocumentCount',
25+
'find',
26+
'findOne',
27+
'findOneAndDelete',
28+
'findOneAndRemove',
29+
'findOneAndUpdate',
30+
'replaceOne',
31+
'updateMany',
32+
'updateOne'
33+
].forEach(fn => {
34+
Query.prototype[`_${fn}`] = model.hooks.createWrapper(fn,
35+
Query.prototype[`_${fn}`], null, kareemOptions);
36+
});
37+
};

lib/index.js

-3
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,6 @@ Mongoose.prototype.get = Mongoose.prototype.set;
158158
* var opts = { replset: { strategy: 'ping', rs_name: 'testSet' }}
159159
* db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database', opts);
160160
*
161-
* // with [host, database_name[, port] signature
162-
* db = mongoose.createConnection('localhost', 'database', port)
163-
*
164161
* // and options
165162
* var opts = { server: { auto_reconnect: false }, user: 'username', pass: 'mypassword' }
166163
* db = mongoose.createConnection('localhost', 'database', port, opts)

lib/model.js

+35-69
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,41 @@
44
* Module dependencies.
55
*/
66

7-
var Aggregate = require('./aggregate');
8-
var ChangeStream = require('./cursor/ChangeStream');
9-
var Document = require('./document');
10-
var DocumentNotFoundError = require('./error').DocumentNotFoundError;
11-
var DivergentArrayError = require('./error').DivergentArrayError;
12-
var Error = require('./error');
13-
var EventEmitter = require('events').EventEmitter;
14-
var MongooseMap = require('./types/map');
15-
var OverwriteModelError = require('./error').OverwriteModelError;
16-
var PromiseProvider = require('./promise_provider');
17-
var Query = require('./query');
18-
var Schema = require('./schema');
19-
var VersionError = require('./error').VersionError;
20-
var ParallelSaveError = require('./error').ParallelSaveError;
21-
var applyHooks = require('./helpers/model/applyHooks');
22-
var applyMethods = require('./helpers/model/applyMethods');
23-
var applyStatics = require('./helpers/model/applyStatics');
24-
var applyWriteConcern = require('./helpers/schema/applyWriteConcern');
25-
var cast = require('./cast');
26-
var castUpdate = require('./helpers/query/castUpdate');
27-
var discriminator = require('./helpers/model/discriminator');
28-
var getDiscriminatorByValue = require('./queryhelpers').getDiscriminatorByValue;
29-
var immediate = require('./helpers/immediate');
30-
var internalToObjectOptions = require('./options').internalToObjectOptions;
31-
var isPathSelectedInclusive = require('./helpers/projection/isPathSelectedInclusive');
32-
var get = require('lodash.get');
33-
var getSchemaTypes = require('./helpers/populate/getSchemaTypes');
34-
var getVirtual = require('./helpers/populate/getVirtual');
35-
var modifiedPaths = require('./helpers/update/modifiedPaths');
36-
var mpath = require('mpath');
37-
var parallel = require('async/parallel');
38-
var parallelLimit = require('async/parallelLimit');
39-
var setDefaultsOnInsert = require('./helpers/setDefaultsOnInsert');
40-
var utils = require('./utils');
7+
const Aggregate = require('./aggregate');
8+
const ChangeStream = require('./cursor/ChangeStream');
9+
const Document = require('./document');
10+
const DocumentNotFoundError = require('./error').DocumentNotFoundError;
11+
const DivergentArrayError = require('./error').DivergentArrayError;
12+
const Error = require('./error');
13+
const EventEmitter = require('events').EventEmitter;
14+
const MongooseMap = require('./types/map');
15+
const OverwriteModelError = require('./error').OverwriteModelError;
16+
const PromiseProvider = require('./promise_provider');
17+
const Query = require('./query');
18+
const Schema = require('./schema');
19+
const VersionError = require('./error').VersionError;
20+
const ParallelSaveError = require('./error').ParallelSaveError;
21+
const applyQueryMiddleware = require('./helpers/query/applyQueryMiddleware');
22+
const applyHooks = require('./helpers/model/applyHooks');
23+
const applyMethods = require('./helpers/model/applyMethods');
24+
const applyStatics = require('./helpers/model/applyStatics');
25+
const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
26+
const cast = require('./cast');
27+
const castUpdate = require('./helpers/query/castUpdate');
28+
const discriminator = require('./helpers/model/discriminator');
29+
const getDiscriminatorByValue = require('./queryhelpers').getDiscriminatorByValue;
30+
const immediate = require('./helpers/immediate');
31+
const internalToObjectOptions = require('./options').internalToObjectOptions;
32+
const isPathSelectedInclusive = require('./helpers/projection/isPathSelectedInclusive');
33+
const get = require('lodash.get');
34+
const getSchemaTypes = require('./helpers/populate/getSchemaTypes');
35+
const getVirtual = require('./helpers/populate/getVirtual');
36+
const modifiedPaths = require('./helpers/update/modifiedPaths');
37+
const mpath = require('mpath');
38+
const parallel = require('async/parallel');
39+
const parallelLimit = require('async/parallelLimit');
40+
const setDefaultsOnInsert = require('./helpers/setDefaultsOnInsert');
41+
const utils = require('./utils');
4142

4243
const VERSION_WHERE = 1;
4344
const VERSION_INC = 2;
@@ -4380,41 +4381,6 @@ function applyQueryMethods(model, methods) {
43804381
}
43814382
}
43824383

4383-
/*!
4384-
* Apply query middleware
4385-
*
4386-
* @param {Model} model
4387-
*/
4388-
4389-
function applyQueryMiddleware(Query, model) {
4390-
const kareemOptions = {
4391-
useErrorHandlers: true,
4392-
numCallbackParams: 1,
4393-
nullResultByDefault: true
4394-
};
4395-
4396-
// `update()` thunk has a different name because `_update` was already taken
4397-
Query.prototype._execUpdate = model.hooks.createWrapper('update',
4398-
Query.prototype._execUpdate, null, kareemOptions);
4399-
4400-
[
4401-
'count',
4402-
'countDocuments',
4403-
'estimatedDocumentCount',
4404-
'find',
4405-
'findOne',
4406-
'findOneAndDelete',
4407-
'findOneAndRemove',
4408-
'findOneAndUpdate',
4409-
'replaceOne',
4410-
'updateMany',
4411-
'updateOne'
4412-
].forEach(fn => {
4413-
Query.prototype[`_${fn}`] = model.hooks.createWrapper(fn,
4414-
Query.prototype[`_${fn}`], null, kareemOptions);
4415-
});
4416-
}
4417-
44184384
/*!
44194385
* Subclass this model with `conn`, `schema`, and `collection` settings.
44204386
*

lib/types/map.js

+4
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ class MongooseMap extends Map {
9090
return new Map(this);
9191
}
9292

93+
toObject() {
94+
return new Map(this);
95+
}
96+
9397
toJSON() {
9498
let ret = {};
9599
const keys = this.keys();

lib/utils.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,10 @@ exports.isMongooseObject = function(v) {
482482
return false;
483483
}
484484

485-
return v.$__ != null || v.isMongooseArray || v.isMongooseBuffer;
485+
return v.$__ != null || // Document
486+
v.isMongooseArray || // Array or Document Array
487+
v.isMongooseBuffer || // Buffer
488+
v.$isMongooseMap; // Map
486489
};
487490
var isMongooseObject = exports.isMongooseObject;
488491

test/connection.test.js

+7
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ describe('connections:', function() {
5656
}).catch(done);
5757
});
5858

59+
it('throws helpful error with legacy syntax (gh-6756)', function(done) {
60+
assert.throws(function() {
61+
mongoose.createConnection('localhost', 'dbname', 27017);
62+
}, /mongoosejs\.com.*connections\.html/);
63+
done();
64+
});
65+
5966
it('resolving with q (gh-5714)', function(done) {
6067
var bootMongo = Q.defer();
6168

0 commit comments

Comments
 (0)