Skip to content

Commit 81cba56

Browse files
committed
Merge branch 'master' into 8.0
2 parents e159400 + 236a7a7 commit 81cba56

21 files changed

+361
-59
lines changed

.mocharc.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@ reporter: spec # better to identify failing / slow tests than "dot"
22
ui: bdd # explicitly setting, even though it is mocha default
33
require:
44
- test/mocha-fixtures.js
5+
extension:
6+
- test.js
7+
watch-files:
8+
- test/**/*.js

.npmignore

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,13 @@ webpack.base.config.js
4747
notes.md
4848
list.out
4949

50-
eslintrc.json
50+
# config files
51+
lgtm.yml
52+
.mocharc.yml
53+
.eslintrc.js
54+
.markdownlint-cli2.cjs
55+
tsconfig.json
56+
57+
# scripts
58+
scripts/
59+
tools/

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
7.6.2 / 2023-10-13
2+
==================
3+
* perf: avoid storing a separate entry in schema subpaths for every element in an array #13953 #13874
4+
* fix(document): avoid triggering setter when initializing Model.prototype.collection to allow defining collection as a schema path name #13968 #13956
5+
* fix(model): make bulkSave() save changes in discriminator paths if calling bulkSave() on base model #13959 #13907
6+
* fix(document): allow calling $model() with no args for TypeScript #13963 #13878
7+
* fix(schema): handle embedded discriminators defined using Schema.prototype.discriminator() #13958 #13898
8+
* types(model): make InsertManyResult consistent with return type of insertMany #13965 #13904
9+
* types(models): add cleaner type definitions for insertMany() with no generics to prevent errors when using insertMany() in generic classes #13964 #13957
10+
* types(schematypes): allow defining map path using type: 'Map' in addition to type: Map #13960 #13755
11+
12+
7.6.1 / 2023-10-09
13+
==================
14+
* fix: bump bson to match mongodb@5.9.0 exactly #13947 [hasezoey](https://github.com/hasezoey)
15+
* fix: raw result deprecation message #13954 [simllll](https://github.com/simllll)
16+
* type: add types for includeResultMetadata #13955 [simllll](https://github.com/simllll)
17+
* perf(npmignore): ignore newer files #13946 [hasezoey](https://github.com/hasezoey)
18+
* perf: move mocha config from package.json to mocharc #13948 [hasezoey](https://github.com/hasezoey)
19+
20+
7.6.0 / 2023-10-06
21+
==================
22+
* feat: upgrade mongodb node driver -> 5.9.0 #13927 #13926 [sanguineti](https://github.com/sanguineti)
23+
* fix: avoid CastError when passing different value of discriminator key in `$or` #13938 #13906
24+
125
7.5.4 / 2023-10-04
226
==================
327
* fix: avoid stripping out `id` property when `_id` is set #13933 #13892 #13867

