Skip to content

Commit

Permalink
Merge branch 'master' into 8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Oct 13, 2023
2 parents e159400 + 236a7a7 commit 81cba56
Show file tree
Hide file tree
Showing 21 changed files with 361 additions and 59 deletions.
4 changes: 4 additions & 0 deletions .mocharc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ reporter: spec # better to identify failing / slow tests than "dot"
ui: bdd # explicitly setting, even though it is mocha default
require:
- test/mocha-fixtures.js
extension:
- test.js
watch-files:
- test/**/*.js
11 changes: 10 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,13 @@ webpack.base.config.js
notes.md
list.out

eslintrc.json
# config files
lgtm.yml
.mocharc.yml
.eslintrc.js
.markdownlint-cli2.cjs
tsconfig.json

# scripts
scripts/
tools/
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
7.6.2 / 2023-10-13
==================
* perf: avoid storing a separate entry in schema subpaths for every element in an array #13953 #13874
* fix(document): avoid triggering setter when initializing Model.prototype.collection to allow defining collection as a schema path name #13968 #13956
* fix(model): make bulkSave() save changes in discriminator paths if calling bulkSave() on base model #13959 #13907
* fix(document): allow calling $model() with no args for TypeScript #13963 #13878
* fix(schema): handle embedded discriminators defined using Schema.prototype.discriminator() #13958 #13898
* types(model): make InsertManyResult consistent with return type of insertMany #13965 #13904
* types(models): add cleaner type definitions for insertMany() with no generics to prevent errors when using insertMany() in generic classes #13964 #13957
* types(schematypes): allow defining map path using type: 'Map' in addition to type: Map #13960 #13755

7.6.1 / 2023-10-09
==================
* fix: bump bson to match mongodb@5.9.0 exactly #13947 [hasezoey](https://github.com/hasezoey)
* fix: raw result deprecation message #13954 [simllll](https://github.com/simllll)
* type: add types for includeResultMetadata #13955 [simllll](https://github.com/simllll)
* perf(npmignore): ignore newer files #13946 [hasezoey](https://github.com/hasezoey)
* perf: move mocha config from package.json to mocharc #13948 [hasezoey](https://github.com/hasezoey)

7.6.0 / 2023-10-06
==================
* feat: upgrade mongodb node driver -> 5.9.0 #13927 #13926 [sanguineti](https://github.com/sanguineti)
* fix: avoid CastError when passing different value of discriminator key in `$or` #13938 #13906

