mongoose 5.0.17 → 5.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +4 -3
- package/History.md +61 -0
- package/lib/aggregate.js +15 -4
- package/lib/connection.js +12 -0
- package/lib/document.js +79 -18
- package/lib/drivers/browser/objectid.js +12 -0
- package/lib/drivers/node-mongodb-native/collection.js +46 -35
- package/lib/error/version.js +4 -2
- package/lib/index.js +12 -7
- package/lib/internal.js +1 -0
- package/lib/model.js +329 -96
- package/lib/plugins/idGetter.js +0 -12
- package/lib/plugins/saveSubdocs.js +1 -1
- package/lib/query.js +202 -109
- package/lib/queryhelpers.js +59 -32
- package/lib/schema/array.js +6 -3
- package/lib/schema/date.js +5 -2
- package/lib/schema/decimal128.js +4 -0
- package/lib/schema/embedded.js +15 -9
- package/lib/schema/index.js +2 -0
- package/lib/schema/map.js +29 -0
- package/lib/schema/objectid.js +0 -20
- package/lib/schema.js +49 -9
- package/lib/schematype.js +19 -1
- package/lib/services/model/applyHooks.js +22 -2
- package/lib/services/model/applyMethods.js +14 -4
- package/lib/services/populate/getVirtual.js +4 -0
- package/lib/services/query/castUpdate.js +1 -1
- package/lib/services/query/completeMany.js +47 -0
- package/lib/types/buffer.js +1 -1
- package/lib/types/documentarray.js +16 -2
- package/lib/types/embedded.js +33 -1
- package/lib/types/index.js +2 -0
- package/lib/types/map.js +149 -0
- package/lib/types/objectid.js +12 -0
- package/lib/types/subdocument.js +30 -1
- package/lib/utils.js +49 -6
- package/migrating_to_5.md +1 -1
- package/package.json +5 -5
package/.travis.yml
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
language: node_js
|
|
2
2
|
sudo: false
|
|
3
3
|
node_js:
|
|
4
|
+
- "10"
|
|
4
5
|
- "9"
|
|
5
6
|
- "8"
|
|
6
7
|
- "7"
|
|
@@ -8,11 +9,11 @@ node_js:
|
|
|
8
9
|
- "5"
|
|
9
10
|
- "4"
|
|
10
11
|
before_script:
|
|
11
|
-
- wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.
|
|
12
|
-
- tar -zxvf mongodb-linux-x86_64-3.
|
|
12
|
+
- wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.4.tgz
|
|
13
|
+
- tar -zxvf mongodb-linux-x86_64-3.6.4.tgz
|
|
13
14
|
- mkdir -p ./data/db/27017
|
|
14
15
|
- mkdir -p ./data/db/27000
|
|
15
|
-
- ./mongodb-linux-x86_64-3.
|
|
16
|
+
- ./mongodb-linux-x86_64-3.6.4/bin/mongod --fork --nopreallocj --dbpath ./data/db/27017 --syslog --port 27017
|
|
16
17
|
script:
|
|
17
18
|
- npm test
|
|
18
19
|
- npm run lint
|
package/History.md
CHANGED
|
@@ -1,3 +1,64 @@
|
|
|
1
|
+
5.1.2 / 2018-05-21
|
|
2
|
+
==================
|
|
3
|
+
* docs(guide): add missing SchemaTypes #6490 [distancesprinter](https://github.com/distancesprinter)
|
|
4
|
+
* fix(map): make MongooseMap.toJSON return a serialized object #6486 #6478 [lineus](https://github.com/lineus)
|
|
5
|
+
* fix(query): make CustomQuery inherit from model.Query for hooks #6483 #6455 [lineus](https://github.com/lineus)
|
|
6
|
+
* fix(document): prevent default falses from being skipped by $__dirty #6481 #6477 [lineus](https://github.com/lineus)
|
|
7
|
+
* docs(connection): document `useDb()` #6480
|
|
8
|
+
* fix(model): skip redundant clone in insertMany #6479 [d1manson](https://github.com/d1manson)
|
|
9
|
+
* fix(aggregate): let replaceRoot accept objects as well as strings #6475 #6474 [lineus](https://github.com/lineus)
|
|
10
|
+
* docs(model): clarify `emit()` in mapReduce and how map/reduce are run #6465
|
|
11
|
+
* fix(populate): flatten array to handle multi-level nested `refPath` #6457
|
|
12
|
+
* fix(date): cast small numeric strings as years #6444 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
|
|
13
|
+
* fix(populate): remove unmatched ids when using virtual populate on already hydrated document #6435
|
|
14
|
+
* fix(array): use custom array class to avoid clobbered property names #6431
|
|
15
|
+
* fix(model): handle hooks for custom methods that return promises #6385
|
|
16
|
+
|
|
17
|
+
4.13.13 / 2018-05-17
|
|
18
|
+
====================
|
|
19
|
+
* fix(update): stop clobbering $in when casting update #6441 #6339
|
|
20
|
+
* fix: upgrade async -> 2.6.0 re: security warning
|
|
21
|
+
|
|
22
|
+
5.1.1 / 2018-05-14
|
|
23
|
+
==================
|
|
24
|
+
* docs(schema): add notes in api and guide about schema.methods object #6470 #6440 [lineus](https://github.com/lineus)
|
|
25
|
+
* fix(error): add modified paths to VersionError #6464 #6433 [paglias](https://github.com/paglias)
|
|
26
|
+
* fix(populate): only call populate with full param signature when match is not present #6458 #6451 [lineus](https://github.com/lineus)
|
|
27
|
+
* docs: fix geoNear link in migration guide #6450 [kawache](https://github.com/kawache)
|
|
28
|
+
* fix(discriminator): throw readable error when `create()` with a non-existent discriminator key #6434
|
|
29
|
+
* fix(populate): add `retainNullValues` option to avoid stripping out null keys #6432
|
|
30
|
+
* fix(populate): handle populate in embedded discriminators underneath nested paths #6411
|
|
31
|
+
* docs(model): add change streams and ToC, make terminology more consistent #5888
|
|
32
|
+
|
|
33
|
+
5.1.0 / 2018-05-10
|
|
34
|
+
==================
|
|
35
|
+
* feat(ObjectId): add `_id` getter so you can get a usable id whether or not the path is populated #6415 #6115
|
|
36
|
+
* feat(model): add Model.startSession() #6362
|
|
37
|
+
* feat(document): add doc.$session() and set session on doc after query #6362
|
|
38
|
+
* feat: add Map type that supports arbitrary keys #6287 #681
|
|
39
|
+
* feat: add `cloneSchemas` option to mongoose global to opt in to always cloning schemas before use #6274
|
|
40
|
+
* feat(model): add `findOneAndDelete()` and `findByIdAndDelete()` #6164
|
|
41
|
+
* feat(document): support `$ignore()` on single nested and array subdocs #6152
|
|
42
|
+
* feat(document): add warning about calling `save()` on subdocs #6152
|
|
43
|
+
* fix(model): make `save()` use `updateOne()` instead of `update()` #6031
|
|
44
|
+
* feat(error): add version number to VersionError #5966
|
|
45
|
+
* fix(query): allow `[]` as a value for `$in` when casting #5913
|
|
46
|
+
* fix(document): avoid running validators on single nested paths if only a child path is modified #5885
|
|
47
|
+
* feat(schema): print warning if method conflicts with mongoose internals #5860
|
|
48
|
+
|
|
49
|
+
5.0.18 / 2018-05-09
|
|
50
|
+
===================
|
|
51
|
+
* fix(update): stop clobbering $in when casting update #6441 #6339 [lineus](https://github.com/lineus)
|
|
52
|
+
* fix: upgrade mongodb driver -> 3.0.8 to fix session issue #6437 #6357 [simllll](https://github.com/simllll)
|
|
53
|
+
* fix: upgrade bson -> 1.0.5 re: https://snyk.io/vuln/npm:bson:20180225 #6423 [ChristianMurphy](https://github.com/ChristianMurphy)
|
|
54
|
+
* fix: look for `valueOf()` when casting to Decimal128 #6419 #6418 [lineus](https://github.com/lineus)
|
|
55
|
+
* fix: populate array of objects with space separated paths #6414 [lineus](https://github.com/lineus)
|
|
56
|
+
* test: add coverage for `mongoose.pluralize()` #6412 [FastDeath](https://github.com/FastDeath)
|
|
57
|
+
* fix(document): avoid running default functions on init() if path has value #6410
|
|
58
|
+
* fix(document): allow saving document with `null` id #6406
|
|
59
|
+
* fix: prevent casting of populated docs in document.init #6390 [lineus](https://github.com/lineus)
|
|
60
|
+
* fix: remove `toHexString()` helper that was added in 5.0.15 #6359
|
|
61
|
+
|
|
1
62
|
5.0.17 / 2018-04-30
|
|
2
63
|
===================
|
|
3
64
|
* docs(migration): certain chars in passwords may cause connection failures #6401 [markstos](https://github.com/markstos)
|
package/lib/aggregate.js
CHANGED
|
@@ -342,23 +342,34 @@ Aggregate.prototype.unwind = function() {
|
|
|
342
342
|
/**
|
|
343
343
|
* Appends a new $replaceRoot operator to this aggregate pipeline.
|
|
344
344
|
*
|
|
345
|
-
* Note that the `$replaceRoot` operator requires
|
|
346
|
-
* Mongoose will prepend '$' if the specified field doesn't start '$'.
|
|
345
|
+
* Note that the `$replaceRoot` operator requires field strings to start with '$'.
|
|
346
|
+
* If you are passing in a string Mongoose will prepend '$' if the specified field doesn't start '$'.
|
|
347
|
+
* If you are passing in an object the strings in your expression will not be altered.
|
|
347
348
|
*
|
|
348
349
|
* ####Examples:
|
|
349
350
|
*
|
|
350
351
|
* aggregate.replaceRoot("user");
|
|
351
352
|
*
|
|
353
|
+
* aggregate.replaceRoot({ x: { $concat: ['$this', '$that'] } });
|
|
354
|
+
*
|
|
352
355
|
* @see $replaceRoot https://docs.mongodb.org/manual/reference/operator/aggregation/replaceRoot
|
|
353
|
-
* @param {String} the field which will become the new root document
|
|
356
|
+
* @param {String|Object} the field or document which will become the new root document
|
|
354
357
|
* @return {Aggregate}
|
|
355
358
|
* @api public
|
|
356
359
|
*/
|
|
357
360
|
|
|
358
361
|
Aggregate.prototype.replaceRoot = function(newRoot) {
|
|
362
|
+
var ret;
|
|
363
|
+
|
|
364
|
+
if (typeof newRoot === 'string') {
|
|
365
|
+
ret = newRoot.startsWith('$') ? newRoot : '$' + newRoot;
|
|
366
|
+
} else {
|
|
367
|
+
ret = newRoot;
|
|
368
|
+
}
|
|
369
|
+
|
|
359
370
|
return this.append({
|
|
360
371
|
$replaceRoot: {
|
|
361
|
-
newRoot:
|
|
372
|
+
newRoot: ret
|
|
362
373
|
}
|
|
363
374
|
});
|
|
364
375
|
};
|
package/lib/connection.js
CHANGED
|
@@ -770,6 +770,18 @@ Connection.prototype.optionsProvideAuthenticationData = function(options) {
|
|
|
770
770
|
((options.pass) || this.authMechanismDoesNotRequirePassword());
|
|
771
771
|
};
|
|
772
772
|
|
|
773
|
+
/**
|
|
774
|
+
* Switches to a different database using the same connection pool.
|
|
775
|
+
*
|
|
776
|
+
* Returns a new connection object, with the new db.
|
|
777
|
+
*
|
|
778
|
+
* @method useDb
|
|
779
|
+
* @memberOf Connection
|
|
780
|
+
* @param {String} name The database name
|
|
781
|
+
* @return {Connection} New Connection Object
|
|
782
|
+
* @api public
|
|
783
|
+
*/
|
|
784
|
+
|
|
773
785
|
/*!
|
|
774
786
|
* Module exports.
|
|
775
787
|
*/
|
package/lib/document.js
CHANGED
|
@@ -94,7 +94,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
94
94
|
$__hasIncludedChildren(fields) :
|
|
95
95
|
{};
|
|
96
96
|
|
|
97
|
-
this.$__buildDoc(obj, fields, skipId, exclude, hasIncludedChildren);
|
|
97
|
+
this.$__buildDoc(obj, fields, skipId, exclude, hasIncludedChildren, false);
|
|
98
98
|
|
|
99
99
|
// By default, defaults get applied **before** setting initial values
|
|
100
100
|
// Re: gh-6155
|
|
@@ -115,7 +115,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
115
115
|
// Function defaults get applied **after** setting initial values so they
|
|
116
116
|
// see the full doc rather than an empty one, unless they opt out.
|
|
117
117
|
// Re: gh-3781, gh-6155
|
|
118
|
-
$__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false);
|
|
118
|
+
$__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false, options.skipDefaults);
|
|
119
119
|
|
|
120
120
|
this.$__._id = this._id;
|
|
121
121
|
|
|
@@ -218,7 +218,7 @@ function $__hasIncludedChildren(fields) {
|
|
|
218
218
|
* ignore
|
|
219
219
|
*/
|
|
220
220
|
|
|
221
|
-
function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isBeforeSetters) {
|
|
221
|
+
function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
|
|
222
222
|
const paths = Object.keys(doc.schema.paths);
|
|
223
223
|
const plen = paths.length;
|
|
224
224
|
|
|
@@ -274,6 +274,10 @@ function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isB
|
|
|
274
274
|
continue;
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
if (pathsToSkip && pathsToSkip[curPath]) {
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
|
|
277
281
|
if (fields && exclude !== null) {
|
|
278
282
|
if (exclude === true) {
|
|
279
283
|
// apply defaults to all non-excluded fields
|
|
@@ -322,7 +326,10 @@ function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isB
|
|
|
322
326
|
Document.prototype.$__buildDoc = function(obj, fields, skipId, exclude, hasIncludedChildren) {
|
|
323
327
|
const doc = {};
|
|
324
328
|
|
|
325
|
-
const paths = Object.keys(this.schema.paths)
|
|
329
|
+
const paths = Object.keys(this.schema.paths).
|
|
330
|
+
// Don't build up any paths that are underneath a map, we don't know
|
|
331
|
+
// what the keys will be
|
|
332
|
+
filter(p => !p.includes('$*'));
|
|
326
333
|
const plen = paths.length;
|
|
327
334
|
let ii = 0;
|
|
328
335
|
|
|
@@ -486,7 +493,9 @@ function init(self, obj, doc, prefix) {
|
|
|
486
493
|
if (obj[i] === null) {
|
|
487
494
|
doc[i] = null;
|
|
488
495
|
} else if (obj[i] !== undefined) {
|
|
489
|
-
|
|
496
|
+
let intCache = obj[i].$__ || {};
|
|
497
|
+
let wasPopulated = intCache.wasPopulated || null;
|
|
498
|
+
if (schema && !wasPopulated) {
|
|
490
499
|
try {
|
|
491
500
|
doc[i] = schema.cast(obj[i], self, true);
|
|
492
501
|
} catch (e) {
|
|
@@ -535,6 +544,26 @@ Document.prototype.update = function update() {
|
|
|
535
544
|
return this.constructor.update.apply(this.constructor, args);
|
|
536
545
|
};
|
|
537
546
|
|
|
547
|
+
/**
|
|
548
|
+
* Getter/setter around the session associated with this document. Used to
|
|
549
|
+
* automatically set `session` if you `save()` a doc that you got from a
|
|
550
|
+
* query with an associated session.
|
|
551
|
+
*
|
|
552
|
+
* @param {ClientSession} [session] overwrite the current session
|
|
553
|
+
* @return {ClientSession}
|
|
554
|
+
* @method $session
|
|
555
|
+
* @api public
|
|
556
|
+
* @memberOf Document
|
|
557
|
+
*/
|
|
558
|
+
|
|
559
|
+
Document.prototype.$session = function $session(session) {
|
|
560
|
+
if (arguments.length === 0) {
|
|
561
|
+
return this.$__.session;
|
|
562
|
+
}
|
|
563
|
+
this.$__.session = session;
|
|
564
|
+
return session;
|
|
565
|
+
};
|
|
566
|
+
|
|
538
567
|
/**
|
|
539
568
|
* Alias for `set()`, used internally to avoid conflicts
|
|
540
569
|
*
|
|
@@ -972,7 +1001,11 @@ Document.prototype.$__set = function(pathToMark, path, constructing, parts, sche
|
|
|
972
1001
|
cur += (cur ? '.' + parts[i] : parts[i]);
|
|
973
1002
|
|
|
974
1003
|
if (last) {
|
|
975
|
-
obj
|
|
1004
|
+
if (obj instanceof Map) {
|
|
1005
|
+
obj.set(parts[i], val);
|
|
1006
|
+
} else {
|
|
1007
|
+
obj[parts[i]] = val;
|
|
1008
|
+
}
|
|
976
1009
|
} else {
|
|
977
1010
|
if (obj[parts[i]] && utils.getFunctionName(obj[parts[i]].constructor) === 'Object') {
|
|
978
1011
|
obj = obj[parts[i]];
|
|
@@ -1049,9 +1082,13 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1049
1082
|
}
|
|
1050
1083
|
|
|
1051
1084
|
for (var i = 0, l = pieces.length; i < l; i++) {
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1085
|
+
if (obj == null) {
|
|
1086
|
+
obj = void 0;
|
|
1087
|
+
} else if (obj instanceof Map) {
|
|
1088
|
+
obj = obj.get(pieces[i]);
|
|
1089
|
+
} else {
|
|
1090
|
+
obj = obj[pieces[i]];
|
|
1091
|
+
}
|
|
1055
1092
|
}
|
|
1056
1093
|
|
|
1057
1094
|
if (adhoc) {
|
|
@@ -1479,6 +1516,7 @@ Document.prototype.validate = function(options, callback) {
|
|
|
1479
1516
|
function _getPathsToValidate(doc) {
|
|
1480
1517
|
var i;
|
|
1481
1518
|
var len;
|
|
1519
|
+
var skipSchemaValidators = {};
|
|
1482
1520
|
|
|
1483
1521
|
// only validate required fields when necessary
|
|
1484
1522
|
var paths = Object.keys(doc.$__.activePaths.states.require).filter(function(path) {
|
|
@@ -1511,6 +1549,7 @@ function _getPathsToValidate(doc) {
|
|
|
1511
1549
|
return p != null && p.indexOf(subdoc.$basePath + '.') !== 0;
|
|
1512
1550
|
});
|
|
1513
1551
|
paths.push(subdoc.$basePath);
|
|
1552
|
+
skipSchemaValidators[subdoc.$basePath] = true;
|
|
1514
1553
|
}
|
|
1515
1554
|
}
|
|
1516
1555
|
}
|
|
@@ -1557,7 +1596,24 @@ function _getPathsToValidate(doc) {
|
|
|
1557
1596
|
}
|
|
1558
1597
|
}
|
|
1559
1598
|
|
|
1560
|
-
|
|
1599
|
+
len = paths.length;
|
|
1600
|
+
for (i = 0; i < len; ++i) {
|
|
1601
|
+
const path = paths[i];
|
|
1602
|
+
const _pathType = doc.schema.path(path);
|
|
1603
|
+
if (!_pathType || !_pathType.$isSchemaMap) {
|
|
1604
|
+
continue;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
const val = doc.getValue(path);
|
|
1608
|
+
if (val == null) {
|
|
1609
|
+
continue;
|
|
1610
|
+
}
|
|
1611
|
+
for (let key of val.keys()) {
|
|
1612
|
+
paths.push(path + '.' + key);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
return [paths, skipSchemaValidators];
|
|
1561
1617
|
}
|
|
1562
1618
|
|
|
1563
1619
|
/*!
|
|
@@ -1584,7 +1640,9 @@ Document.prototype.$__validate = function(callback) {
|
|
|
1584
1640
|
};
|
|
1585
1641
|
|
|
1586
1642
|
// only validate required fields when necessary
|
|
1587
|
-
const
|
|
1643
|
+
const pathDetails = _getPathsToValidate(this);
|
|
1644
|
+
const paths = pathDetails[0];
|
|
1645
|
+
const skipSchemaValidators = pathDetails[1];
|
|
1588
1646
|
|
|
1589
1647
|
if (paths.length === 0) {
|
|
1590
1648
|
return process.nextTick(function() {
|
|
@@ -1621,6 +1679,7 @@ Document.prototype.$__validate = function(callback) {
|
|
|
1621
1679
|
|
|
1622
1680
|
process.nextTick(function() {
|
|
1623
1681
|
const p = _this.schema.path(path);
|
|
1682
|
+
|
|
1624
1683
|
if (!p) {
|
|
1625
1684
|
return --total || complete();
|
|
1626
1685
|
}
|
|
@@ -1641,7 +1700,7 @@ Document.prototype.$__validate = function(callback) {
|
|
|
1641
1700
|
_this.invalidate(path, err, undefined, true);
|
|
1642
1701
|
}
|
|
1643
1702
|
--total || complete();
|
|
1644
|
-
}, scope);
|
|
1703
|
+
}, scope, { skipSchemaValidators: skipSchemaValidators[path] });
|
|
1645
1704
|
});
|
|
1646
1705
|
};
|
|
1647
1706
|
|
|
@@ -1673,14 +1732,16 @@ Document.prototype.$__validate = function(callback) {
|
|
|
1673
1732
|
*/
|
|
1674
1733
|
|
|
1675
1734
|
Document.prototype.validateSync = function(pathsToValidate) {
|
|
1676
|
-
|
|
1735
|
+
const _this = this;
|
|
1677
1736
|
|
|
1678
1737
|
if (typeof pathsToValidate === 'string') {
|
|
1679
1738
|
pathsToValidate = pathsToValidate.split(' ');
|
|
1680
1739
|
}
|
|
1681
1740
|
|
|
1682
1741
|
// only validate required fields when necessary
|
|
1683
|
-
|
|
1742
|
+
const pathDetails = _getPathsToValidate(this);
|
|
1743
|
+
let paths = pathDetails[0];
|
|
1744
|
+
const skipSchemaValidators = pathDetails[1];
|
|
1684
1745
|
|
|
1685
1746
|
if (pathsToValidate && pathsToValidate.length) {
|
|
1686
1747
|
var tmp = [];
|
|
@@ -1710,7 +1771,9 @@ Document.prototype.validateSync = function(pathsToValidate) {
|
|
|
1710
1771
|
}
|
|
1711
1772
|
|
|
1712
1773
|
var val = _this.getValue(path);
|
|
1713
|
-
var err = p.doValidateSync(val, _this
|
|
1774
|
+
var err = p.doValidateSync(val, _this, {
|
|
1775
|
+
skipSchemaValidators: skipSchemaValidators[path]
|
|
1776
|
+
});
|
|
1714
1777
|
if (err) {
|
|
1715
1778
|
_this.invalidate(path, err, undefined, true);
|
|
1716
1779
|
}
|
|
@@ -1940,7 +2003,7 @@ Document.prototype.$__dirty = function() {
|
|
|
1940
2003
|
// gh-2558: if we had to set a default and the value is not undefined,
|
|
1941
2004
|
// we have to save as well
|
|
1942
2005
|
all = all.concat(this.$__.activePaths.map('default', function(path) {
|
|
1943
|
-
if (path === '_id' ||
|
|
2006
|
+
if (path === '_id' || _this.getValue(path) == null) {
|
|
1944
2007
|
return;
|
|
1945
2008
|
}
|
|
1946
2009
|
return {
|
|
@@ -2617,7 +2680,6 @@ Document.prototype.populate = function populate() {
|
|
|
2617
2680
|
if (fn) {
|
|
2618
2681
|
var paths = utils.object.vals(pop);
|
|
2619
2682
|
this.$__.populate = undefined;
|
|
2620
|
-
paths.__noPromise = true;
|
|
2621
2683
|
var topLevelModel = this.constructor;
|
|
2622
2684
|
if (this.$__isNested) {
|
|
2623
2685
|
topLevelModel = this.$__.scope.constructor;
|
|
@@ -2685,7 +2747,6 @@ Document.prototype.execPopulate = function() {
|
|
|
2685
2747
|
|
|
2686
2748
|
Document.prototype.populated = function(path, val, options) {
|
|
2687
2749
|
// val and options are internal
|
|
2688
|
-
|
|
2689
2750
|
if (val === null || val === void 0) {
|
|
2690
2751
|
if (!this.$__.populated) {
|
|
2691
2752
|
return undefined;
|
|
@@ -7,6 +7,18 @@
|
|
|
7
7
|
|
|
8
8
|
var ObjectId = require('bson').ObjectID;
|
|
9
9
|
|
|
10
|
+
/*!
|
|
11
|
+
* Getter for convenience with populate, see gh-6115
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
Object.defineProperty(ObjectId.prototype, '_id', {
|
|
15
|
+
enumerable: false,
|
|
16
|
+
configurable: true,
|
|
17
|
+
get: function() {
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
10
22
|
/*!
|
|
11
23
|
* ignore
|
|
12
24
|
*/
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
1
3
|
/*!
|
|
2
4
|
* Module dependencies.
|
|
3
5
|
*/
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
const MongooseCollection = require('../../collection');
|
|
8
|
+
const Collection = require('mongodb').Collection;
|
|
9
|
+
const get = require('lodash.get');
|
|
10
|
+
const utils = require('../../utils');
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) collection implementation.
|
|
@@ -217,44 +220,52 @@ function format(obj, sub) {
|
|
|
217
220
|
if (obj && typeof obj.toBSON === 'function') {
|
|
218
221
|
obj = obj.toBSON();
|
|
219
222
|
}
|
|
223
|
+
if (obj == null) {
|
|
224
|
+
return obj;
|
|
225
|
+
}
|
|
226
|
+
|
|
220
227
|
var x = utils.clone(obj, {transform: false});
|
|
221
228
|
var representation;
|
|
222
229
|
|
|
223
|
-
if (x
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
if (x[key]) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
x[key]
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
x[key]
|
|
253
|
-
}
|
|
230
|
+
if (x.constructor.name === 'Binary') {
|
|
231
|
+
x = 'BinData(' + x.sub_type + ', "' + x.toString('base64') + '")';
|
|
232
|
+
} else if (x.constructor.name === 'ObjectID') {
|
|
233
|
+
representation = 'ObjectId("' + x.toHexString() + '")';
|
|
234
|
+
x = {inspect: function() { return representation; }};
|
|
235
|
+
} else if (x.constructor.name === 'Date') {
|
|
236
|
+
representation = 'new Date("' + x.toUTCString() + '")';
|
|
237
|
+
x = {inspect: function() { return representation; }};
|
|
238
|
+
} else if (x.constructor.name === 'Object') {
|
|
239
|
+
var keys = Object.keys(x);
|
|
240
|
+
var numKeys = keys.length;
|
|
241
|
+
var key;
|
|
242
|
+
for (var i = 0; i < numKeys; ++i) {
|
|
243
|
+
key = keys[i];
|
|
244
|
+
if (x[key]) {
|
|
245
|
+
if (typeof x[key].toBSON === 'function') {
|
|
246
|
+
x[key] = x[key].toBSON();
|
|
247
|
+
}
|
|
248
|
+
if (x[key].constructor.name === 'Binary') {
|
|
249
|
+
x[key] = 'BinData(' + x[key].sub_type + ', "' +
|
|
250
|
+
x[key].buffer.toString('base64') + '")';
|
|
251
|
+
} else if (x[key].constructor.name === 'Object') {
|
|
252
|
+
x[key] = format(x[key], true);
|
|
253
|
+
} else if (x[key].constructor.name === 'ObjectID') {
|
|
254
|
+
formatObjectId(x, key);
|
|
255
|
+
} else if (x[key].constructor.name === 'Date') {
|
|
256
|
+
formatDate(x, key);
|
|
257
|
+
} else if (x[key].constructor.name === 'ClientSession') {
|
|
258
|
+
representation = 'ClientSession("' +
|
|
259
|
+
get(x[key], 'id.id.buffer', '').toString('hex') + '")';
|
|
260
|
+
x[key] = {inspect: function() { return representation; }};
|
|
261
|
+
} else if (Array.isArray(x[key])) {
|
|
262
|
+
x[key] = x[key].map(map);
|
|
254
263
|
}
|
|
255
264
|
}
|
|
256
265
|
}
|
|
257
|
-
|
|
266
|
+
}
|
|
267
|
+
if (sub) {
|
|
268
|
+
return x;
|
|
258
269
|
}
|
|
259
270
|
|
|
260
271
|
return require('util')
|
package/lib/error/version.js
CHANGED
|
@@ -13,10 +13,12 @@ var MongooseError = require('./');
|
|
|
13
13
|
* @api private
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
function VersionError(doc) {
|
|
16
|
+
function VersionError(doc, currentVersion, modifiedPaths) {
|
|
17
17
|
MongooseError.call(this, 'No matching document found for id "' + doc._id +
|
|
18
|
-
'"');
|
|
18
|
+
'" version ' + currentVersion);
|
|
19
19
|
this.name = 'VersionError';
|
|
20
|
+
this.version = currentVersion;
|
|
21
|
+
this.modifiedPaths = modifiedPaths;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
/*!
|
package/lib/index.js
CHANGED
|
@@ -80,6 +80,7 @@ Mongoose.prototype.STATES = STATES;
|
|
|
80
80
|
* - 'debug': prints the operations mongoose sends to MongoDB to the console
|
|
81
81
|
* - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
|
|
82
82
|
* - 'useFindAndModify': true by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
|
|
83
|
+
* - 'cloneSchemas': false by default. Set to `true` to `clone()` all schemas before compiling into a model.
|
|
83
84
|
*
|
|
84
85
|
* @param {String} key
|
|
85
86
|
* @param {String|Function|Boolean} value
|
|
@@ -237,8 +238,8 @@ Mongoose.prototype.disconnect = function(callback) {
|
|
|
237
238
|
/**
|
|
238
239
|
* Getter/setter around function for pluralizing collection names.
|
|
239
240
|
*
|
|
240
|
-
* @param {Function|null} [fn] overwrites the function used to pluralize
|
|
241
|
-
* @return {Function|null} the current function used to pluralize
|
|
241
|
+
* @param {Function|null} [fn] overwrites the function used to pluralize collection names
|
|
242
|
+
* @return {Function|null} the current function used to pluralize collection names, defaults to the legacy function from `mongoose-legacy-pluralize`.
|
|
242
243
|
* @api public
|
|
243
244
|
*/
|
|
244
245
|
|
|
@@ -291,7 +292,7 @@ Mongoose.prototype.pluralize = function(fn) {
|
|
|
291
292
|
*/
|
|
292
293
|
|
|
293
294
|
Mongoose.prototype.model = function(name, schema, collection, skipInit) {
|
|
294
|
-
|
|
295
|
+
let model;
|
|
295
296
|
if (typeof name === 'function') {
|
|
296
297
|
model = name;
|
|
297
298
|
name = model.name;
|
|
@@ -319,7 +320,7 @@ Mongoose.prototype.model = function(name, schema, collection, skipInit) {
|
|
|
319
320
|
}
|
|
320
321
|
|
|
321
322
|
// handle internal options from connection.model()
|
|
322
|
-
|
|
323
|
+
let options;
|
|
323
324
|
if (skipInit && utils.isObject(skipInit)) {
|
|
324
325
|
options = skipInit;
|
|
325
326
|
skipInit = true;
|
|
@@ -337,16 +338,20 @@ Mongoose.prototype.model = function(name, schema, collection, skipInit) {
|
|
|
337
338
|
}
|
|
338
339
|
}
|
|
339
340
|
|
|
341
|
+
const originalSchema = schema;
|
|
340
342
|
if (schema) {
|
|
343
|
+
if (this.get('cloneSchemas')) {
|
|
344
|
+
schema = schema.clone();
|
|
345
|
+
}
|
|
341
346
|
this._applyPlugins(schema);
|
|
342
347
|
}
|
|
343
348
|
|
|
344
|
-
|
|
349
|
+
let sub;
|
|
345
350
|
|
|
346
351
|
// connection.model() may be passing a different schema for
|
|
347
352
|
// an existing model name. in this case don't read from cache.
|
|
348
353
|
if (this.models[name] && options.cache !== false) {
|
|
349
|
-
if (
|
|
354
|
+
if (originalSchema && originalSchema.instanceOfSchema && originalSchema !== this.models[name].schema) {
|
|
350
355
|
throw new mongoose.Error.OverwriteModelError(name);
|
|
351
356
|
}
|
|
352
357
|
|
|
@@ -380,7 +385,7 @@ Mongoose.prototype.model = function(name, schema, collection, skipInit) {
|
|
|
380
385
|
utils.toCollectionName(name, this.pluralize());
|
|
381
386
|
}
|
|
382
387
|
|
|
383
|
-
|
|
388
|
+
const connection = options.connection || this.connection;
|
|
384
389
|
model = this.Model.compile(model || name, schema, collection, connection, this);
|
|
385
390
|
|
|
386
391
|
if (!skipInit) {
|