docs/timestamps.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ Mongoose: users.findOneAndUpdate({}, { '$setOnInsert': { createdAt: new Date("Su
199199

200200
Notice the `$setOnInsert` for `createdAt` and `$set` for `updatedAt`.
201201
MongoDB's [`$setOnInsert` operator](https://www.mongodb.com/docs/manual/reference/operator/update/setOnInsert/) applies the update only if a new document is [upserted](https://masteringjs.io/tutorials/mongoose/upsert).
202-
So, for example, if you want to *only* set `updatedAt` if the document if a new document is created, you can disable the `updatedAt` timestamp and set it yourself as shown below:
202+
So, for example, if you want to *only* set `updatedAt` if a new document is created, you can disable the `updatedAt` timestamp and set it yourself as shown below:
203203

204204
```javascript
205205
await User.findOneAndUpdate({}, { $setOnInsert: { updatedAt: new Date() } }, {

lib/cast.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,13 @@ module.exports = function cast(schema, obj, options, context) {
6868
if (val[k] == null || typeof val[k] !== 'object') {
6969
throw new CastError('Object', val[k], path + '.' + k);
7070
}
71-
val[k] = cast(schema, val[k], options, context);
71+
const discriminatorValue = val[k][schema.options.discriminatorKey];
72+
if (discriminatorValue == null) {
73+
val[k] = cast(schema, val[k], options, context);
74+
} else {
75+
const discriminatorSchema = getSchemaDiscriminatorByValue(context.schema, discriminatorValue);
76+
val[k] = cast(discriminatorSchema ? discriminatorSchema : schema, val[k], options, context);
77+
}
7278
}
7379
} else if (path === '$where') {
7480
type = typeof val;
@@ -303,7 +309,6 @@ module.exports = function cast(schema, obj, options, context) {
303309
} else {
304310
const ks = Object.keys(val);
305311
let $cond;
306-
307312
let k = ks.length;
308313

309314
while (k--) {

lib/model.js

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,40 +1070,45 @@ Model.prototype.deleteOne = function deleteOne(options) {
10701070
};
10711071

10721072
/**
1073-
* Returns another Model instance.
1073+
* Returns the model instance used to create this document if no `name` specified.
1074+
* If `name` specified, returns the model with the given `name`.
10741075
*
10751076
* #### Example:
10761077
*
1077-
* const doc = new Tank;
1078-
* await doc.model('User').findById(id);
1078+
* const doc = new Tank({});
1079+
* doc.$model() === Tank; // true
1080+
* await doc.$model('User').findById(id);
10791081
*
1080-
* @param {String} name model name
1081-
* @method model
1082+
* @param {String} [name] model name
1083+
* @method $model
10821084
* @api public
10831085
* @return {Model}
10841086
*/
10851087

1086-
Model.prototype.model = function model(name) {
1088+
Model.prototype.$model = function $model(name) {
1089+
if (arguments.length === 0) {
1090+
return this.constructor;
1091+
}
10871092
return this[modelDbSymbol].model(name);
10881093
};
10891094

10901095
/**
1091-
* Returns another Model instance.
1096+
* Returns the model instance used to create this document if no `name` specified.
1097+
* If `name` specified, returns the model with the given `name`.
10921098
*
10931099
* #### Example:
10941100
*
1095-
* const doc = new Tank;
1096-
* await doc.model('User').findById(id);
1101+
* const doc = new Tank({});
1102+
* doc.$model() === Tank; // true
1103+
* await doc.$model('User').findById(id);
10971104
*
1098-
* @param {String} name model name
1099-
* @method $model
1105+
* @param {String} [name] model name
1106+
* @method model
11001107
* @api public
11011108
* @return {Model}
11021109
*/
11031110

1104-
Model.prototype.$model = function $model(name) {
1105-
return this[modelDbSymbol].model(name);
1106-
};
1111+
Model.prototype.model = Model.prototype.$model;
11071112

11081113
/**
11091114
* Returns a document with `_id` only if at least one document exists in the database that matches
@@ -3679,6 +3684,7 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
36793684
}
36803685

36813686
setDefaultOptions();
3687+
const discriminatorKey = this.schema.options.discriminatorKey;
36823688

36833689
const writeOperations = documents.reduce((accumulator, document, i) => {
36843690
if (!options.skipValidation) {
@@ -3709,6 +3715,12 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
37093715

37103716
_applyCustomWhere(document, where);
37113717

3718+
// Set the discriminator key, so bulk write casting knows which
3719+
// schema to use re: gh-13907
3720+
if (document[discriminatorKey] != null && !(discriminatorKey in where)) {
3721+
where[discriminatorKey] = document[discriminatorKey];
3722+
}
3723+
37123724
document.$__version(where, delta);
37133725
const writeOperation = { updateOne: { filter: where, update: changes } };
37143726
utils.injectTimestampsOption(writeOperation.updateOne, options.timestamps);
@@ -4649,8 +4661,6 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
46494661

46504662
schema._preCompile();
46514663

4652-
model.prototype.$__setSchema(schema);
4653-
46544664
const _userProvidedOptions = schema._userProvidedOptions || {};
46554665

46564666
const collectionOptions = {
@@ -4663,13 +4673,16 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
46634673
collectionOptions.autoCreate = schema.options.autoCreate;
46644674
}
46654675

4666-
model.prototype.collection = connection.collection(
4676+
const collection = connection.collection(
46674677
collectionName,
46684678
collectionOptions
46694679
);
46704680

4671-
model.prototype.$collection = model.prototype.collection;
4672-
model.prototype[modelCollectionSymbol] = model.prototype.collection;
4681+
model.prototype.collection = collection;
4682+
model.prototype.$collection = collection;
4683+
model.prototype[modelCollectionSymbol] = collection;
4684+
4685+
model.prototype.$__setSchema(schema);
46734686

46744687
// apply methods and statics
46754688
applyMethods(model, schema);
@@ -4678,8 +4691,8 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
46784691
applyStaticHooks(model, schema.s.hooks, schema.statics);
46794692

46804693
model.schema = model.prototype.$__schema;
4681-
model.collection = model.prototype.collection;
4682-
model.$__collection = model.collection;
4694+
model.collection = collection;
4695+
model.$__collection = collection;
46834696

46844697
// Create custom query constructor
46854698
model.Query = function() {

lib/query.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4786,7 +4786,6 @@ function _getPopulatedPaths(list, arr, prefix) {
47864786

47874787
Query.prototype.cast = function(model, obj) {
47884788
obj || (obj = this._conditions);
4789-
47904789
model = model || this.model;
47914790
const discriminatorKey = model.schema.options.discriminatorKey;
47924791
if (obj != null &&

lib/schema.js

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ const isPOJO = utils.isPOJO;
3737

3838
let id = 0;
3939

40+
const numberRE = /^\d+$/;
41+
4042
/**
4143
* Schema constructor.
4244
*
@@ -723,19 +725,6 @@ Schema.prototype.add = function add(obj, prefix) {
723725
for (const key in val[0].discriminators) {
724726
schemaType.discriminator(key, val[0].discriminators[key]);
725727
}
726-
} else if (val[0] != null && val[0].instanceOfSchema && val[0]._applyDiscriminators instanceof Map) {
727-
const applyDiscriminators = val[0]._applyDiscriminators;
728-
const schemaType = this.path(prefix + key);
729-
for (const disc of applyDiscriminators.keys()) {
730-
schemaType.discriminator(disc, applyDiscriminators.get(disc));
731-
}
732-
}
733-
else if (val != null && val.instanceOfSchema && val._applyDiscriminators instanceof Map) {
734-
const applyDiscriminators = val._applyDiscriminators;
735-
const schemaType = this.path(prefix + key);
736-
for (const disc of applyDiscriminators.keys()) {
737-
schemaType.discriminator(disc, applyDiscriminators.get(disc));
738-
}
739728
}
740729
} else if (Object.keys(val).length < 1) {
741730
// Special-case: {} always interpreted as Mixed path so leaf at this node
@@ -1017,7 +1006,7 @@ Schema.prototype.path = function(path, obj) {
10171006

10181007
// subpaths?
10191008
return /\.\d+\.?.*$/.test(path)
1020-
? getPositionalPath(this, path)
1009+
? getPositionalPath(this, path, cleanPath)
10211010
: undefined;
10221011
}
10231012

@@ -1634,7 +1623,7 @@ Schema.prototype.pathType = function(path) {
16341623
}
16351624

16361625
if (/\.\d+\.|\.\d+$/.test(path)) {
1637-
return getPositionalPathType(this, path);
1626+
return getPositionalPathType(this, path, cleanPath);
16381627
}
16391628
return 'adhocOrUndefined';
16401629
};
@@ -1678,7 +1667,7 @@ Schema.prototype.setupTimestamp = function(timestamps) {
16781667
* @api private
16791668
*/
16801669

1681-
function getPositionalPathType(self, path) {
1670+
function getPositionalPathType(self, path, cleanPath) {
16821671
const subpaths = path.split(/\.(\d+)\.|\.(\d+)$/).filter(Boolean);
16831672
if (subpaths.length < 2) {
16841673
return self.paths.hasOwnProperty(subpaths[0]) ?
@@ -1729,7 +1718,7 @@ function getPositionalPathType(self, path) {
17291718
val = val.schema.path(subpath);
17301719
}
17311720

1732-
self.subpaths[path] = val;
1721+
self.subpaths[cleanPath] = val;
17331722
if (val) {
17341723
return 'real';
17351724
}
@@ -1744,9 +1733,9 @@ function getPositionalPathType(self, path) {
17441733
* ignore
17451734
*/
17461735

1747-
function getPositionalPath(self, path) {
1748-
getPositionalPathType(self, path);
1749-
return self.subpaths[path];
1736+
function getPositionalPath(self, path, cleanPath) {
1737+
getPositionalPathType(self, path, cleanPath);
1738+
return self.subpaths[cleanPath];
17501739
}
17511740

17521741
/**
@@ -2638,6 +2627,9 @@ Schema.prototype._getSchema = function(path) {
26382627
// Re: gh-5628, because `schema.path()` doesn't take $ into account.
26392628
parts[i] = '0';
26402629
}
2630+
if (numberRE.test(parts[i])) {
2631+
parts[i] = '$';
2632+
}
26412633
}
26422634
return search(parts, _this);
26432635
};

lib/schema/documentArray.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ function SchemaDocumentArray(key, schema, options, schemaOptions) {
8888

8989
this.$embeddedSchemaType.caster = this.Constructor;
9090
this.$embeddedSchemaType.schema = this.schema;
91+
92+
if (schema._applyDiscriminators != null) {
93+
for (const disc of schema._applyDiscriminators.keys()) {
94+
this.discriminator(disc, schema._applyDiscriminators.get(disc));
95+
}
96+
}
9197
}
9298

9399
/**

lib/schema/subdocument.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ function SchemaSubdocument(schema, path, options) {
5555
this.$isSingleNested = true;
5656
this.base = schema.base;
5757
SchemaType.call(this, path, options, 'Embedded');
58+
59+
if (schema._applyDiscriminators != null) {
60+
for (const disc of schema._applyDiscriminators.keys()) {
61+
this.discriminator(disc, schema._applyDiscriminators.get(disc));
62+
}
63+
}
5864
}
5965

6066
/*!

0 commit comments

Comments
 (0)