7.5.4 / 2023-10-04
==================
* fix: avoid stripping out `id` property when `_id` is set #13933 #13892 #13867
Expand Down
2 changes: 1 addition & 1 deletion docs/timestamps.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ Mongoose: users.findOneAndUpdate({}, { '$setOnInsert': { createdAt: new Date("Su

Notice the `$setOnInsert` for `createdAt` and `$set` for `updatedAt`.
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).
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:
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:

```javascript
await User.findOneAndUpdate({}, { $setOnInsert: { updatedAt: new Date() } }, {
Expand Down
9 changes: 7 additions & 2 deletions lib/cast.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,13 @@ module.exports = function cast(schema, obj, options, context) {
if (val[k] == null || typeof val[k] !== 'object') {
throw new CastError('Object', val[k], path + '.' + k);
}
val[k] = cast(schema, val[k], options, context);
const discriminatorValue = val[k][schema.options.discriminatorKey];
if (discriminatorValue == null) {
val[k] = cast(schema, val[k], options, context);
} else {
const discriminatorSchema = getSchemaDiscriminatorByValue(context.schema, discriminatorValue);
val[k] = cast(discriminatorSchema ? discriminatorSchema : schema, val[k], options, context);
}
}
} else if (path === '$where') {
type = typeof val;
Expand Down Expand Up @@ -303,7 +309,6 @@ module.exports = function cast(schema, obj, options, context) {
} else {
const ks = Object.keys(val);
let $cond;

let k = ks.length;

while (k--) {
Expand Down
55 changes: 34 additions & 21 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -1070,40 +1070,45 @@ Model.prototype.deleteOne = function deleteOne(options) {
};

/**
* Returns another Model instance.
* Returns the model instance used to create this document if no `name` specified.
* If `name` specified, returns the model with the given `name`.
*
* #### Example:
*
* const doc = new Tank;
* await doc.model('User').findById(id);
* const doc = new Tank({});
* doc.$model() === Tank; // true
* await doc.$model('User').findById(id);
*
* @param {String} name model name
* @method model
* @param {String} [name] model name
* @method $model
* @api public
* @return {Model}
*/

Model.prototype.model = function model(name) {
Model.prototype.$model = function $model(name) {
if (arguments.length === 0) {
return this.constructor;
}
return this[modelDbSymbol].model(name);
};

/**
* Returns another Model instance.
* Returns the model instance used to create this document if no `name` specified.
* If `name` specified, returns the model with the given `name`.
*
* #### Example:
*
* const doc = new Tank;
* await doc.model('User').findById(id);
* const doc = new Tank({});
* doc.$model() === Tank; // true
* await doc.$model('User').findById(id);
*
* @param {String} name model name
* @method $model
* @param {String} [name] model name
* @method model
* @api public
* @return {Model}
*/

Model.prototype.$model = function $model(name) {
return this[modelDbSymbol].model(name);
};
Model.prototype.model = Model.prototype.$model;

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

setDefaultOptions();
const discriminatorKey = this.schema.options.discriminatorKey;

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

_applyCustomWhere(document, where);

// Set the discriminator key, so bulk write casting knows which
// schema to use re: gh-13907
if (document[discriminatorKey] != null && !(discriminatorKey in where)) {
where[discriminatorKey] = document[discriminatorKey];
}

document.$__version(where, delta);
const writeOperation = { updateOne: { filter: where, update: changes } };
utils.injectTimestampsOption(writeOperation.updateOne, options.timestamps);
Expand Down Expand Up @@ -4649,8 +4661,6 @@ Model.compile = function compile(name, schema, collectionName, connection, base)

schema._preCompile();

model.prototype.$__setSchema(schema);

const _userProvidedOptions = schema._userProvidedOptions || {};

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

model.prototype.collection = connection.collection(
const collection = connection.collection(
collectionName,
collectionOptions
);

model.prototype.$collection = model.prototype.collection;
model.prototype[modelCollectionSymbol] = model.prototype.collection;
model.prototype.collection = collection;
model.prototype.$collection = collection;
model.prototype[modelCollectionSymbol] = collection;

model.prototype.$__setSchema(schema);

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

model.schema = model.prototype.$__schema;
model.collection = model.prototype.collection;
model.$__collection = model.collection;
model.collection = collection;
model.$__collection = collection;

// Create custom query constructor
model.Query = function() {
Expand Down
1 change: 0 additions & 1 deletion lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -4786,7 +4786,6 @@ function _getPopulatedPaths(list, arr, prefix) {

Query.prototype.cast = function(model, obj) {
obj || (obj = this._conditions);

model = model || this.model;
const discriminatorKey = model.schema.options.discriminatorKey;
if (obj != null &&
Expand Down
32 changes: 12 additions & 20 deletions lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const isPOJO = utils.isPOJO;

let id = 0;

const numberRE = /^\d+$/;

/**
* Schema constructor.
*
Expand Down Expand Up @@ -723,19 +725,6 @@ Schema.prototype.add = function add(obj, prefix) {
for (const key in val[0].discriminators) {
schemaType.discriminator(key, val[0].discriminators[key]);
}
} else if (val[0] != null && val[0].instanceOfSchema && val[0]._applyDiscriminators instanceof Map) {
const applyDiscriminators = val[0]._applyDiscriminators;
const schemaType = this.path(prefix + key);
for (const disc of applyDiscriminators.keys()) {
schemaType.discriminator(disc, applyDiscriminators.get(disc));
}
}
else if (val != null && val.instanceOfSchema && val._applyDiscriminators instanceof Map) {
const applyDiscriminators = val._applyDiscriminators;
const schemaType = this.path(prefix + key);
for (const disc of applyDiscriminators.keys()) {
schemaType.discriminator(disc, applyDiscriminators.get(disc));
}
}
} else if (Object.keys(val).length < 1) {
// Special-case: {} always interpreted as Mixed path so leaf at this node
Expand Down Expand Up @@ -1017,7 +1006,7 @@ Schema.prototype.path = function(path, obj) {

// subpaths?
return /\.\d+\.?.*$/.test(path)
? getPositionalPath(this, path)
? getPositionalPath(this, path, cleanPath)
: undefined;
}

Expand Down Expand Up @@ -1634,7 +1623,7 @@ Schema.prototype.pathType = function(path) {
}

if (/\.\d+\.|\.\d+$/.test(path)) {
return getPositionalPathType(this, path);
return getPositionalPathType(this, path, cleanPath);
}
return 'adhocOrUndefined';
};
Expand Down Expand Up @@ -1678,7 +1667,7 @@ Schema.prototype.setupTimestamp = function(timestamps) {
* @api private
*/

function getPositionalPathType(self, path) {
function getPositionalPathType(self, path, cleanPath) {
const subpaths = path.split(/\.(\d+)\.|\.(\d+)$/).filter(Boolean);
if (subpaths.length < 2) {
return self.paths.hasOwnProperty(subpaths[0]) ?
Expand Down Expand Up @@ -1729,7 +1718,7 @@ function getPositionalPathType(self, path) {
val = val.schema.path(subpath);
}

self.subpaths[path] = val;
self.subpaths[cleanPath] = val;
if (val) {
return 'real';
}
Expand All @@ -1744,9 +1733,9 @@ function getPositionalPathType(self, path) {
* ignore
*/

function getPositionalPath(self, path) {
getPositionalPathType(self, path);
return self.subpaths[path];
function getPositionalPath(self, path, cleanPath) {
getPositionalPathType(self, path, cleanPath);
return self.subpaths[cleanPath];
}

/**
Expand Down Expand Up @@ -2638,6 +2627,9 @@ Schema.prototype._getSchema = function(path) {
// Re: gh-5628, because `schema.path()` doesn't take $ into account.
parts[i] = '0';
}
if (numberRE.test(parts[i])) {
parts[i] = '$';
}
}
return search(parts, _this);
};
Expand Down
6 changes: 6 additions & 0 deletions lib/schema/documentArray.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ function SchemaDocumentArray(key, schema, options, schemaOptions) {

this.$embeddedSchemaType.caster = this.Constructor;
this.$embeddedSchemaType.schema = this.schema;

if (schema._applyDiscriminators != null) {
for (const disc of schema._applyDiscriminators.keys()) {
this.discriminator(disc, schema._applyDiscriminators.get(disc));
}
}
}

/**
Expand Down
6 changes: 6 additions & 0 deletions lib/schema/subdocument.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ function SchemaSubdocument(schema, path, options) {
this.$isSingleNested = true;
this.base = schema.base;
SchemaType.call(this, path, options, 'Embedded');

if (schema._applyDiscriminators != null) {
for (const disc of schema._applyDiscriminators.keys()) {
this.discriminator(disc, schema._applyDiscriminators.get(disc));
}
}
}

/*!
Expand Down
1 change: 0 additions & 1 deletion lib/schemaType.js
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,6 @@ SchemaType.prototype.applySetters = function(value, scope, init, priorVal, optio
if (v == null) {
return this._castNullish(v);
}

// do not cast until all setters are applied #665
v = this.cast(v, scope, init, priorVal, options);

Expand Down
11 changes: 1 addition & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "mongoose",
"description": "Mongoose MongoDB ODM",
"version": "7.5.4",
"version": "7.6.2",
"author": "Guillermo Rauch <guillermo@learnboost.com>",
"keywords": [
"mongodb",
Expand Down Expand Up @@ -39,7 +39,6 @@
"axios": "1.1.3",
"babel-loader": "8.2.5",
"benchmark": "2.1.4",
"bluebird": "3.7.2",
"broken-link-checker": "^0.7.8",
"buffer": "^5.6.0",
"cheerio": "1.0.0-rc.12",
Expand Down Expand Up @@ -130,14 +129,6 @@
},
"homepage": "https://mongoosejs.com",
"browser": "./dist/browser.umd.js",
"mocha": {
"extension": [
"test.js"
],
"watch-files": [
"test/**/*.js"
]
},
"config": {
"mongodbMemoryServer": {
"disablePostinstall": true
Expand Down

0 comments on commit 81cba56

Please sign in to comment.