From 85c1009cc2ffbd1eef9456a8b42aa98560564078 Mon Sep 17 00:00:00 2001 From: Naor Peled Date: Mon, 24 Oct 2022 16:55:50 +0300 Subject: [PATCH 001/112] initial commit --- types/models.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/types/models.d.ts b/types/models.d.ts index d3cbbcf1338..e83d16dd88a 100644 --- a/types/models.d.ts +++ b/types/models.d.ts @@ -169,6 +169,7 @@ declare module 'mongoose' { countDocuments(callback?: Callback): QueryWithHelpers, TQueryHelpers, T>; /** Creates a new document or documents */ + create>(docs: Array, options?: SaveOptions, callback?: Callback>>): Promise[]>; create>(docs: Array, options?: SaveOptions): Promise[]>; create>(docs: Array, callback: Callback[]>): void; create>(doc: DocContents | T): Promise>; From e3cbf9436a4f7b6a0485fad2cc20618c3eeb171c Mon Sep 17 00:00:00 2001 From: Naor Peled Date: Mon, 24 Oct 2022 16:57:22 +0300 Subject: [PATCH 002/112] wip --- types/models.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/models.d.ts b/types/models.d.ts index e83d16dd88a..1ff14c5ff20 100644 --- a/types/models.d.ts +++ b/types/models.d.ts @@ -169,8 +169,8 @@ declare module 'mongoose' { countDocuments(callback?: Callback): QueryWithHelpers, TQueryHelpers, T>; /** Creates a new document or documents */ - create>(docs: Array, options?: SaveOptions, callback?: Callback>>): Promise[]>; create>(docs: Array, options?: SaveOptions): Promise[]>; + create>(docs: Array, options?: SaveOptions, callback?: Callback>>): Promise[]>; create>(docs: Array, callback: Callback[]>): void; create>(doc: DocContents | T): Promise>; create>(...docs: Array): Promise[]>; From d082a8d0ec44237d53704c44df1c31dc9969cc40 Mon Sep 17 00:00:00 2001 From: Naor Peled Date: Mon, 24 Oct 2022 16:58:35 +0300 Subject: [PATCH 003/112] wip --- types/models.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/models.d.ts b/types/models.d.ts index 1ff14c5ff20..bda2e2f06bd 100644 --- a/types/models.d.ts +++ b/types/models.d.ts @@ -171,7 +171,7 @@ declare module 'mongoose' { /** Creates a new document or documents */ create>(docs: Array, options?: SaveOptions): Promise[]>; create>(docs: Array, options?: SaveOptions, callback?: Callback>>): Promise[]>; - create>(docs: Array, callback: Callback[]>): void; + create>(docs: Array, callback: Callback>>): void; create>(doc: DocContents | T): Promise>; create>(...docs: Array): Promise[]>; create>(doc: T | DocContents, callback: Callback>): void; From 134d769a9e94cdcb2a02483c749d06616009f44f Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 26 Oct 2022 14:23:05 -0400 Subject: [PATCH 004/112] fix(map): allow populating map of arrays like in 5.x Re: #12494 --- lib/helpers/populate/assignVals.js | 5 ++++ lib/types/map.js | 20 ++++++++++++--- test/types.map.test.js | 41 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/lib/helpers/populate/assignVals.js b/lib/helpers/populate/assignVals.js index 651a48e4887..da40f396e2a 100644 --- a/lib/helpers/populate/assignVals.js +++ b/lib/helpers/populate/assignVals.js @@ -52,6 +52,11 @@ module.exports = function assignVals(o) { const _allIds = o.allIds[i]; + if (o.path.endsWith('.$*')) { + // Skip maps re: gh-12494 + return valueFilter(val, options, populateOptions, _allIds); + } + if (o.justOne === true && Array.isArray(val)) { // Might be an embedded discriminator (re: gh-9244) with multiple models, so make sure to pick the right // model before assigning. diff --git a/lib/types/map.js b/lib/types/map.js index 3c68026fa0e..6516d2e4038 100644 --- a/lib/types/map.js +++ b/lib/types/map.js @@ -97,15 +97,27 @@ class MongooseMap extends Map { const fullPath = this.$__path + '.' + key; const populated = this.$__parent != null && this.$__parent.$__ ? - this.$__parent.$populated(fullPath) || this.$__parent.$populated(this.$__path) : + this.$__parent.$populated(fullPath, true) || this.$__parent.$populated(this.$__path, true) : null; const priorVal = this.get(key); if (populated != null) { - if (value.$__ == null) { - value = new populated.options[populateModelSymbol](value); + if (Array.isArray(value) && this.$__schemaType.$isMongooseArray) { + value = value.map(v => { + if (v.$__ == null) { + v = new populated.options[populateModelSymbol](v); + } + // Doesn't support single nested "in-place" populate + v.$__.wasPopulated = { value: v._id }; + return v; + }); + } else { + if (value.$__ == null) { + value = new populated.options[populateModelSymbol](value); + } + // Doesn't support single nested "in-place" populate + value.$__.wasPopulated = { value: value._id }; } - value.$__.wasPopulated = { value: populated.value }; } else { try { value = this.$__schemaType. diff --git a/test/types.map.test.js b/test/types.map.test.js index 9edd721b068..c3415a6c3bf 100644 --- a/test/types.map.test.js +++ b/test/types.map.test.js @@ -1050,4 +1050,45 @@ describe('Map', function() { const res = doc.toObject({ flattenMaps: true }); assert.equal(res.l1.l1key.l2.l2key.value, 'abc'); }); + + it('handles populating map of arrays (gh-12494)', async function() { + const User = new mongoose.Schema({ + name: String, + addresses: { + type: Map, + of: [{ + type: mongoose.Schema.Types.ObjectId, + ref: 'Address' + }], + default: {} + } + }); + + const Address = new mongoose.Schema({ + city: String + }); + + const UserModel = db.model('User', User); + const AddressModel = db.model('Address', Address); + + const address = await new AddressModel({ city: 'London' }).save(); + + const { _id } = await new UserModel({ + name: 'Name', + addresses: { + home: [address._id] + } + }).save(); + + const query = UserModel.findById(_id); + + query.populate({ + path: 'addresses.$*' + }); + + const doc = await query.exec(); + assert.ok(Array.isArray(doc.addresses.get('home'))); + assert.equal(doc.addresses.get('home').length, 1); + assert.equal(doc.addresses.get('home')[0].city, 'London'); + }); }); From bcc85cbe0637ab6bd700437299b89f7a9f93cd60 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 26 Oct 2022 15:56:36 -0400 Subject: [PATCH 005/112] fix: support populating just one entry in map of arrays of refs Fix #12494 --- .../populate/getModelsMapForPopulate.js | 5 +- lib/model.js | 6 ++- lib/types/map.js | 7 +++ test/document.test.js | 48 +++++++++++++++++++ test/types.map.test.js | 17 +++++-- 5 files changed, 78 insertions(+), 5 deletions(-) diff --git a/lib/helpers/populate/getModelsMapForPopulate.js b/lib/helpers/populate/getModelsMapForPopulate.js index d767c369578..e554f4810a8 100644 --- a/lib/helpers/populate/getModelsMapForPopulate.js +++ b/lib/helpers/populate/getModelsMapForPopulate.js @@ -207,6 +207,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) { let isRefPath = false; let justOne = null; + const originalSchema = schema; if (schema && schema.instance === 'Array') { schema = schema.caster; } @@ -277,7 +278,9 @@ module.exports = function getModelsMapForPopulate(model, docs, options) { schemaForCurrentDoc = schema; } - if (schemaForCurrentDoc != null) { + if (originalSchema && originalSchema.path.endsWith('.$*')) { + justOne = !originalSchema.$isMongooseArray && !originalSchema._arrayPath; + } else if (schemaForCurrentDoc != null) { justOne = !schemaForCurrentDoc.$isMongooseArray && !schemaForCurrentDoc._arrayPath; } diff --git a/lib/model.js b/lib/model.js index 8fd7bdfbdd2..27dd89ee5a7 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4784,7 +4784,11 @@ function populate(model, docs, options, callback) { for (const val of vals) { mod.options._childDocs.push(val); } - _assign(model, vals, mod, assignmentOpts); + try { + _assign(model, vals, mod, assignmentOpts); + } catch (err) { + return callback(err); + } } for (const arr of params) { diff --git a/lib/types/map.js b/lib/types/map.js index 6516d2e4038..4c571160fb8 100644 --- a/lib/types/map.js +++ b/lib/types/map.js @@ -1,6 +1,7 @@ 'use strict'; const Mixed = require('../schema/mixed'); +const MongooseError = require('../error/mongooseError'); const clone = require('../helpers/clone'); const deepEqual = require('../utils').deepEqual; const getConstructorName = require('../helpers/getConstructorName'); @@ -102,6 +103,12 @@ class MongooseMap extends Map { const priorVal = this.get(key); if (populated != null) { + if (this.$__schemaType.$isSingleNested) { + throw new MongooseError( + 'Cannot manually populate single nested subdoc underneath Map ' + + `at path "${this.$__path}". Try using an array instead of a Map.` + ); + } if (Array.isArray(value) && this.$__schemaType.$isMongooseArray) { value = value.map(v => { if (v.$__ == null) { diff --git a/test/document.test.js b/test/document.test.js index df17aa9da77..1a757bbde32 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -11016,6 +11016,54 @@ describe('document', function() { assert.equal(foo.get('bar.another'), 2); }); + it('populating subdocument refs underneath maps throws (gh-12494) (gh-10856)', async function() { + // Bar model, has a name property and some other properties that we are interested in + const BarSchema = new Schema({ + name: String, + more: String, + another: Number + }); + const Bar = db.model('Bar', BarSchema); + + // Denormalised Bar schema with just the name, for use on the Foo model + const BarNameSchema = new Schema({ + _id: { + type: Schema.Types.ObjectId, + ref: 'Bar' + }, + name: String + }); + + // Foo model, which contains denormalized bar data (just the name) + const FooSchema = new Schema({ + something: String, + other: Number, + map: { + type: Map, + of: { + type: BarNameSchema, + ref: 'Bar' + } + } + }); + const Foo = db.model('Foo', FooSchema); + + const bar = await Bar.create({ + name: 'I am Bar', + more: 'With more data', + another: 2 + }); + const { _id } = await Foo.create({ + something: 'I am Foo', + other: 1, + map: { test: bar } + }); + + const err = await Foo.findById(_id).populate('map').then(() => null, err => err); + assert.ok(err); + assert.ok(err.message.includes('Cannot manually populate single nested subdoc underneath Map'), err.message); + }); + it('handles save with undefined nested doc under subdoc (gh-11110)', async function() { const testSchema = new Schema({ level_1_array: [new Schema({ diff --git a/test/types.map.test.js b/test/types.map.test.js index c3415a6c3bf..fe895ed228d 100644 --- a/test/types.map.test.js +++ b/test/types.map.test.js @@ -1080,13 +1080,24 @@ describe('Map', function() { } }).save(); - const query = UserModel.findById(_id); - + // Using `.$*` + let query = UserModel.findById(_id); query.populate({ path: 'addresses.$*' }); - const doc = await query.exec(); + let doc = await query.exec(); + assert.ok(Array.isArray(doc.addresses.get('home'))); + assert.equal(doc.addresses.get('home').length, 1); + assert.equal(doc.addresses.get('home')[0].city, 'London'); + + // Populating just one path in the map + query = UserModel.findById(_id); + query.populate({ + path: 'addresses.home' + }); + + doc = await query.exec(); assert.ok(Array.isArray(doc.addresses.get('home'))); assert.equal(doc.addresses.get('home').length, 1); assert.equal(doc.addresses.get('home')[0].city, 'London'); From 998f19a85c1915f25217c55353e42a6cbc35bef3 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 27 Oct 2022 13:19:14 -0400 Subject: [PATCH 006/112] Update test/types.map.test.js Co-authored-by: hasezoey --- test/types.map.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/types.map.test.js b/test/types.map.test.js index fe895ed228d..72885e21c88 100644 --- a/test/types.map.test.js +++ b/test/types.map.test.js @@ -1071,7 +1071,7 @@ describe('Map', function() { const UserModel = db.model('User', User); const AddressModel = db.model('Address', Address); - const address = await new AddressModel({ city: 'London' }).save(); + const address = await AddressModel.create({ city: 'London' }); const { _id } = await new UserModel({ name: 'Name', From 938964f34f87d59750e0f366a11612cd4f15526c Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 27 Oct 2022 13:19:20 -0400 Subject: [PATCH 007/112] Update test/types.map.test.js Co-authored-by: hasezoey --- test/types.map.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/types.map.test.js b/test/types.map.test.js index 72885e21c88..bff74800c02 100644 --- a/test/types.map.test.js +++ b/test/types.map.test.js @@ -1073,12 +1073,12 @@ describe('Map', function() { const address = await AddressModel.create({ city: 'London' }); - const { _id } = await new UserModel({ + const { _id } = await UserModel.create({ name: 'Name', addresses: { home: [address._id] } - }).save(); + }); // Using `.$*` let query = UserModel.findById(_id); From 3f0fb626b6740b21cda144ad196b417018ff359b Mon Sep 17 00:00:00 2001 From: Nico Date: Thu, 27 Oct 2022 20:06:15 +0200 Subject: [PATCH 008/112] Add missing propsParameter property to ValidateOpts type As the documention mentions [it](https://mongoosejs.com/docs/api.html#schematype_SchemaType-validate), the `propsParameter` property does not exists on the `ValidateOpts` type and cause TypeScript to generate an error. --- types/validation.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/types/validation.d.ts b/types/validation.d.ts index 3e6d0671a64..17ee7026090 100644 --- a/types/validation.d.ts +++ b/types/validation.d.ts @@ -28,5 +28,6 @@ declare module 'mongoose' { message?: string | ValidatorMessageFn; type?: string; validator: ValidateFn | LegacyAsyncValidateFn | AsyncValidateFn; + propsParameter?: boolean; } } From 5740c2cf2c9785265c20472024afa119068644d1 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 27 Oct 2022 14:10:43 -0400 Subject: [PATCH 009/112] fix(schema): make _getSchema() find path underneath subdocument with map of mixed Fix #12530 --- lib/schema.js | 11 +++++++++-- test/schema.test.js | 13 +++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/schema.js b/lib/schema.js index ba8435e0e66..4a3f68e03ae 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -2409,8 +2409,15 @@ Schema.prototype._getSchema = function(path) { if (p + 1 >= parts.length) { return foundschema.$__schemaType; } - const ret = search(parts.slice(p + 1), foundschema.$__schemaType.schema); - return ret; + + if (foundschema.$__schemaType instanceof MongooseTypes.Mixed) { + return foundschema.$__schemaType; + } + if (foundschema.$__schemaType.schema != null) { + // Map of docs + const ret = search(parts.slice(p + 1), foundschema.$__schemaType.schema); + return ret; + } } foundschema.$fullPath = resultPath.join('.'); diff --git a/test/schema.test.js b/test/schema.test.js index 36368c58b2d..619df3dd7c9 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -2885,4 +2885,17 @@ describe('schema', function() { assert.equal(schema.path('num').instance, 'Decimal128'); assert.equal(schema.path('num2').instance, 'Decimal128'); }); + + it('_getSchema finds path underneath nested subdocument with map of mixed (gh-12530)', function() { + const schema = new Schema({ + child: new Schema({ + testMap: { + type: Map, + of: 'Mixed' + } + }) + }); + + assert.equal(schema._getSchema('child.testMap.foo.bar').instance, 'Mixed'); + }); }); From 0b70933e71d2fb7ba16baa502c8bcbeb4e9d28d6 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 27 Oct 2022 14:33:24 -0400 Subject: [PATCH 010/112] fix(populate): correctly get schema type underneath map of mixed in getSchemaTypes --- lib/helpers/populate/getSchemaTypes.js | 2 ++ test/helpers/populate.getSchemaTypes.test.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/helpers/populate/getSchemaTypes.js b/lib/helpers/populate/getSchemaTypes.js index 177e7889344..0534f015286 100644 --- a/lib/helpers/populate/getSchemaTypes.js +++ b/lib/helpers/populate/getSchemaTypes.js @@ -173,6 +173,8 @@ module.exports = function getSchemaTypes(model, schema, doc, path) { } } } + } else if (foundschema.$isSchemaMap && foundschema.$__schemaType instanceof Mixed) { + return foundschema.$__schemaType; } const fullPath = nestedPath.concat([trypath]).join('.'); diff --git a/test/helpers/populate.getSchemaTypes.test.js b/test/helpers/populate.getSchemaTypes.test.js index 531290156e8..b34af9d3a36 100644 --- a/test/helpers/populate.getSchemaTypes.test.js +++ b/test/helpers/populate.getSchemaTypes.test.js @@ -178,4 +178,18 @@ describe('getSchemaTypes', function() { assert.equal(schemaTypes.length, 1); assert.equal(schemaTypes[0].options.ref, 'Enemy'); }); + + it('finds path underneath nested subdocument with map of mixed (gh-12530)', function() { + const schema = new Schema({ + child: new Schema({ + testMap: { + type: Map, + of: 'Mixed' + } + }) + }); + + const schemaTypes = getSchemaTypes(null, schema, null, 'child.testMap.foo.bar'); + assert.equal(schemaTypes.instance, 'Mixed'); + }); }); From 3df419fdb49e1abbe61a13a402faa2ba0db02479 Mon Sep 17 00:00:00 2001 From: Nicolas Polizzo Date: Thu, 27 Oct 2022 20:47:24 +0200 Subject: [PATCH 011/112] Add missing optional props parameter in ValidateFn --- types/validation.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/validation.d.ts b/types/validation.d.ts index 17ee7026090..7d8924c5880 100644 --- a/types/validation.d.ts +++ b/types/validation.d.ts @@ -12,7 +12,7 @@ declare module 'mongoose' { } interface ValidateFn { - (value: T): boolean; + (value: T, props?: ValidatorProps & Record): boolean; } interface LegacyAsyncValidateFn { @@ -20,7 +20,7 @@ declare module 'mongoose' { } interface AsyncValidateFn { - (value: any): Promise; + (value: T, props?: ValidatorProps & Record): Promise; } interface ValidateOpts { From f87f1896601c0a73a05003869764e333caadfdae Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 28 Oct 2022 14:26:19 -0400 Subject: [PATCH 012/112] docs: add Lodash guide highlighting issues with cloneDeep() Fix #12559 --- docs/guides.md | 1 + docs/lodash.md | 39 +++++++++++++++++++++++++++++++++++++++ docs/source/index.js | 1 + 3 files changed, 41 insertions(+) create mode 100644 docs/lodash.md diff --git a/docs/guides.md b/docs/guides.md index ba4d6bbf2d4..d9072c39542 100644 --- a/docs/guides.md +++ b/docs/guides.md @@ -33,6 +33,7 @@ integrating Mongoose with external tools and frameworks. ### Integrations * [Promises](/docs/promises.html) +* [Lodash](/docs/lodash.html) * [AWS Lambda](/docs/lambda.html) * [Browser Library](/docs/browser.html) * [GeoJSON](/docs/geojson.html) diff --git a/docs/lodash.md b/docs/lodash.md new file mode 100644 index 00000000000..9dad5b4ee51 --- /dev/null +++ b/docs/lodash.md @@ -0,0 +1,39 @@ +# Using Mongoose with Lodash + +For the most part, Mongoose works well with [Lodash](https://lodash.com/). +However, there are a few caveats that you should know about. + +* [`cloneDeep()`](#clonedeep) + +## `cloneDeep()` + +You should not use [Lodash's `cloneDeep()` function](https://lodash.com/docs/4.17.15#cloneDeep) on any Mongoose objects. +This includes [connections](./connections.html), [model classes](./models.html), and [queries](./queries.html), but is _especially_ important for [documents](./documents.html). +For example, you may be tempted to do the following: + +```javascript +const _ = require('lodash'); + +const doc = await MyModel.findOne(); + +const newDoc = _.cloneDeep(doc); +newDoc.myProperty = 'test'; +await newDoc.save(); +``` + +However, the above code will throw the following error if `MyModel` has any array properties. + +```no-highlight +TypeError: this.__parentArray.$path is not a function +``` + +This is because Lodash's `cloneDeep()` function doesn't [handle proxies](https://stackoverflow.com/questions/50663784/lodash-clonedeep-remove-proxy-from-object), and [Mongoose arrays are proxies as of Mongoose 6](https://thecodebarbarian.com/introducing-mongoose-6.html#arrays-as-proxies). +You typically don't have to deep clone Mongoose documents, but, if you have to, use the following alternative to `cloneDeep()`: + +```javascript +const doc = await MyModel.findOne(); + +const newDoc = new MyModel().init(doc.toObject()); +newDoc.myProperty = 'test'; +await newDoc.save(); +``` \ No newline at end of file diff --git a/docs/source/index.js b/docs/source/index.js index 5f3a059950d..78a79ea55d7 100644 --- a/docs/source/index.js +++ b/docs/source/index.js @@ -62,6 +62,7 @@ exports['docs/jobs.pug'] = { jobs }; exports['docs/change-streams.md'] = { title: 'MongoDB Change Streams in NodeJS with Mongoose', markdown: true }; +exports['docs/lodash.md'] = { title: 'Using Mongoose with Lodash', markdown: true }; for (const props of Object.values(exports)) { props.jobs = jobs; From ebd0581959fd4dc5a678f476b5c39e03d661cb62 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Mon, 31 Oct 2022 11:18:09 +0100 Subject: [PATCH 013/112] fix(query): select Map field with select: false when explicitly requested fix #12603 --- lib/queryhelpers.js | 4 +++- test/query.test.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/queryhelpers.js b/lib/queryhelpers.js index dfc98e49ec5..62a8cb5b1f4 100644 --- a/lib/queryhelpers.js +++ b/lib/queryhelpers.js @@ -232,7 +232,9 @@ exports.applyPaths = function applyPaths(fields, schema) { schema.eachPath(function(path, type) { if (prefix) path = prefix + '.' + path; if (type.$isSchemaMap || path.endsWith('.$*')) { - if (type.options && type.options.select === false) { + const plusPath = '+' + path; + const hasPlusPath = fields && plusPath in fields; + if (type.options && type.options.select === false && !hasPlusPath) { excluded.push(path); } return; diff --git a/test/query.test.js b/test/query.test.js index b61b39631b7..b56a5e6c3de 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -4133,6 +4133,34 @@ describe('Query', function() { assert.equal(item.doNotSelect, undefined); }); + it('Map field with select: false is selected when explicitly requested (gh-12603)', async function() { + const testSchema = new mongoose.Schema({ + title: String, + body: { + type: Map, + of: { en: String, pt: String }, + select: false + } + }); + + const Test = db.model('Test', testSchema); + await Test.create({ + title: 'test', + body: { + A: { en: 'en test A value', pt: 'pt test A value' }, + B: { en: 'en test B value', pt: 'pt test B value' } + } + }); + + const item = await Test.findOne({}).select('+body'); + assert.equal(item.title, 'test'); + assert.equal(item.get('body.A.en'), 'en test A value'); + + const item2 = await Test.findOne({}).select('body'); + assert.equal(item2.title, undefined); + assert.equal(item2.get('body.A.en'), 'en test A value'); + }); + it('treats ObjectId as object with `_id` for `merge()` (gh-12325)', async function() { const testSchema = new mongoose.Schema({ name: String }); const Test = db.model('Test', testSchema); From 774a92a904880bde25d3a25e8032e131e60db003 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Tue, 1 Nov 2022 11:02:04 +0100 Subject: [PATCH 014/112] Removed outdated example fix #12618 --- lib/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/index.js b/lib/index.js index 29aec767819..f395aded5a6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -322,10 +322,6 @@ Mongoose.prototype.get = Mongoose.prototype.set; * const opts = { replset: { strategy: 'ping', rs_name: 'testSet' }} * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database', opts); * - * // and options - * const opts = { server: { auto_reconnect: false }, user: 'username', pass: 'mypassword' } - * db = mongoose.createConnection('localhost', 'database', port, opts) - * * // initialize now, connect later * db = mongoose.createConnection(); * db.openUri('localhost', 'database', port, [opts]); From 92f34f88bafca08b2fbfcec985c9c1b623e904b3 Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 1 Nov 2022 13:03:43 -0700 Subject: [PATCH 015/112] fix(docs): links on queries.md are relative links --- docs/queries.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/queries.md b/docs/queries.md index 7e46a83d2d1..797e1830342 100644 --- a/docs/queries.md +++ b/docs/queries.md @@ -3,23 +3,23 @@ Mongoose [models](./models.html) provide several static helper functions for [CRUD operations](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete). Each of these functions returns a -[mongoose `Query` object](http://mongoosejs.com/docs/api.html#Query). - -- [`Model.deleteMany()`](/docs/api.html#model_Model-deleteMany) -- [`Model.deleteOne()`](/docs/api.html#model_Model-deleteOne) -- [`Model.find()`](/docs/api.html#model_Model-find) -- [`Model.findById()`](/docs/api.html#model_Model-findById) -- [`Model.findByIdAndDelete()`](/docs/api.html#model_Model-findByIdAndDelete) -- [`Model.findByIdAndRemove()`](/docs/api.html#model_Model-findByIdAndRemove) -- [`Model.findByIdAndUpdate()`](/docs/api.html#model_Model-findByIdAndUpdate) -- [`Model.findOne()`](/docs/api.html#model_Model-findOne) -- [`Model.findOneAndDelete()`](/docs/api.html#model_Model-findOneAndDelete) -- [`Model.findOneAndRemove()`](/docs/api.html#model_Model-findOneAndRemove) -- [`Model.findOneAndReplace()`](/docs/api.html#model_Model-findOneAndReplace) -- [`Model.findOneAndUpdate()`](/docs/api.html#model_Model-findOneAndUpdate) -- [`Model.replaceOne()`](/docs/api.html#model_Model-replaceOne) -- [`Model.updateMany()`](/docs/api.html#model_Model-updateMany) -- [`Model.updateOne()`](/docs/api.html#model_Model-updateOne) +[mongoose `Query` object](../docs/api.html#Query). + +- [`Model.deleteMany()`](../docs/api.html#model_Model-deleteMany) +- [`Model.deleteOne()`](../docs/api.html#model_Model-deleteOne) +- [`Model.find()`](../docs/api.html#model_Model-find) +- [`Model.findById()`](../docs/api.html#model_Model-findById) +- [`Model.findByIdAndDelete()`](../docs/api.html#model_Model-findByIdAndDelete) +- [`Model.findByIdAndRemove()`](../docs/api.html#model_Model-findByIdAndRemove) +- [`Model.findByIdAndUpdate()`](../docs/api.html#model_Model-findByIdAndUpdate) +- [`Model.findOne()`](../docs/api.html#model_Model-findOne) +- [`Model.findOneAndDelete()`](../docs/api.html#model_Model-findOneAndDelete) +- [`Model.findOneAndRemove()`](../docs/api.html#model_Model-findOneAndRemove) +- [`Model.findOneAndReplace()`](../docs/api.html#model_Model-findOneAndReplace) +- [`Model.findOneAndUpdate()`](../docs/api.html#model_Model-findOneAndUpdate) +- [`Model.replaceOne()`](../docs/api.html#model_Model-replaceOne) +- [`Model.updateMany()`](../docs/api.html#model_Model-updateMany) +- [`Model.updateOne()`](../docs/api.html#model_Model-updateOne) A mongoose query can be executed in one of two ways. First, if you pass in a `callback` function, Mongoose will execute the query asynchronously @@ -200,7 +200,7 @@ of inactivity. You can read more about working around session idle timeouts in t

Versus Aggregation

-[Aggregation](https://mongoosejs.com/docs/api.html#aggregate_Aggregate) can +[Aggregation](../docs/api.html#aggregate_Aggregate) can do many of the same things that queries can. For example, below is how you can use `aggregate()` to find docs where `name.last = 'Ghost'`: @@ -212,7 +212,7 @@ However, just because you can use `aggregate()` doesn't mean you should. In general, you should use queries where possible, and only use `aggregate()` when you absolutely need to. -Unlike query results, Mongoose does **not** [`hydrate()`](/docs/api/model.html#model_Model-hydrate) +Unlike query results, Mongoose does **not** [`hydrate()`](../docs/api/model.html#model_Model-hydrate) aggregation results. Aggregation results are always POJOs, not Mongoose documents. @@ -223,7 +223,7 @@ docs[0] instanceof mongoose.Document; // false ``` Also, unlike query filters, Mongoose also doesn't -[cast](/docs/tutorials/query_casting.html) aggregation pipelines. That means +[cast](../docs/tutorials/query_casting.html) aggregation pipelines. That means you're responsible for ensuring the values you pass in to an aggregation pipeline have the correct type. @@ -242,4 +242,4 @@ const aggRes = await Person.aggregate([{ $match: { _id: idString } }])

Next Up

-Now that we've covered `Queries`, let's take a look at [Validation](/docs/validation.html). +Now that we've covered `Queries`, let's take a look at [Validation](../docs/validation.html). From 4d708abbc75fc64f5c5c85d8d12ce269736b8ddd Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 1 Nov 2022 13:29:57 -0700 Subject: [PATCH 016/112] ctrl f and replace /docs/ with ../docs/ in the docs/ folder --- docs/change-streams.md | 4 +- docs/connections.md | 12 +++--- docs/deprecations.md | 8 ++-- docs/documents.md | 6 +-- docs/faq.md | 2 +- docs/geojson.md | 6 +-- docs/guide.md | 40 +++++++++---------- docs/guides.md | 64 +++++++++++++++--------------- docs/index.md | 10 ++--- docs/middleware.md | 34 ++++++++-------- docs/migrating_to_5.md | 2 +- docs/plugins.md | 2 +- docs/populate.md | 4 +- docs/schematypes.md | 2 +- docs/transactions.md | 16 ++++---- docs/tutorials/findoneandupdate.md | 2 +- docs/tutorials/getters-setters.md | 4 +- docs/tutorials/lean.md | 12 +++--- docs/tutorials/ssl.md | 2 +- docs/tutorials/virtuals.md | 6 +-- docs/validation.md | 8 ++-- 21 files changed, 123 insertions(+), 123 deletions(-) diff --git a/docs/change-streams.md b/docs/change-streams.md index bc1424ccf12..122ac267e68 100644 --- a/docs/change-streams.md +++ b/docs/change-streams.md @@ -1,7 +1,7 @@ ## Change Streams [Change streams](https://www.mongodb.com/developer/quickstart/nodejs-change-streams-triggers/) let you listen for updates to documents in a given model's collection, or even documents in an entire database. -Unlike [middleware](/docs/middleware.html), change streams are a MongoDB server construct, which means they pick up changes from anywhere. +Unlike [middleware](../docs/middleware.html), change streams are a MongoDB server construct, which means they pick up changes from anywhere. Even if you update a document from a MongoDB GUI, your Mongoose change stream will be notified. The `watch()` function creates a change stream. @@ -50,7 +50,7 @@ For local development, we recommend [mongodb-memory-server](https://www.npmjs.co ### Iterating using `next()` -If you want to iterate through a change stream in a [AWS Lambda function](/docs/lambda.html), do **not** use event emitters to listen to the change stream. +If you want to iterate through a change stream in a [AWS Lambda function](../docs/lambda.html), do **not** use event emitters to listen to the change stream. You need to make sure you close your change stream when your Lambda function is done executing, because your change stream may end up in an inconsistent state if Lambda stops your container while the change stream is pulling data from MongoDB. Change streams also have a `next()` function that lets you explicitly wait for the next change to come in. diff --git a/docs/connections.md b/docs/connections.md index 1a7935adb1a..154393c84c7 100644 --- a/docs/connections.md +++ b/docs/connections.md @@ -71,11 +71,11 @@ mongoose.set('bufferCommands', false); ``` Note that buffering is also responsible for waiting until Mongoose -creates collections if you use the [`autoCreate` option](/docs/guide.html#autoCreate). +creates collections if you use the [`autoCreate` option](../docs/guide.html#autoCreate). If you disable buffering, you should also disable the `autoCreate` -option and use [`createCollection()`](/docs/api/model.html#model_Model-createCollection) -to create [capped collections](/docs/guide.html#capped) or -[collections with collations](/docs/guide.html#collation). +option and use [`createCollection()`](../docs/api/model.html#model_Model-createCollection) +to create [capped collections](../docs/guide.html#capped) or +[collections with collations](../docs/guide.html#collation). ```javascript const schema = new Schema({ @@ -139,7 +139,7 @@ A full list of options can be found on the [MongoDB Node.js driver docs for `Mon 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) +* `bufferCommands` - This is a mongoose-specific option (not passed to the MongoDB driver) that disables [Mongoose's buffering mechanism](../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.username` 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). @@ -460,4 +460,4 @@ mongoose.createConnection(uri);

Next Up

-Now that we've covered connections, let's take a look at [models](/docs/models.html). +Now that we've covered connections, let's take a look at [models](../docs/models.html). diff --git a/docs/deprecations.md b/docs/deprecations.md index 14aaaf35465..4407167f423 100644 --- a/docs/deprecations.md +++ b/docs/deprecations.md @@ -28,7 +28,7 @@ deleteMany, or bulkWrite instead. ``` To remove this deprecation warning, replace any usage of `remove()` with -`deleteMany()`, _unless_ you specify the [`single` option to `remove()`](/docs/api.html#model_Model-remove). The `single` +`deleteMany()`, _unless_ you specify the [`single` option to `remove()`](../docs/api.html#model_Model-remove). The `single` option limited `remove()` to deleting at most one document, so you should replace `remove(filter, { single: true })` with `deleteOne(filter)`. @@ -46,9 +46,9 @@ MyModel.deleteOne({ answer: 42 });

update()

-Like `remove()`, the [`update()` function](/docs/api.html#model_Model-update) is deprecated in favor -of the more explicit [`updateOne()`](/docs/api.html#model_Model-updateOne), [`updateMany()`](/docs/api.html#model_Model-updateMany), and [`replaceOne()`](/docs/api.html#model_Model-replaceOne) functions. You should replace -`update()` with `updateOne()`, unless you use the [`multi` or `overwrite` options](/docs/api.html#model_Model-update). +Like `remove()`, the [`update()` function](../docs/api.html#model_Model-update) is deprecated in favor +of the more explicit [`updateOne()`](../docs/api.html#model_Model-updateOne), [`updateMany()`](../docs/api.html#model_Model-updateMany), and [`replaceOne()`](../docs/api.html#model_Model-replaceOne) functions. You should replace +`update()` with `updateOne()`, unless you use the [`multi` or `overwrite` options](../docs/api.html#model_Model-update). ``` collection.update is deprecated. Use updateOne, updateMany, or bulkWrite diff --git a/docs/documents.md b/docs/documents.md index a1b909ffeac..837c19e40b0 100644 --- a/docs/documents.md +++ b/docs/documents.md @@ -140,7 +140,7 @@ Read the [validation](./validation.html) guide for more details. There are 2 different ways to overwrite a document (replacing all keys in the document). One way is to use the -[`Document#overwrite()` function](/docs/api/document.html#document_Document-overwrite) +[`Document#overwrite()` function](../docs/api/document.html#document_Document-overwrite) followed by `save()`. ```javascript @@ -151,7 +151,7 @@ doc.overwrite({ name: 'Jean-Luc Picard' }); await doc.save(); ``` -The other way is to use [`Model.replaceOne()`](/docs/api/model.html#model_Model-replaceOne). +The other way is to use [`Model.replaceOne()`](../docs/api/model.html#model_Model-replaceOne). ```javascript // Sets `name` and unsets all other properties @@ -161,4 +161,4 @@ await Person.replaceOne({ _id }, { name: 'Jean-Luc Picard' }); ### Next Up Now that we've covered Documents, let's take a look at -[Subdocuments](/docs/subdocs.html). +[Subdocuments](../docs/subdocs.html). diff --git a/docs/faq.md b/docs/faq.md index 5dbeca8431a..70a12cf7488 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -396,7 +396,7 @@ Consider using a regex like `/^[a-f0-9]{24}$/` to test whether a string is exact **A**. In order to avoid executing a separate query for each document returned from the `find` query, Mongoose instead queries using (numDocuments * limit) as the limit. If you need the correct limit, you should use the -[perDocumentLimit](/docs/populate.html#limit-vs-perDocumentLimit) option (new in Mongoose 5.9.0). Just keep in +[perDocumentLimit](../docs/populate.html#limit-vs-perDocumentLimit) option (new in Mongoose 5.9.0). Just keep in mind that populate() will execute a separate query for each document.
diff --git a/docs/geojson.md b/docs/geojson.md index b88be069568..0ab628f553e 100644 --- a/docs/geojson.md +++ b/docs/geojson.md @@ -46,7 +46,7 @@ const citySchema = new mongoose.Schema({ }); ``` -Using [subdocuments](/docs/subdocs.html), you can define a common `pointSchema` and reuse it everywhere you want to store a GeoJSON point. +Using [subdocuments](../docs/subdocs.html), you can define a common `pointSchema` and reuse it everywhere you want to store a GeoJSON point. ```javascript const pointSchema = new mongoose.Schema({ @@ -127,7 +127,7 @@ a polygon representing the state of Colorado using [require:geojson.*driver query] ``` -Mongoose also has a [`within()` helper](/docs/api.html#query_Query-within) +Mongoose also has a [`within()` helper](../docs/api.html#query_Query-within) that's a shorthand for `$geoWithin`. ```javascript @@ -144,7 +144,7 @@ a 2dsphere index on a GeoJSON point: [require:geojson.*index$] ``` -You can also define a geospatial index using the [`Schema#index()` function](/docs/api/schema.html#schema_Schema-index) +You can also define a geospatial index using the [`Schema#index()` function](../docs/api/schema.html#schema_Schema-index) as shown below. ```javascript diff --git a/docs/guide.md b/docs/guide.md index 454dac270cf..08a8f72e032 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -1,7 +1,7 @@ ## Schemas If you haven't yet done so, please take a minute to read the [quickstart](./index.html) to get an idea of how Mongoose works. -If you are migrating from 5.x to 6.x please take a moment to read the [migration guide](/docs/migrating_to_6.html). +If you are migrating from 5.x to 6.x please take a moment to read the [migration guide](../docs/migrating_to_6.html).
  • Defining your schema
  • @@ -183,7 +183,7 @@ ways to add a static: - Add a function property to the second argument of the schema-constructor (`statics`) - Add a function property to `schema.statics` -- Call the [`Schema#static()` function](/docs/api.html#schema_Schema-static) +- Call the [`Schema#static()` function](../docs/api.html#schema_Schema-static) ```javascript @@ -449,7 +449,7 @@ console.log(person); // { n: 'Not Val' } ``` You can also declare aliases on nested paths. It is easier to use nested -schemas and [subdocuments](/docs/subdocs.html), but you can also declare +schemas and [subdocuments](../docs/subdocs.html), but you can also declare nested path aliases inline as long as you use the full nested path `nested.myProp` as the alias. @@ -506,9 +506,9 @@ Valid options:

    option: autoIndex

    -By default, Mongoose's [`init()` function](/docs/api.html#model_Model-init) +By default, Mongoose's [`init()` function](../docs/api.html#model_Model-init) creates all the indexes defined in your model's schema by calling -[`Model.createIndexes()`](/docs/api.html#model_Model-createIndexes) +[`Model.createIndexes()`](../docs/api.html#model_Model-createIndexes) after you successfully connect to MongoDB. Creating indexes automatically is great for development and test environments. But index builds can also create significant load on your production database. If you want to manage indexes @@ -521,7 +521,7 @@ Clock.ensureIndexes(callback); ``` The `autoIndex` option is set to `true` by default. You can change this -default by setting [`mongoose.set('autoIndex', false);`](/docs/api/mongoose.html#mongoose_Mongoose-set) +default by setting [`mongoose.set('autoIndex', false);`](../docs/api/mongoose.html#mongoose_Mongoose-set)

    option: autoCreate

    @@ -529,7 +529,7 @@ Before Mongoose builds indexes, it calls `Model.createCollection()` to create th Calling `createCollection()` sets the [collection's default collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) based on the [collation option](#collation) and establishes the collection as a capped collection if you set the [`capped` schema option](#capped). -You can disable this behavior by setting `autoCreate` to `false` using [`mongoose.set('autoCreate', false)`](/docs/api/mongoose.html#mongoose_Mongoose-set). +You can disable this behavior by setting `autoCreate` to `false` using [`mongoose.set('autoCreate', false)`](../docs/api/mongoose.html#mongoose_Mongoose-set). Like `autoIndex`, `autoCreate` is helpful for development and test environments, but you may want to disable it for production to avoid unnecessary database calls. Unfortunately, `createCollection()` cannot change an existing collection. @@ -609,7 +609,7 @@ const dataSchema = new Schema({..}, { collection: 'data' });

    option: discriminatorKey

    -When you define a [discriminator](/docs/discriminators.html), Mongoose adds a path to your +When you define a [discriminator](../docs/discriminators.html), Mongoose adds a path to your schema that stores which discriminator a document is an instance of. By default, Mongoose adds an `__t` path, but you can set `discriminatorKey` to overwrite this default. @@ -650,8 +650,8 @@ console.log(p.id); // undefined

    option: _id

    Mongoose assigns each of your schemas an `_id` field by default if one -is not passed into the [Schema](/docs/api.html#schema-js) constructor. -The type assigned is an [ObjectId](/docs/api.html#schema_Schema-Types) +is not passed into the [Schema](../docs/api.html#schema-js) constructor. +The type assigned is an [ObjectId](../docs/api.html#schema_Schema-Types) to coincide with MongoDB's default behavior. If you don't want an `_id` added to your schema at all, you may disable it using this option. @@ -724,7 +724,7 @@ sam.$isEmpty('inventory'); // false

    option: read

    -Allows setting [query#read](/docs/api.html#query_Query-read) options at the +Allows setting [query#read](../docs/api.html#query_Query-read) options at the schema level, providing us a way to apply default [ReadPreferences](http://docs.mongodb.org/manual/applications/replication/#replica-set-read-preference) to all queries derived from a model. @@ -911,11 +911,11 @@ console.log(m.toJSON()); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom console.log(JSON.stringify(m)); // { "_id": "504e0cd7dd992d9be2f20b6f", "name": "Max Headroom is my name" } ``` -To see all available `toJSON/toObject` options, read [this](/docs/api.html#document_Document-toObject). +To see all available `toJSON/toObject` options, read [this](../docs/api.html#document_Document-toObject).

    option: toObject

    -Documents have a [toObject](/docs/api.html#document_Document-toObject) method +Documents have a [toObject](../docs/api.html#document_Document-toObject) method which converts the mongoose document into a plain JavaScript object. This method accepts a few options. Instead of applying these options on a per-document basis, we may declare the options at the schema level and have @@ -935,7 +935,7 @@ const m = new M({ name: 'Max Headroom' }); console.log(m); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' } ``` -To see all available `toObject` options, read [this](/docs/api.html#document_Document-toObject). +To see all available `toObject` options, read [this](../docs/api.html#document_Document-toObject).

    option: typeKey

    @@ -1035,7 +1035,7 @@ const thing = new Thing({ name: 'no versioning please' }); thing.save(); // { name: 'no versioning please' } ``` -Mongoose _only_ updates the version key when you use [`save()`](/docs/api.html#document_Document-save). +Mongoose _only_ updates the version key when you use [`save()`](../docs/api.html#document_Document-save). If you use `update()`, `findOneAndUpdate()`, etc. Mongoose will **not** update the version key. As a workaround, you can use the below middleware. @@ -1350,12 +1350,12 @@ new Parent({ child: {} }).validateSync().errors;

    With ES6 Classes

    -Schemas have a [`loadClass()` method](/docs/api/schema.html#schema_Schema-loadClass) +Schemas have a [`loadClass()` method](../docs/api/schema.html#schema_Schema-loadClass) that you can use to create a Mongoose schema from an [ES6 class](https://thecodebarbarian.com/an-overview-of-es6-classes): -* [ES6 class methods](https://masteringjs.io/tutorials/fundamentals/class#methods) become [Mongoose methods](/docs/guide.html#methods) -* [ES6 class statics](https://masteringjs.io/tutorials/fundamentals/class#statics) become [Mongoose statics](/docs/guide.html#statics) -* [ES6 getters and setters](https://masteringjs.io/tutorials/fundamentals/class#getterssetters) become [Mongoose virtuals](/docs/tutorials/virtuals.html) +* [ES6 class methods](https://masteringjs.io/tutorials/fundamentals/class#methods) become [Mongoose methods](../docs/guide.html#methods) +* [ES6 class statics](https://masteringjs.io/tutorials/fundamentals/class#statics) become [Mongoose statics](../docs/guide.html#statics) +* [ES6 getters and setters](https://masteringjs.io/tutorials/fundamentals/class#getterssetters) become [Mongoose virtuals](../docs/tutorials/virtuals.html) Here's an example of using `loadClass()` to create a schema from an ES6 class: @@ -1398,4 +1398,4 @@ of use cases, including e-commerce, wikis, and appointment bookings.

    Next Up

    -Now that we've covered `Schemas`, let's take a look at [SchemaTypes](/docs/schematypes.html). +Now that we've covered `Schemas`, let's take a look at [SchemaTypes](../docs/schematypes.html). diff --git a/docs/guides.md b/docs/guides.md index ba4d6bbf2d4..2e8b230559b 100644 --- a/docs/guides.md +++ b/docs/guides.md @@ -5,45 +5,45 @@ integrating Mongoose with external tools and frameworks. ### Mongoose Core Concepts -* [Schemas](/docs/guide.html) -* [SchemaTypes](/docs/schematypes.html) -* [Connections](/docs/connections.html) -* [Models](/docs/models.html) -* [Documents](/docs/documents.html) -* [Subdocuments](/docs/subdocs.html) -* [Queries](/docs/queries.html) -* [Validation](/docs/validation.html) -* [Middleware](/docs/middleware.html) -* [Populate](/docs/populate.html) -* [Discriminators](/docs/discriminators.html) -* [Plugins](/docs/plugins.html) -* [Faster Mongoose Queries With Lean](/docs/tutorials/lean.html) -* [Query Casting](/docs/tutorials/query_casting.html) -* [findOneAndUpdate](/docs/tutorials/findoneandupdate.html) -* [Getters and Setters](/docs/tutorials/getters-setters.html) -* [Virtuals](/docs/tutorials/virtuals.html) +* [Schemas](../docs/guide.html) +* [SchemaTypes](../docs/schematypes.html) +* [Connections](../docs/connections.html) +* [Models](../docs/models.html) +* [Documents](../docs/documents.html) +* [Subdocuments](../docs/subdocs.html) +* [Queries](../docs/queries.html) +* [Validation](../docs/validation.html) +* [Middleware](../docs/middleware.html) +* [Populate](../docs/populate.html) +* [Discriminators](../docs/discriminators.html) +* [Plugins](../docs/plugins.html) +* [Faster Mongoose Queries With Lean](../docs/tutorials/lean.html) +* [Query Casting](../docs/tutorials/query_casting.html) +* [findOneAndUpdate](../docs/tutorials/findoneandupdate.html) +* [Getters and Setters](../docs/tutorials/getters-setters.html) +* [Virtuals](../docs/tutorials/virtuals.html) ### Advanced Topics -* [Working with Dates](/docs/tutorials/dates.html) -* [Custom Casting For Built-in Types](/docs/tutorials/custom-casting.html) -* [Custom SchemaTypes](/docs/customschematypes.html) -* [Advanced Schemas](/docs/advanced_schemas.html) +* [Working with Dates](../docs/tutorials/dates.html) +* [Custom Casting For Built-in Types](../docs/tutorials/custom-casting.html) +* [Custom SchemaTypes](../docs/customschematypes.html) +* [Advanced Schemas](../docs/advanced_schemas.html) ### Integrations -* [Promises](/docs/promises.html) -* [AWS Lambda](/docs/lambda.html) -* [Browser Library](/docs/browser.html) -* [GeoJSON](/docs/geojson.html) -* [Transactions](/docs/transactions.html) -* [MongoDB Driver Deprecation Warnings](/docs/deprecations.html) -* [Testing with Jest](/docs/jest.html) -* [SSL Connections](/docs/tutorials/ssl.html) +* [Promises](../docs/promises.html) +* [AWS Lambda](../docs/lambda.html) +* [Browser Library](../docs/browser.html) +* [GeoJSON](../docs/geojson.html) +* [Transactions](../docs/transactions.html) +* [MongoDB Driver Deprecation Warnings](../docs/deprecations.html) +* [Testing with Jest](../docs/jest.html) +* [SSL Connections](../docs/tutorials/ssl.html) ### Migration Guides -* [Mongoose 5.x to 6.x](/docs/migrating_to_6.html) -* [Mongoose 4.x to 5.x](/docs/migrating_to_5.html) -* [Mongoose 3.x to 4.x](/docs/migration.html) +* [Mongoose 5.x to 6.x](../docs/migrating_to_6.html) +* [Mongoose 4.x to 5.x](../docs/migrating_to_5.html) +* [Mongoose 3.x to 4.x](../docs/migration.html) diff --git a/docs/index.md b/docs/index.md index 82082723936..2f274878862 100644 --- a/docs/index.md +++ b/docs/index.md @@ -40,7 +40,7 @@ async function main() { For brevity, let's assume that all following code is within the `main()` function. -With Mongoose, everything is derived from a [Schema](/docs/guide.html). +With Mongoose, everything is derived from a [Schema](../docs/guide.html). Let's get a reference to it and define our kittens. ```javascript @@ -49,7 +49,7 @@ const kittySchema = new mongoose.Schema({ }); ``` -So far so good. We've got a schema with one property, `name`, which will be a `String`. The next step is compiling our schema into a [Model](/docs/models.html). +So far so good. We've got a schema with one property, `name`, which will be a `String`. The next step is compiling our schema into a [Model](../docs/models.html). ```javascript const Kitten = mongoose.model('Kitten', kittySchema); @@ -88,7 +88,7 @@ fluffy.speak(); // "Meow name is fluffy" ``` We have talking kittens! But we still haven't saved anything to MongoDB. -Each document can be saved to the database by calling its [save](/docs/api.html#model_Model-save) method. The first argument to the callback will be an error if any occurred. +Each document can be saved to the database by calling its [save](../docs/api.html#model_Model-save) method. The first argument to the callback will be an error if any occurred. ```javascript await fluffy.save(); @@ -96,7 +96,7 @@ fluffy.speak(); ``` Say time goes by and we want to display all the kittens we've seen. -We can access all of the kitten documents through our Kitten [model](/docs/models.html). +We can access all of the kitten documents through our Kitten [model](../docs/models.html). ```javascript const kittens = await Kitten.find(); @@ -104,7 +104,7 @@ console.log(kittens); ``` We just logged all of the kittens in our db to the console. -If we want to filter our kittens by name, Mongoose supports MongoDBs rich [querying](/docs/queries.html) syntax. +If we want to filter our kittens by name, Mongoose supports MongoDBs rich [querying](../docs/queries.html) syntax. ```javascript await Kitten.find({ name: /^fluff/ }); diff --git a/docs/middleware.md b/docs/middleware.md index bf5bf3709fb..3a03fda8f7e 100644 --- a/docs/middleware.md +++ b/docs/middleware.md @@ -28,12 +28,12 @@ Document middleware is supported for the following document functions. In Mongoose, a document is an instance of a `Model` class. In document middleware functions, `this` refers to the document. -* [validate](/docs/api/document.html#document_Document-validate) -* [save](/docs/api/model.html#model_Model-save) -* [remove](/docs/api/model.html#model_Model-remove) -* [updateOne](/docs/api/document.html#document_Document-updateOne) -* [deleteOne](/docs/api/model.html#model_Model-deleteOne) -* [init](/docs/api/document.html#document_Document-init) (note: init hooks are [synchronous](#synchronous)) +* [validate](../docs/api/document.html#document_Document-validate) +* [save](../docs/api/model.html#model_Model-save) +* [remove](../docs/api/model.html#model_Model-remove) +* [updateOne](../docs/api/document.html#document_Document-updateOne) +* [deleteOne](../docs/api/model.html#model_Model-deleteOne) +* [init](../docs/api/document.html#document_Document-init) (note: init hooks are [synchronous](#synchronous)) Query middleware is supported for the following Query functions. Query middleware executes when you call `exec()` or `then()` on a Query object, or `await` on a Query object. @@ -186,7 +186,7 @@ error `err1` and then throw an error `err2`, mongoose will report `err1`.

    Post middleware

    -[post](/docs/api.html#schema_Schema-post) middleware are executed _after_ +[post](../docs/api.html#schema_Schema-post) middleware are executed _after_ the hooked method and all of its `pre` middleware have completed. ```javascript @@ -229,7 +229,7 @@ schema.post('save', function(doc, next) {

    Define Middleware Before Compiling Models

    -Calling `pre()` or `post()` after [compiling a model](/docs/models.html#compiling) +Calling `pre()` or `post()` after [compiling a model](../docs/models.html#compiling) does **not** work in Mongoose in general. For example, the below `pre('save')` middleware will not fire. @@ -247,8 +247,8 @@ const user = new User({ name: 'test' }); user.save(); ``` -This means that you must add all middleware and [plugins](/docs/plugins.html) -**before** calling [`mongoose.model()`](/docs/api/mongoose.html#mongoose_Mongoose-model). +This means that you must add all middleware and [plugins](../docs/plugins.html) +**before** calling [`mongoose.model()`](../docs/api/mongoose.html#mongoose_Mongoose-model). The below script will print out "Hello from pre save": ```javascript @@ -266,7 +266,7 @@ user.save(); As a consequence, be careful about exporting Mongoose models from the same file that you define your schema. If you choose to use this pattern, you -must define [global plugins](/docs/api/mongoose.html#mongoose_Mongoose-plugin) +must define [global plugins](../docs/api/mongoose.html#mongoose_Mongoose-plugin) **before** calling `require()` on your model file. ```javascript @@ -314,10 +314,10 @@ doc.remove(); Model.remove(); ``` -You can pass options to [`Schema.pre()`](/docs/api.html#schema_Schema-pre) -and [`Schema.post()`](/docs/api.html#schema_Schema-post) to switch whether -Mongoose calls your `remove()` hook for [`Document.remove()`](/docs/api.html#model_Model-remove) -or [`Model.remove()`](/docs/api.html#model_Model-remove). Note here that you need to set both `document` and `query` properties in the passed object: +You can pass options to [`Schema.pre()`](../docs/api.html#schema_Schema-pre) +and [`Schema.post()`](../docs/api.html#schema_Schema-post) to switch whether +Mongoose calls your `remove()` hook for [`Document.remove()`](../docs/api.html#model_Model-remove) +or [`Model.remove()`](../docs/api.html#model_Model-remove). Note here that you need to set both `document` and `query` properties in the passed object: ```javascript // Only document middleware @@ -382,7 +382,7 @@ schema.pre('findOneAndUpdate', async function() { However, if you define `pre('updateOne')` document middleware, `this` will be the document being updated. That's because `pre('updateOne')` -document middleware hooks into [`Document#updateOne()`](/docs/api/document.html#document_Document-updateOne) +document middleware hooks into [`Document#updateOne()`](../docs/api/document.html#document_Document-updateOne) rather than `Query#updateOne()`. ```javascript @@ -510,4 +510,4 @@ rejections.

    Next Up

    Now that we've covered middleware, let's take a look at Mongoose's approach -to faking JOINs with its query [population](/docs/populate.html) helper. +to faking JOINs with its query [population](../docs/populate.html) helper. diff --git a/docs/migrating_to_5.md b/docs/migrating_to_5.md index 2df53f050c6..17f50029bbd 100644 --- a/docs/migrating_to_5.md +++ b/docs/migrating_to_5.md @@ -465,7 +465,7 @@ In Mongoose 5.x, the above code will correctly overwrite `'baseball'` with `{ $n Mongoose 5.x uses version 3.x of the [MongoDB Node.js driver](http://npmjs.com/package/mongodb). MongoDB driver 3.x changed the format of -the result of [`bulkWrite()` calls](/docs/api.html#model_Model-bulkWrite) so there is no longer a top-level `nInserted`, `nModified`, etc. property. The new result object structure is [described here](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~BulkWriteOpResult). +the result of [`bulkWrite()` calls](../docs/api.html#model_Model-bulkWrite) so there is no longer a top-level `nInserted`, `nModified`, etc. property. The new result object structure is [described here](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~BulkWriteOpResult). ```javascript const Model = mongoose.model('Test', new Schema({ name: String })); diff --git a/docs/plugins.md b/docs/plugins.md index 23a015b4ff7..9daa6b45a17 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -102,7 +102,7 @@ The Mongoose team maintains several plugins that add cool new features to Mongoose. Here's a couple: * [mongoose-autopopulate](http://plugins.mongoosejs.io/plugins/autopopulate): Always [`populate()`](/docs/populate.html) certain fields in your Mongoose schemas. -* [mongoose-lean-virtuals](http://plugins.mongoosejs.io/plugins/lean-virtuals): Attach virtuals to the results of Mongoose queries when using [`.lean()`](/docs/api.html#query_Query-lean). +* [mongoose-lean-virtuals](http://plugins.mongoosejs.io/plugins/lean-virtuals): Attach virtuals to the results of Mongoose queries when using [`.lean()`](../docs/api.html#query_Query-lean). * [mongoose-cast-aggregation](https://www.npmjs.com/package/mongoose-cast-aggregation) You can find a full list of officially supported plugins on [Mongoose's plugins search site](https://plugins.mongoosejs.io/). diff --git a/docs/populate.md b/docs/populate.md index e5abfa69a72..b8e2599db02 100644 --- a/docs/populate.md +++ b/docs/populate.md @@ -140,7 +140,7 @@ story.populated('author'); // undefined ``` A common reason for checking whether a path is populated is getting the `author` -id. However, for your convenience, Mongoose adds a [`_id` getter to ObjectId instances](/docs/api/mongoose.html#mongoose_Mongoose-set) +id. However, for your convenience, Mongoose adds a [`_id` getter to ObjectId instances](../docs/api/mongoose.html#mongoose_Mongoose-set) so you can use `story.author._id` regardless of whether `author` is populated. ```javascript @@ -476,7 +476,7 @@ This is known as a "cross-database populate," because it enables you to populate across MongoDB databases and even across MongoDB instances. If you don't have access to the model instance when defining your `eventSchema`, -you can also pass [the model instance as an option to `populate()`](/docs/api/model.html#model_Model-populate). +you can also pass [the model instance as an option to `populate()`](../docs/api/model.html#model_Model-populate). ```javascript const events = await Event. diff --git a/docs/schematypes.md b/docs/schematypes.md index 3c42ce365d6..9126aee9a4a 100644 --- a/docs/schematypes.md +++ b/docs/schematypes.md @@ -209,7 +209,7 @@ types. * `set`: function, defines a custom setter for this property using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). * `alias`: string, mongoose >= 4.10.0 only. Defines a [virtual](./guide.html#virtuals) with the given name that gets/sets this path. * `immutable`: boolean, defines path as immutable. Mongoose prevents you from changing immutable paths unless the parent document has `isNew: true`. -* `transform`: function, Mongoose calls this function when you call [`Document#toJSON()`](/docs/api/document.html#document_Document-toJSON) function, including when you [`JSON.stringify()`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript) a document. +* `transform`: function, Mongoose calls this function when you call [`Document#toJSON()`](../docs/api/document.html#document_Document-toJSON) function, including when you [`JSON.stringify()`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript) a document. ```javascript const numberSchema = new Schema({ diff --git a/docs/transactions.md b/docs/transactions.md index 0c63caa9377..57165de455a 100644 --- a/docs/transactions.md +++ b/docs/transactions.md @@ -12,8 +12,8 @@ If you haven't already, import mongoose: import mongoose from 'mongoose'; ``` -To create a transaction, you first need to create a session using or [`Mongoose#startSession`](/docs/api/mongoose.html#mongoose_Mongoose-startSession) -or [`Connection#startSession()`](/docs/api/connection.html#connection_Connection-startSession). +To create a transaction, you first need to create a session using or [`Mongoose#startSession`](../docs/api/mongoose.html#mongoose_Mongoose-startSession) +or [`Connection#startSession()`](../docs/api/connection.html#connection_Connection-startSession). ```javascript // Using Mongoose's default connection @@ -51,11 +51,11 @@ The `Connection#transaction()` function informs Mongoose change tracking that th

    With Mongoose Documents and save()

    -If you get a [Mongoose document](/docs/documents.html) from [`findOne()`](/docs/api.html#findone_findOne) -or [`find()`](/docs/api.html#find_find) using a session, the document will -keep a reference to the session and use that session for [`save()`](/docs/api.html#document_Document-save). +If you get a [Mongoose document](/docs/documents.html) from [`findOne()`](../docs/api.html#findone_findOne) +or [`find()`](../docs/api.html#find_find) using a session, the document will +keep a reference to the session and use that session for [`save()`](../docs/api.html#document_Document-save). -To get/set the session associated with a given document, use [`doc.$session()`](/docs/api.html#document_Document-$session). +To get/set the session associated with a given document, use [`doc.$session()`](../docs/api.html#document_Document-$session). ```javascript [require:transactions.*save] @@ -64,8 +64,8 @@ To get/set the session associated with a given document, use [`doc.$session()`](

    With the Aggregation Framework

    The `Model.aggregate()` function also supports transactions. Mongoose -aggregations have a [`session()` helper](/docs/api.html#aggregate_Aggregate-session) -that sets the [`session` option](/docs/api.html#aggregate_Aggregate-option). +aggregations have a [`session()` helper](../docs/api.html#aggregate_Aggregate-session) +that sets the [`session` option](../docs/api.html#aggregate_Aggregate-option). Below is an example of executing an aggregation within a transaction. ```javascript diff --git a/docs/tutorials/findoneandupdate.md b/docs/tutorials/findoneandupdate.md index 9492ddab78b..0395cfa3480 100644 --- a/docs/tutorials/findoneandupdate.md +++ b/docs/tutorials/findoneandupdate.md @@ -1,6 +1,6 @@ # How to Use `findOneAndUpdate()` in Mongoose -The [`findOneAndUpdate()` function in Mongoose](/docs/api.html#query_Query-findOneAndUpdate) has a wide variety of use cases. [You should use `save()` to update documents where possible](https://masteringjs.io/tutorials/mongoose/update), but there are some cases where you need to use [`findOneAndUpdate()`](https://masteringjs.io/tutorials/mongoose/findoneandupdate). In this tutorial, you'll see how to use `findOneAndUpdate()`, and learn when you need to use it. +The [`findOneAndUpdate()` function in Mongoose](../docs/api.html#query_Query-findOneAndUpdate) has a wide variety of use cases. [You should use `save()` to update documents where possible](https://masteringjs.io/tutorials/mongoose/update), but there are some cases where you need to use [`findOneAndUpdate()`](https://masteringjs.io/tutorials/mongoose/findoneandupdate). In this tutorial, you'll see how to use `findOneAndUpdate()`, and learn when you need to use it. * [Getting Started](#getting-started) * [Atomic Updates](#atomic-updates) diff --git a/docs/tutorials/getters-setters.md b/docs/tutorials/getters-setters.md index 044ca0ea406..a0684fc4cd1 100644 --- a/docs/tutorials/getters-setters.md +++ b/docs/tutorials/getters-setters.md @@ -37,7 +37,7 @@ const userSchema = new Schema({ }, { toJSON: { getters: false } }); ``` -To skip getters on a one-off basis, use [`user.get()` with the `getters` option set to `false`](/docs/api/document.html#document_Document-get) as shown below. +To skip getters on a one-off basis, use [`user.get()` with the `getters` option set to `false`](../docs/api/document.html#document_Document-get) as shown below. ```javascript [require:getters/setters.*getters.*skip] @@ -53,7 +53,7 @@ make it easy to search without worrying about case. Below is an example [require:getters/setters.*setters.*basic] ``` -Mongoose also runs setters on update operations, like [`updateOne()`](/docs/api/query.html#query_Query-updateOne). Mongoose will +Mongoose also runs setters on update operations, like [`updateOne()`](../docs/api/query.html#query_Query-updateOne). Mongoose will [upsert a document](https://masteringjs.io/tutorials/mongoose/upsert) with a lowercased `email` in the below example. diff --git a/docs/tutorials/lean.md b/docs/tutorials/lean.md index f5f1b28e1fe..f7d7fd325e7 100644 --- a/docs/tutorials/lean.md +++ b/docs/tutorials/lean.md @@ -1,7 +1,7 @@ # Faster Mongoose Queries With Lean -The [lean option](/docs/api.html#query_Query-lean) tells Mongoose to skip -[hydrating](/docs/api.html#model_Model-hydrate) the result documents. This +The [lean option](../docs/api.html#query_Query-lean) tells Mongoose to skip +[hydrating](../docs/api.html#model_Model-hydrate) the result documents. This makes queries faster and less memory intensive, but the result documents are plain old JavaScript objects (POJOs), **not** [Mongoose documents](/docs/documents.html). In this tutorial, you'll learn more about the tradeoffs of using `lean()`. @@ -14,7 +14,7 @@ In this tutorial, you'll learn more about the tradeoffs of using `lean()`.

    Using Lean

    By default, Mongoose queries return an instance of the -[Mongoose `Document` class](/docs/api.html#Document). Documents are much +[Mongoose `Document` class](../docs/api.html#Document). Documents are much heavier than vanilla JavaScript objects, because they have a lot of internal state for change tracking. Enabling the `lean` option tells Mongoose to skip instantiating a full Mongoose document and just give you the POJO. @@ -74,9 +74,9 @@ populated documents as well. In the below example, both the top-level If you're executing a query and sending the results without modification to, say, an [Express response](http://expressjs.com/en/4x/api.html#res), you should use lean. In general, if you do not modify the query results and do not use -[custom getters](/docs/api.html#schematype_SchemaType-get), you should use +[custom getters](../docs/api.html#schematype_SchemaType-get), you should use `lean()`. If you modify the query results or rely on features like getters -or [transforms](/docs/api.html#document_Document-toObject), you should not +or [transforms](../docs/api.html#document_Document-toObject), you should not use `lean()`. Below is an example of an [Express route](http://expressjs.com/en/guide/routing.html) @@ -119,7 +119,7 @@ to add virtuals to your lean query results. ## Plugins Using `lean()` bypasses all Mongoose features, including [virtuals](/docs/tutorials/virtuals.html), [getters/setters](/docs/tutorials/getters-setters.html), -and [defaults](/docs/api.html#schematype_SchemaType-default). If you want to +and [defaults](../docs/api.html#schematype_SchemaType-default). If you want to use these features with `lean()`, you need to use the corresponding plugin: - [mongoose-lean-virtuals](https://plugins.mongoosejs.io/plugins/lean-virtuals) diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index 02843ce86d0..edddfea3614 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -1,6 +1,6 @@ # SSL Connections -Mongoose supports connecting to [MongoDB clusters that require SSL connections](https://docs.mongodb.com/manual/tutorial/configure-ssl/). Setting the `ssl` option to `true` in [`mongoose.connect()`](/docs/api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using SSL: +Mongoose supports connecting to [MongoDB clusters that require SSL connections](https://docs.mongodb.com/manual/tutorial/configure-ssl/). Setting the `ssl` option to `true` in [`mongoose.connect()`](../docs/api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using SSL: ```javascript mongoose.connect('mongodb://localhost:27017/test', { ssl: true }); diff --git a/docs/tutorials/virtuals.md b/docs/tutorials/virtuals.md index 103ed34c571..bf8ce789e3c 100644 --- a/docs/tutorials/virtuals.md +++ b/docs/tutorials/virtuals.md @@ -18,13 +18,13 @@ want the email's domain. For example, the domain portion of 'test@gmail.com' is 'gmail.com'. Below is one way to implement the `domain` property using a virtual. -You define virtuals on a schema using the [`Schema#virtual()` function](/docs/api/schema.html#schema_Schema-virtual). +You define virtuals on a schema using the [`Schema#virtual()` function](../docs/api/schema.html#schema_Schema-virtual). ```javascript [require:Virtuals.*basic] ``` -The `Schema#virtual()` function returns a [`VirtualType` object](/docs/api/virtualtype.html). Unlike normal document properties, +The `Schema#virtual()` function returns a [`VirtualType` object](../docs/api/virtualtype.html). Unlike normal document properties, virtuals do not have any underlying value and Mongoose does not do any type coercion on virtuals. However, virtuals do have [getters and setters](/docs/tutorials/getters-setters.html), which make @@ -69,7 +69,7 @@ console.log(doc.toObject({ virtuals: true })); Virtuals are properties on Mongoose documents. If you use the [lean option](/docs/tutorials/lean.html), that means your queries return POJOs rather than full Mongoose documents. That means no virtuals if you use -[`lean()`](/docs/api/query.html#query_Query-lean). +[`lean()`](../docs/api/query.html#query_Query-lean). ```javascript [require:Virtuals.*lean] diff --git a/docs/validation.md b/docs/validation.md index 0607f4dc154..c918c5cc536 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -142,10 +142,10 @@ nested objects are not fully fledged paths. ### Update Validators In the above examples, you learned about document validation. Mongoose also -supports validation for [`update()`](/docs/api.html#query_Query-update), -[`updateOne()`](/docs/api.html#query_Query-updateOne), -[`updateMany()`](/docs/api.html#query_Query-updateMany), -and [`findOneAndUpdate()`](/docs/api.html#query_Query-findOneAndUpdate) operations. +supports validation for [`update()`](../docs/api.html#query_Query-update), +[`updateOne()`](../docs/api.html#query_Query-updateOne), +[`updateMany()`](../docs/api.html#query_Query-updateMany), +and [`findOneAndUpdate()`](../docs/api.html#query_Query-findOneAndUpdate) operations. Update validators are off by default - you need to specify the `runValidators` option. From d1a3c1dc6d33f5b0fd3ea011cd12bd7f9b7fdea4 Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 1 Nov 2022 13:36:52 -0700 Subject: [PATCH 017/112] add relative links to other non absolute links --- docs/migrating_to_6.md | 2 +- docs/models.md | 2 +- docs/plugins.md | 6 +++--- docs/populate.md | 2 +- docs/schematypes.md | 16 ++++++++-------- docs/transactions.md | 2 +- docs/tutorials/dates.md | 4 ++-- docs/tutorials/findoneandupdate.md | 2 +- docs/tutorials/getters-setters.md | 2 +- docs/tutorials/lean.md | 8 ++++---- docs/tutorials/ssl.md | 2 +- docs/tutorials/virtuals.md | 18 +++++++++--------- docs/typescript.md | 12 ++++++------ docs/typescript/schemas.md | 6 +++--- docs/typescript/statics-and-methods.md | 4 ++-- docs/typescript/statics.md | 2 +- docs/typescript/virtuals.md | 4 ++-- docs/validation.md | 4 ++-- 18 files changed, 49 insertions(+), 49 deletions(-) diff --git a/docs/migrating_to_6.md b/docs/migrating_to_6.md index 611997bef59..b46780b49ea 100644 --- a/docs/migrating_to_6.md +++ b/docs/migrating_to_6.md @@ -9,7 +9,7 @@ There are several [backwards-breaking changes](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) you should be aware of when migrating from Mongoose 5.x to Mongoose 6.x. -If you're still on Mongoose 4.x, please read the [Mongoose 4.x to 5.x migration guide](/docs/migrating_to_5.html) and upgrade to Mongoose 5.x first. +If you're still on Mongoose 4.x, please read the [Mongoose 4.x to 5.x migration guide](../docs/migrating_to_5.html) and upgrade to Mongoose 5.x first. * [Version Requirements](#version-requirements) * [MongoDB Driver 4.0](#mongodb-driver-40) diff --git a/docs/models.md b/docs/models.md index 16f57ce1e5f..be9c2a8e6bc 100644 --- a/docs/models.md +++ b/docs/models.md @@ -207,4 +207,4 @@ The [API docs](./api.html#model_Model) cover many additional methods available l ## Next Up -Now that we've covered `Models`, let's take a look at [Documents](/docs/documents.html). +Now that we've covered `Models`, let's take a look at [Documents](../docs/documents.html). diff --git a/docs/plugins.md b/docs/plugins.md index 9daa6b45a17..febbb7af79b 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -65,8 +65,8 @@ const Player = mongoose.model('Player', playerSchema);

    Apply Plugins Before Compiling Models

    -Because many plugins rely on [middleware](/docs/middleware.html), you should make sure to apply plugins **before** -you call `mongoose.model()` or `conn.model()`. Otherwise, [any middleware the plugin registers won't get applied](/docs/middleware.html#defining). +Because many plugins rely on [middleware](../docs/middleware.html), you should make sure to apply plugins **before** +you call `mongoose.model()` or `conn.model()`. Otherwise, [any middleware the plugin registers won't get applied](../docs/middleware.html#defining). ```javascript // loadedAt.js @@ -101,7 +101,7 @@ gameSchema.plugin(loadedAtPlugin); The Mongoose team maintains several plugins that add cool new features to Mongoose. Here's a couple: -* [mongoose-autopopulate](http://plugins.mongoosejs.io/plugins/autopopulate): Always [`populate()`](/docs/populate.html) certain fields in your Mongoose schemas. +* [mongoose-autopopulate](http://plugins.mongoosejs.io/plugins/autopopulate): Always [`populate()`](../docs/populate.html) certain fields in your Mongoose schemas. * [mongoose-lean-virtuals](http://plugins.mongoosejs.io/plugins/lean-virtuals): Attach virtuals to the results of Mongoose queries when using [`.lean()`](../docs/api.html#query_Query-lean). * [mongoose-cast-aggregation](https://www.npmjs.com/package/mongoose-cast-aggregation) diff --git a/docs/populate.md b/docs/populate.md index b8e2599db02..178a9958c38 100644 --- a/docs/populate.md +++ b/docs/populate.md @@ -743,7 +743,7 @@ AuthorSchema.virtual('posts', {

    Populating Maps

    -[Maps](/docs/schematypes.html#maps) are a type that represents an object with arbitrary +[Maps](../docs/schematypes.html#maps) are a type that represents an object with arbitrary string keys. For example, in the below schema, `members` is a map from strings to ObjectIds. ```javascript diff --git a/docs/schematypes.md b/docs/schematypes.md index 9126aee9a4a..d4bb251dd74 100644 --- a/docs/schematypes.md +++ b/docs/schematypes.md @@ -127,7 +127,7 @@ const schema = new Schema({ }); ``` -As a consequence, [you need a little extra work to define a property named `type` in your schema](/docs/faq.html#type-key). +As a consequence, [you need a little extra work to define a property named `type` in your schema](../docs/faq.html#type-key). For example, suppose you're building a stock portfolio app, and you want to store the asset's `type` (stock, bond, ETF, etc.). Naively, you might define your schema as shown below: @@ -261,14 +261,14 @@ const schema2 = new Schema({ * `enum`: Array, creates a [validator](./validation.html) that checks if the value is in the given array. * `minLength`: Number, creates a [validator](./validation.html) that checks if the value length is not less than the given number * `maxLength`: Number, creates a [validator](./validation.html) that checks if the value length is not greater than the given number -* `populate`: Object, sets default [populate options](/docs/populate.html#query-conditions) +* `populate`: Object, sets default [populate options](../docs/populate.html#query-conditions)
    Number
    * `min`: Number, creates a [validator](./validation.html) that checks if the value is greater than or equal to the given minimum. * `max`: Number, creates a [validator](./validation.html) that checks if the value is less than or equal to the given maximum. * `enum`: Array, creates a [validator](./validation.html) that checks if the value is strictly equal to one of the values in the given array. -* `populate`: Object, sets default [populate options](/docs/populate.html#query-conditions) +* `populate`: Object, sets default [populate options](../docs/populate.html#query-conditions)
    Date
    @@ -278,7 +278,7 @@ const schema2 = new Schema({
    ObjectId
    -* `populate`: Object, sets default [populate options](/docs/populate.html#query-conditions) +* `populate`: Object, sets default [populate options](../docs/populate.html#query-conditions)

    Usage Notes

    @@ -333,7 +333,7 @@ call it and assign the returned value to the path. The values `null` and `undefined` are not cast. NaN, strings that cast to NaN, arrays, and objects that don't have a `valueOf()` function -will all result in a [CastError](/docs/validation.html#cast-errors) once validated, meaning that it will not throw on initialization, only when validated. +will all result in a [CastError](../docs/validation.html#cast-errors) once validated, meaning that it will not throw on initialization, only when validated.

    Dates

    @@ -443,7 +443,7 @@ Mongoose casts the below values to `false`: * `'0'` * `'no'` -Any other value causes a [CastError](/docs/validation.html#cast-errors). +Any other value causes a [CastError](../docs/validation.html#cast-errors). You can modify what values Mongoose converts to true or false using the `convertToTrue` and `convertToFalse` properties, which are [JavaScript sets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). @@ -566,7 +566,7 @@ Map types are stored as [BSON objects in MongoDB](https://en.wikipedia.org/wiki/ Keys in a BSON object are ordered, so this means the [insertion order](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Description) property of maps is maintained. -Mongoose supports a special `$*` syntax to [populate](/docs/populate.html) all elements in a map. +Mongoose supports a special `$*` syntax to [populate](../docs/populate.html) all elements in a map. For example, suppose your `socialMediaHandles` map contains a `ref`: ```javascript @@ -720,4 +720,4 @@ including what validators it has and what the type is. ### Next Up -Now that we've covered `SchemaTypes`, let's take a look at [Connections](/docs/connections.html). +Now that we've covered `SchemaTypes`, let's take a look at [Connections](../docs/connections.html). diff --git a/docs/transactions.md b/docs/transactions.md index 57165de455a..825b9d3b12f 100644 --- a/docs/transactions.md +++ b/docs/transactions.md @@ -51,7 +51,7 @@ The `Connection#transaction()` function informs Mongoose change tracking that th

    With Mongoose Documents and save()

    -If you get a [Mongoose document](/docs/documents.html) from [`findOne()`](../docs/api.html#findone_findOne) +If you get a [Mongoose document](../docs/documents.html) from [`findOne()`](../docs/api.html#findone_findOne) or [`find()`](../docs/api.html#find_find) using a session, the document will keep a reference to the session and use that session for [`save()`](../docs/api.html#document_Document-save). diff --git a/docs/tutorials/dates.md b/docs/tutorials/dates.md index 582ed41ba6c..650b26afe76 100644 --- a/docs/tutorials/dates.md +++ b/docs/tutorials/dates.md @@ -13,7 +13,7 @@ const userSchema = new mongoose.Schema({ const User = mongoose.model('User', userSchema); ``` -When you create a user [document](/docs/documents.html), Mongoose will cast +When you create a user [document](../docs/documents.html), Mongoose will cast the value to a [native JavaScript date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) using the [`Date()` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Syntax). @@ -21,7 +21,7 @@ using the [`Date()` constructor](https://developer.mozilla.org/en-US/docs/Web/Ja [require:Date Tutorial.*Example 1.2] ``` -An invalid date will lead to a `CastError` when you [validate the document](/docs/validation.html). +An invalid date will lead to a `CastError` when you [validate the document](../docs/validation.html). ```javascript [require:Date Tutorial.*Example 1.3] diff --git a/docs/tutorials/findoneandupdate.md b/docs/tutorials/findoneandupdate.md index 0395cfa3480..ae18024386e 100644 --- a/docs/tutorials/findoneandupdate.md +++ b/docs/tutorials/findoneandupdate.md @@ -36,7 +36,7 @@ which has the same option. With the exception of an [unindexed upsert](https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/#upsert-with-unique-index), [`findOneAndUpdate()` is atomic](https://docs.mongodb.com/manual/core/write-operations-atomicity/#atomicity). That means you can assume the document doesn't change between when MongoDB finds the document and when it updates the document, _unless_ you're doing an [upsert](#upsert). -For example, if you're using `save()` to update a document, the document can change in MongoDB in between when you load the document using `findOne()` and when you save the document using `save()` as show below. For many use cases, the `save()` race condition is a non-issue. But you can work around it with `findOneAndUpdate()` (or [transactions](/docs/transactions.html)) if you need to. +For example, if you're using `save()` to update a document, the document can change in MongoDB in between when you load the document using `findOne()` and when you save the document using `save()` as show below. For many use cases, the `save()` race condition is a non-issue. But you can work around it with `findOneAndUpdate()` (or [transactions](../docs/transactions.html)) if you need to. ```javascript [require:Tutorial.*findOneAndUpdate.*save race condition] diff --git a/docs/tutorials/getters-setters.md b/docs/tutorials/getters-setters.md index a0684fc4cd1..33d142c38df 100644 --- a/docs/tutorials/getters-setters.md +++ b/docs/tutorials/getters-setters.md @@ -1,6 +1,6 @@ # Getters/Setters in Mongoose -Mongoose getters and setters allow you to execute custom logic when getting or setting a property on a [Mongoose document](/docs/documents.html). Getters let you transform data in MongoDB into a more user friendly form, and setters let you transform user data before it gets to MongoDB. +Mongoose getters and setters allow you to execute custom logic when getting or setting a property on a [Mongoose document](../docs/documents.html). Getters let you transform data in MongoDB into a more user friendly form, and setters let you transform user data before it gets to MongoDB. ## Getters diff --git a/docs/tutorials/lean.md b/docs/tutorials/lean.md index f7d7fd325e7..a9153d16318 100644 --- a/docs/tutorials/lean.md +++ b/docs/tutorials/lean.md @@ -3,7 +3,7 @@ The [lean option](../docs/api.html#query_Query-lean) tells Mongoose to skip [hydrating](../docs/api.html#model_Model-hydrate) the result documents. This makes queries faster and less memory intensive, but the result documents are -plain old JavaScript objects (POJOs), **not** [Mongoose documents](/docs/documents.html). +plain old JavaScript objects (POJOs), **not** [Mongoose documents](../docs/documents.html). In this tutorial, you'll learn more about the tradeoffs of using `lean()`. * [Using Lean](#using-lean) @@ -54,7 +54,7 @@ and virtuals don't run if you enable `lean`.

    Lean and Populate

    -[Populate](/docs/populate.html) works with `lean()`. If you +[Populate](../docs/populate.html) works with `lean()`. If you use both `populate()` and `lean()`, the `lean` option propagates to the populated documents as well. In the below example, both the top-level 'Group' documents and the populated 'Person' documents will be lean. @@ -63,7 +63,7 @@ populated documents as well. In the below example, both the top-level [require:Lean Tutorial.*conventional populate] ``` -[Virtual populate](/docs/populate.html#populate-virtuals) also works with lean. +[Virtual populate](../docs/populate.html#populate-virtuals) also works with lean. ```javascript [require:Lean Tutorial.*virtual populate] @@ -118,7 +118,7 @@ to add virtuals to your lean query results. ## Plugins -Using `lean()` bypasses all Mongoose features, including [virtuals](/docs/tutorials/virtuals.html), [getters/setters](/docs/tutorials/getters-setters.html), +Using `lean()` bypasses all Mongoose features, including [virtuals](../docs/tutorials/virtuals.html), [getters/setters](../docs/tutorials/getters-setters.html), and [defaults](../docs/api.html#schematype_SchemaType-default). If you want to use these features with `lean()`, you need to use the corresponding plugin: diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index edddfea3614..41826fb38e9 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -67,7 +67,7 @@ MongooseServerSelectionError: Hostname/IP does not match certificate's altnames: ``` The SSL certificate's [common name](https://knowledge.digicert.com/solution/SO7239.html) **must** line up with the host name -in your connection string. If the SSL certificate is for `hostname2.mydomain.com`, your connection string must connect to `hostname2.mydomain.com`, not any other hostname or IP address that may be equivalent to `hostname2.mydomain.com`. For replica sets, this also means that the SSL certificate's common name must line up with the [machine's `hostname`](/docs/connections.html#replicaset-hostnames). +in your connection string. If the SSL certificate is for `hostname2.mydomain.com`, your connection string must connect to `hostname2.mydomain.com`, not any other hostname or IP address that may be equivalent to `hostname2.mydomain.com`. For replica sets, this also means that the SSL certificate's common name must line up with the [machine's `hostname`](../docs/connections.html#replicaset-hostnames). ## X509 Auth diff --git a/docs/tutorials/virtuals.md b/docs/tutorials/virtuals.md index bf8ce789e3c..50e5db25c6e 100644 --- a/docs/tutorials/virtuals.md +++ b/docs/tutorials/virtuals.md @@ -27,13 +27,13 @@ You define virtuals on a schema using the [`Schema#virtual()` function](../docs/ The `Schema#virtual()` function returns a [`VirtualType` object](../docs/api/virtualtype.html). Unlike normal document properties, virtuals do not have any underlying value and Mongoose does not do any type coercion on virtuals. However, virtuals do have -[getters and setters](/docs/tutorials/getters-setters.html), which make +[getters and setters](../docs/tutorials/getters-setters.html), which make them ideal for computed properties, like the `domain` example above. ## Virtual Setters You can also use virtuals to set multiple properties at once as an -alternative to [custom setters on normal properties](/docs/tutorials/getters-setters.html#setters). For example, suppose +alternative to [custom setters on normal properties](../docs/tutorials/getters-setters.html#setters). For example, suppose you have two string properties: `firstName` and `lastName`. You can create a virtual property `fullName` that lets you set both of these properties at once. The key detail is that, in virtual getters and @@ -49,7 +49,7 @@ By default, Mongoose does not include virtuals when you convert a document to JS For example, if you pass a document to [Express' `res.json()` function](http://expressjs.com/en/4x/api.html#res.json), virtuals will **not** be included by default. To include virtuals in `res.json()`, you need to set the -[`toJSON` schema option](/docs/guide.html#toJSON) to `{ virtuals: true }`. +[`toJSON` schema option](../docs/guide.html#toJSON) to `{ virtuals: true }`. ```javascript [require:Virtuals.*toJSON] @@ -58,7 +58,7 @@ To include virtuals in `res.json()`, you need to set the ## Virtuals in `console.log()` By default, Mongoose does **not** include virtuals in `console.log()` output. -To include virtuals in `console.log()`, you need to set the [`toObject` schema option](/docs/guide.html#toObject) to `{ virtuals: true }`, or use `toObject()` before printing the object. +To include virtuals in `console.log()`, you need to set the [`toObject` schema option](../docs/guide.html#toObject) to `{ virtuals: true }`, or use `toObject()` before printing the object. ```javascript console.log(doc.toObject({ virtuals: true })); @@ -67,7 +67,7 @@ console.log(doc.toObject({ virtuals: true })); ## Virtuals with Lean Virtuals are properties on Mongoose documents. If you use the -[lean option](/docs/tutorials/lean.html), that means your queries return POJOs +[lean option](../docs/tutorials/lean.html), that means your queries return POJOs rather than full Mongoose documents. That means no virtuals if you use [`lean()`](../docs/api/query.html#query_Query-lean). @@ -90,11 +90,11 @@ based on Mongoose virtuals. ``` If you want to query by a computed property, you should set the property using -a [custom setter](/docs/tutorials/getters-setters.html) or [pre save middleware](/docs/middleware.html). +a [custom setter](../docs/tutorials/getters-setters.html) or [pre save middleware](../docs/middleware.html). ## Populate -Mongoose also supports [populating virtuals](/docs/populate.html). A populated +Mongoose also supports [populating virtuals](../docs/populate.html). A populated virtual contains documents from another collection. To define a populated virtual, you need to specify: @@ -107,8 +107,8 @@ virtual, you need to specify: ## Further Reading -* [Virtuals in Mongoose Schemas](/docs/guide.html#virtuals) -* [Populate Virtuals](/docs/populate.html#populate-virtuals) +* [Virtuals in Mongoose Schemas](../docs/guide.html#virtuals) +* [Populate Virtuals](../docs/populate.html#populate-virtuals) * [Mongoose Lean Virtuals plugin](https://plugins.mongoosejs.io/plugins/lean-virtuals) * [Getting Started With Mongoose Virtuals](https://masteringjs.io/tutorials/mongoose/virtuals) * [Understanding Virtuals in Mongoose](https://futurestud.io/tutorials/understanding-virtuals-in-mongoose) \ No newline at end of file diff --git a/docs/typescript.md b/docs/typescript.md index f6f2fc47d87..c7728629d96 100644 --- a/docs/typescript.md +++ b/docs/typescript.md @@ -9,9 +9,9 @@ This guide describes Mongoose's recommended approach to working with Mongoose in To get started with Mongoose in TypeScript, you need to: 1. Create an interface representing a document in MongoDB. -2. Create a [Schema](/docs/guide.html) corresponding to the document interface. +2. Create a [Schema](../docs/guide.html) corresponding to the document interface. 3. Create a Model. -4. [Connect to MongoDB](/docs/connections.html). +4. [Connect to MongoDB](../docs/connections.html). ```typescript import { Schema, model, connect } from 'mongoose'; @@ -91,7 +91,7 @@ const userSchema = new Schema({ }); ``` -That's because `Schema.Types.ObjectId` is a [class that inherits from SchemaType](/docs/schematypes.html), **not** the class you use to create a new MongoDB ObjectId. +That's because `Schema.Types.ObjectId` is a [class that inherits from SchemaType](../docs/schematypes.html), **not** the class you use to create a new MongoDB ObjectId. ### Using `extends Document` @@ -111,10 +111,10 @@ interface IUser extends Document { ``` This approach works, but we recommend your document interface _not_ extend `Document`. -Using `extends Document` makes it difficult for Mongoose to infer which properties are present on [query filters](/docs/queries.html), [lean documents](/docs/tutorials/lean.html), and other cases. +Using `extends Document` makes it difficult for Mongoose to infer which properties are present on [query filters](../docs/queries.html), [lean documents](../docs/tutorials/lean.html), and other cases. We recommend your document interface contain the properties defined in your schema and line up with what your documents look like in MongoDB. -Although you can add [instance methods](/docs/guide.html#methods) to your document interface, we do not recommend doing so. +Although you can add [instance methods](../docs/guide.html#methods) to your document interface, we do not recommend doing so. ### Using Custom Bindings @@ -129,4 +129,4 @@ However, before you do, please [open an issue on Mongoose's GitHub page](https:/ ### Next Up -Now that you've seen the basics of how to use Mongoose in TypeScript, let's take a look at [statics in TypeScript](/docs/typescript/statics-and-methods.html). +Now that you've seen the basics of how to use Mongoose in TypeScript, let's take a look at [statics in TypeScript](../docs/typescript/statics-and-methods.html). diff --git a/docs/typescript/schemas.md b/docs/typescript/schemas.md index 4c2db9b2b34..2a0db24770b 100644 --- a/docs/typescript/schemas.md +++ b/docs/typescript/schemas.md @@ -1,6 +1,6 @@ # Schemas in TypeScript -Mongoose [schemas](/docs/guide.html) are how you tell Mongoose what your documents look like. +Mongoose [schemas](../docs/guide.html) are how you tell Mongoose what your documents look like. Mongoose schemas are separate from TypeScript interfaces, so you need to define both a _document interface_ and a _schema_ until V6.3.1. Mongoose supports auto typed schemas so you don't need to define additional typescript interface anymore but you are still able to do so. Mongoose provides a `InferSchemaType`, which infers the type of the auto typed schema document when needed. @@ -95,7 +95,7 @@ The second generic param, `M`, is the model used with the schema. Mongoose uses The third generic param, `TInstanceMethods` is used to add types for instance methods defined in the schema. -The 4th param, `TQueryHelpers`, is used to add types for [chainable query helpers](/docs/typescript/query-helpers.html). +The 4th param, `TQueryHelpers`, is used to add types for [chainable query helpers](../docs/typescript/query-helpers.html). ## Schema vs Interface fields @@ -141,7 +141,7 @@ const schema = new Schema>({ }); ``` -This is because Mongoose has numerous features that add paths to your schema that should be included in the `DocType` interface without you explicitly putting these paths in the `Schema()` constructor. For example, [timestamps](https://masteringjs.io/tutorials/mongoose/timestamps) and [plugins](/docs/plugins.html). +This is because Mongoose has numerous features that add paths to your schema that should be included in the `DocType` interface without you explicitly putting these paths in the `Schema()` constructor. For example, [timestamps](https://masteringjs.io/tutorials/mongoose/timestamps) and [plugins](../docs/plugins.html). ## Arrays diff --git a/docs/typescript/statics-and-methods.md b/docs/typescript/statics-and-methods.md index b377538f006..17d7b0f3bac 100644 --- a/docs/typescript/statics-and-methods.md +++ b/docs/typescript/statics-and-methods.md @@ -5,7 +5,7 @@ With a little extra configuration, you can also register methods and statics in ## Methods -To define an [instance method](/docs/guide.html#methods) in TypeScript, create a new interface representing your instance methods. +To define an [instance method](../docs/guide.html#methods) in TypeScript, create a new interface representing your instance methods. You need to pass that interface as the 3rd generic parameter to the `Schema` constructor **and** as the 3rd generic parameter to `Model` as shown below. ```typescript @@ -41,7 +41,7 @@ const fullName: string = user.fullName(); // 'Jean-Luc Picard' ## Statics -Mongoose [models](/docs/models.html) do **not** have an explicit generic parameter for [statics](/docs/guide.html#statics). +Mongoose [models](../docs/models.html) do **not** have an explicit generic parameter for [statics](../docs/guide.html#statics). If your model has statics, we recommend creating an interface that [extends](https://www.typescriptlang.org/docs/handbook/interfaces.html) Mongoose's `Model` interface as shown below. ```typescript diff --git a/docs/typescript/statics.md b/docs/typescript/statics.md index c8f163c8b37..8624a14c192 100644 --- a/docs/typescript/statics.md +++ b/docs/typescript/statics.md @@ -1,6 +1,6 @@ # Statics in TypeScript -Mongoose [models](/docs/models.html) do **not** have an explicit generic parameter for [statics](/docs/guide.html#statics). +Mongoose [models](../docs/models.html) do **not** have an explicit generic parameter for [statics](../docs/guide.html#statics). If your model has statics, we recommend creating an interface that [extends](https://www.typescriptlang.org/docs/handbook/interfaces.html) Mongoose's `Model` interface as shown below. ```typescript diff --git a/docs/typescript/virtuals.md b/docs/typescript/virtuals.md index b73602960a2..e89032b53e7 100644 --- a/docs/typescript/virtuals.md +++ b/docs/typescript/virtuals.md @@ -1,6 +1,6 @@ # Virtuals in TypeScript -[Virtuals](/docs/tutorials/virtuals.html) are computed properties: you can access virtuals on hydrated Mongoose documents, but virtuals are **not** stored in MongoDB. +[Virtuals](../docs/tutorials/virtuals.html) are computed properties: you can access virtuals on hydrated Mongoose documents, but virtuals are **not** stored in MongoDB. Mongoose supports auto typed virtuals so you don't need to define additional typescript interface anymore but you are still able to do so. ### Automatically Inferred Types: @@ -29,7 +29,7 @@ const schema = new Schema( ``` ### Set virtuals type manually: -You shouldn't define virtuals in your TypeScript [document interface](/docs/typescript.html). +You shouldn't define virtuals in your TypeScript [document interface](../docs/typescript.html). Instead, you should define a separate interface for your virtuals, and pass this interface to `Model` and `Schema`. For example, suppose you have a `UserDoc` interface, and you want to define a `fullName` virtual. diff --git a/docs/validation.md b/docs/validation.md index c918c5cc536..95ca8b7f41c 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -62,7 +62,7 @@ Mongoose replaces `{VALUE}` with the value being validated. A common gotcha for beginners is that the `unique` option for schemas is *not* a validator. It's a convenient helper for building [MongoDB unique indexes](https://docs.mongodb.com/manual/core/index-unique/). -See the [FAQ](/docs/faq.html) for more information. +See the [FAQ](../docs/faq.html) for more information. ```javascript [require:The `unique` Option is Not a Validator] @@ -210,4 +210,4 @@ of the array. ### Next Up -Now that we've covered `Validation`, let's take a look at [Middleware](/docs/middleware.html). +Now that we've covered `Validation`, let's take a look at [Middleware](../docs/middleware.html). From ef4720613e304e277cfc3d78e91f9e7546852ed7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 23:03:50 +0000 Subject: [PATCH 018/112] chore(deps-dev): bump sinon from 14.0.0 to 14.0.1 Bumps [sinon](https://github.com/sinonjs/sinon) from 14.0.0 to 14.0.1. - [Release notes](https://github.com/sinonjs/sinon/releases) - [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md) - [Commits](https://github.com/sinonjs/sinon/compare/v14.0.0...v14.0.1) --- updated-dependencies: - dependency-name: sinon dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0035f596c32..7eaea2e9817 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "nyc": "15.1.0", "pug": "3.0.2", "q": "1.5.1", - "sinon": "14.0.0", + "sinon": "14.0.1", "stream-browserify": "3.0.0", "ts-benchmark": "^1.1.10", "tsd": "0.24.1", From 60d6a302d3add65be1693d5af4b224ae68dce9d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 23:04:25 +0000 Subject: [PATCH 019/112] chore(deps-dev): bump @typescript-eslint/eslint-plugin Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.38.1 to 5.42.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.42.0/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0035f596c32..a274bd0f079 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "devDependencies": { "@babel/core": "7.19.3", "@babel/preset-env": "7.19.3", - "@typescript-eslint/eslint-plugin": "5.38.1", + "@typescript-eslint/eslint-plugin": "5.42.0", "@typescript-eslint/parser": "5.38.1", "acquit": "1.2.1", "acquit-ignore": "0.2.0", From 2730f14e7c71cc551085040f4a639689a4df0e33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 23:04:41 +0000 Subject: [PATCH 020/112] chore(deps-dev): bump eslint from 8.24.0 to 8.26.0 Bumps [eslint](https://github.com/eslint/eslint) from 8.24.0 to 8.26.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.24.0...v8.26.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0035f596c32..38676ee8d3a 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "cheerio": "1.0.0-rc.12", "crypto-browserify": "3.12.0", "dox": "1.0.0", - "eslint": "8.24.0", + "eslint": "8.26.0", "eslint-plugin-mocha-no-only": "1.1.1", "express": "^4.18.1", "highlight.js": "11.6.0", From 2ae56766ccbe1637327276b101030a43758e65e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 23:04:58 +0000 Subject: [PATCH 021/112] chore(deps-dev): bump axios from 0.27.2 to 1.1.3 Bumps [axios](https://github.com/axios/axios) from 0.27.2 to 1.1.3. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.27.2...v1.1.3) --- updated-dependencies: - dependency-name: axios dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0035f596c32..e69cdf7eb6f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "acquit-ignore": "0.2.0", "acquit-require": "0.1.1", "assert-browserify": "2.0.0", - "axios": "0.27.2", + "axios": "1.1.3", "babel-loader": "8.2.5", "benchmark": "2.1.4", "bluebird": "3.7.2", From 305225c9c068c7118f4582fa08be29d2ada71fc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 23:05:10 +0000 Subject: [PATCH 022/112] chore(deps-dev): bump mongodb-memory-server from 8.9.3 to 8.9.5 Bumps [mongodb-memory-server](https://github.com/nodkz/mongodb-memory-server/tree/HEAD/packages/mongodb-memory-server) from 8.9.3 to 8.9.5. - [Release notes](https://github.com/nodkz/mongodb-memory-server/releases) - [Changelog](https://github.com/nodkz/mongodb-memory-server/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodkz/mongodb-memory-server/commits/v8.9.5/packages/mongodb-memory-server) --- updated-dependencies: - dependency-name: mongodb-memory-server dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0035f596c32..64a4432a764 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "mkdirp": "^1.0.4", "mocha": "10.0.0", "moment": "2.x", - "mongodb-memory-server": "8.9.3", + "mongodb-memory-server": "8.9.5", "ncp": "^2.0.0", "nyc": "15.1.0", "pug": "3.0.2", From f482cbf4a8fa1281cd68bab0432497cf5135a23e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 23:05:42 +0000 Subject: [PATCH 023/112] chore(deps-dev): bump @babel/core from 7.19.3 to 7.19.6 Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.19.3 to 7.19.6. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.19.6/packages/babel-core) --- updated-dependencies: - dependency-name: "@babel/core" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0035f596c32..a1a4e017c30 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "sift": "16.0.0" }, "devDependencies": { - "@babel/core": "7.19.3", + "@babel/core": "7.19.6", "@babel/preset-env": "7.19.3", "@typescript-eslint/eslint-plugin": "5.38.1", "@typescript-eslint/parser": "5.38.1", From e7fcf43dcd0db8543569fc010fdf56ed598f8232 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 23:06:53 +0000 Subject: [PATCH 024/112] chore(deps): bump actions/setup-node from 3.5.0 to 3.5.1 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3.5.0 to 3.5.1. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/969bd2663942d722d85b6a8626225850c2f7be4b...8c91899e586c5b171469028077307d293428b516) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/benchmark.yml | 2 +- .github/workflows/documentation.yml | 2 +- .github/workflows/test.yml | 6 +++--- .github/workflows/tidelift-alignment.yml | 2 +- .github/workflows/tsd.yml | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 6082c98ed66..f9530cf8676 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -26,7 +26,7 @@ jobs: with: fetch-depth: 0 - name: Setup node - uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # v3.5.0 + uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: node-version: 16 diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 34265422137..d3ef9cacb67 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # v3 - name: Setup node - uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # v3.5.0 + uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: node-version: 16 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4cb2d684a6f..3ee1c9b2fbf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - name: Setup node - uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # v3.5.0 + uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: node-version: 14 @@ -62,7 +62,7 @@ jobs: - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - name: Setup node - uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # v3.5.0 + uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: node-version: ${{ matrix.node }} @@ -95,7 +95,7 @@ jobs: steps: - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - name: Setup node - uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # v3.5.0 + uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: node-version: 16 - run: npm install diff --git a/.github/workflows/tidelift-alignment.yml b/.github/workflows/tidelift-alignment.yml index fdad44d641a..8f5564f119d 100644 --- a/.github/workflows/tidelift-alignment.yml +++ b/.github/workflows/tidelift-alignment.yml @@ -17,7 +17,7 @@ jobs: - name: Checkout uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - name: Setup node - uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # v3.5.0 + uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: node-version: 16 - name: Alignment diff --git a/.github/workflows/tsd.yml b/.github/workflows/tsd.yml index cecbed7153a..76fd0b7814a 100644 --- a/.github/workflows/tsd.yml +++ b/.github/workflows/tsd.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - name: Setup node - uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # v3.5.0 + uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: node-version: 14 @@ -43,7 +43,7 @@ jobs: - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - name: Setup node - uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # v3.5.0 + uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: node-version: 12 From 2daac25d0a93254b05d75ba46ec82f214144c8a2 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 1 Nov 2022 20:11:09 -0400 Subject: [PATCH 025/112] test(types): add test coverage for #12431 --- test/types/schema.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 1eddc97363d..794bacba0fa 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -860,3 +860,13 @@ function gh12242() { type Example = InferSchemaType; expectType<0 | 1>({} as Example['active']); } + +function gh12431() { + const testSchema = new Schema({ + testDate: { type: Date }, + testDecimal: { type: Schema.Types.Decimal128 }, + }); + + type Example = InferSchemaType; + expectType<{ testDate?: Date, testDecimal?: Types.Decimal128 }>({} as Example); +} From 36fff7090d336a4d411db5831883978d75015bd8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Nov 2022 06:16:58 +0000 Subject: [PATCH 026/112] chore(deps-dev): bump mocha from 10.0.0 to 10.1.0 Bumps [mocha](https://github.com/mochajs/mocha) from 10.0.0 to 10.1.0. - [Release notes](https://github.com/mochajs/mocha/releases) - [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md) - [Commits](https://github.com/mochajs/mocha/compare/v10.0.0...v10.1.0) --- updated-dependencies: - dependency-name: mocha dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 023fd1cca46..d511a88af98 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "lodash.isequalwith": "4.4.0", "marked": "4.1.1", "mkdirp": "^1.0.4", - "mocha": "10.0.0", + "mocha": "10.1.0", "moment": "2.x", "mongodb-memory-server": "8.9.5", "ncp": "^2.0.0", From 1c7f196d006dce57be17f2d2ddb8e780c93ff7ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Nov 2022 06:17:01 +0000 Subject: [PATCH 027/112] chore(deps): bump sift from 16.0.0 to 16.0.1 Bumps [sift](https://github.com/crcn/sift.js) from 16.0.0 to 16.0.1. - [Release notes](https://github.com/crcn/sift.js/releases) - [Changelog](https://github.com/crcn/sift.js/blob/master/changelog.md) - [Commits](https://github.com/crcn/sift.js/commits) --- updated-dependencies: - dependency-name: sift dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 023fd1cca46..1b132ce116d 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "mpath": "0.9.0", "mquery": "4.0.3", "ms": "2.1.3", - "sift": "16.0.0" + "sift": "16.0.1" }, "devDependencies": { "@babel/core": "7.19.6", From 308bee9ae17194d828ee385e2fadda1a21af1848 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Nov 2022 06:17:46 +0000 Subject: [PATCH 028/112] chore(deps-dev): bump @babel/preset-env from 7.19.3 to 7.19.4 Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.19.3 to 7.19.4. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.19.4/packages/babel-preset-env) --- updated-dependencies: - dependency-name: "@babel/preset-env" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 023fd1cca46..1990a04a638 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ }, "devDependencies": { "@babel/core": "7.19.6", - "@babel/preset-env": "7.19.3", + "@babel/preset-env": "7.19.4", "@typescript-eslint/eslint-plugin": "5.42.0", "@typescript-eslint/parser": "5.38.1", "acquit": "1.2.1", From e3427df446d5622d8435b3967093f9d86d3a350d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Nov 2022 06:21:37 +0000 Subject: [PATCH 029/112] chore(deps-dev): bump @typescript-eslint/parser from 5.38.1 to 5.42.0 Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.38.1 to 5.42.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.42.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9781a307d1b..0bb6e559e22 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@babel/core": "7.19.6", "@babel/preset-env": "7.19.4", "@typescript-eslint/eslint-plugin": "5.42.0", - "@typescript-eslint/parser": "5.38.1", + "@typescript-eslint/parser": "5.42.0", "acquit": "1.2.1", "acquit-ignore": "0.2.0", "acquit-require": "0.1.1", From 0b0937e41aa813b0d3d293992b66cbf1d53d19d6 Mon Sep 17 00:00:00 2001 From: Hafez Date: Wed, 2 Nov 2022 07:35:19 +0100 Subject: [PATCH 030/112] lint: remove dangling comma --- test/types/schema.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 794bacba0fa..86e4d2668a4 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -864,7 +864,7 @@ function gh12242() { function gh12431() { const testSchema = new Schema({ testDate: { type: Date }, - testDecimal: { type: Schema.Types.Decimal128 }, + testDecimal: { type: Schema.Types.Decimal128 } }); type Example = InferSchemaType; From e88b43c016f46d4fc73e56e9528b79f5bb7c56b6 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Wed, 2 Nov 2022 09:59:45 +0100 Subject: [PATCH 031/112] Removed v5 link from v6 docs fix #12624 --- docs/connections.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/connections.md b/docs/connections.md index 1a7935adb1a..3ab10f04c2e 100644 --- a/docs/connections.md +++ b/docs/connections.md @@ -31,7 +31,6 @@ See the [mongodb connection string spec](http://docs.mongodb.org/manual/referenc
  • Multi-mongos support
  • Multiple connections
  • Connection Pools
  • -
  • Option Changes in v5.x

Operation Buffering

From 74af5f5b34cc7fcf631e1e323f18df36c74f6201 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Wed, 2 Nov 2022 10:16:50 +0100 Subject: [PATCH 032/112] fix(type): pre hook with deleteOne should resolve this as query fix #12622 --- test/types/models.test.ts | 8 ++++++++ types/index.d.ts | 12 ++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/test/types/models.test.ts b/test/types/models.test.ts index 19c598c63a4..c6678a5a0d1 100644 --- a/test/types/models.test.ts +++ b/test/types/models.test.ts @@ -192,6 +192,14 @@ projectSchema.post('save', function() { // this => IProject }); +projectSchema.pre('deleteOne', function() { + this.model; +}); + +projectSchema.post('deleteOne', function() { + this.model; +}); + projectSchema.methods.myMethod = () => 10; projectSchema.statics.myStatic = () => 42; diff --git a/types/index.d.ts b/types/index.d.ts index 3c1e7c2563e..97663a46d84 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -274,19 +274,19 @@ declare module 'mongoose' { plugin, POptions extends Parameters[1] = Parameters[1]>(fn: PFunc, opts?: POptions): this; /** Defines a post hook for the model. */ - post>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PostMiddlewareFunction): this; - post>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction): this; post>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, fn: PostMiddlewareFunction>): this; post>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction>): this; + post>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PostMiddlewareFunction): this; + post>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction): this; post>(method: 'aggregate' | RegExp, fn: PostMiddlewareFunction>>): this; post>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction>>): this; post(method: 'insertMany' | RegExp, fn: PostMiddlewareFunction): this; post(method: 'insertMany' | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction): this; - post>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: ErrorHandlingMiddlewareFunction): this; - post>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction): this; post>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, fn: ErrorHandlingMiddlewareFunction): this; post>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction): this; + post>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: ErrorHandlingMiddlewareFunction): this; + post>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction): this; post>(method: 'aggregate' | RegExp, fn: ErrorHandlingMiddlewareFunction>): this; post>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction>): this; post(method: 'insertMany' | RegExp, fn: ErrorHandlingMiddlewareFunction): this; @@ -295,10 +295,10 @@ declare module 'mongoose' { /** Defines a pre hook for the model. */ pre>(method: 'save', fn: PreSaveMiddlewareFunction): this; pre>(method: 'save', options: SchemaPreOptions, fn: PreSaveMiddlewareFunction): this; - pre>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PreMiddlewareFunction): this; - pre>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction): this; pre>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, fn: PreMiddlewareFunction): this; pre>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction): this; + pre>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PreMiddlewareFunction): this; + pre>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction): this; pre>(method: 'aggregate' | RegExp, fn: PreMiddlewareFunction): this; pre>(method: 'aggregate' | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction): this; pre(method: 'insertMany' | RegExp, fn: (this: T, next: (err?: CallbackError) => void, docs: any | Array) => void | Promise): this; From b66f4577110e71190e08d2b7693e91e6472e3856 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Nov 2022 09:38:33 +0000 Subject: [PATCH 033/112] chore(deps-dev): bump marked from 4.1.1 to 4.2.1 Bumps [marked](https://github.com/markedjs/marked) from 4.1.1 to 4.2.1. - [Release notes](https://github.com/markedjs/marked/releases) - [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json) - [Commits](https://github.com/markedjs/marked/compare/v4.1.1...v4.2.1) --- updated-dependencies: - dependency-name: marked dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 529c053d86e..21725e94703 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "highlight.js": "11.6.0", "lodash.isequal": "4.5.0", "lodash.isequalwith": "4.4.0", - "marked": "4.1.1", + "marked": "4.2.1", "mkdirp": "^1.0.4", "mocha": "10.1.0", "moment": "2.x", From 76e594036679771136ee3a4142db2896eb6012ec Mon Sep 17 00:00:00 2001 From: hasezoey Date: Wed, 2 Nov 2022 11:46:40 +0100 Subject: [PATCH 034/112] chore(workflows): update actions/checkout to 3.1.0 also consistenize the versions --- .github/workflows/benchmark.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/documentation.yml | 2 +- .github/workflows/test.yml | 8 ++++---- .github/workflows/tidelift-alignment.yml | 2 +- .github/workflows/tsd.yml | 6 +++--- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index f9530cf8676..131200b6b03 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-20.04 name: Benchmark TypeScript Types steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 with: fetch-depth: 0 - name: Setup node diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9c78ef14c90..e3c4adee9f3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index d3ef9cacb67..74295debf20 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-20.04 name: Test Generating Docs steps: - - uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # v3 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Setup node uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3ee1c9b2fbf..d10fdcc29aa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest name: Lint JS-Files steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Setup node uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 @@ -59,7 +59,7 @@ jobs: MONGOMS_VERSION: ${{ matrix.mongodb }} MONGOMS_PREFER_GLOBAL_PATH: 1 steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Setup node uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 @@ -93,7 +93,7 @@ jobs: runs-on: ubuntu-latest name: Replica Set tests steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Setup node uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: @@ -110,6 +110,6 @@ jobs: contents: read steps: - name: Check out repo - uses: actions/checkout@v3 + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Dependency review uses: actions/dependency-review-action@v2 diff --git a/.github/workflows/tidelift-alignment.yml b/.github/workflows/tidelift-alignment.yml index 8f5564f119d..f825b90e552 100644 --- a/.github/workflows/tidelift-alignment.yml +++ b/.github/workflows/tidelift-alignment.yml @@ -15,7 +15,7 @@ jobs: if: github.repository == 'Automattic/mongoose' steps: - name: Checkout - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Setup node uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 with: diff --git a/.github/workflows/tsd.yml b/.github/workflows/tsd.yml index 76fd0b7814a..4e6ba4b102c 100644 --- a/.github/workflows/tsd.yml +++ b/.github/workflows/tsd.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest name: Lint TS-Files steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Setup node uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest name: Test Typescript Types steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Setup node uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 @@ -50,4 +50,4 @@ jobs: - run: npm install - name: Typings - run: npm run test-tsd \ No newline at end of file + run: npm run test-tsd From 80f597f3b592f7918d1aa6931d405af7a09880cd Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 2 Nov 2022 10:58:27 -0400 Subject: [PATCH 035/112] fix(types): make array paths optional in inferred type of array default returns undefined Fix #12420 --- test/types/schema.test.ts | 12 ++++++++++++ types/inferschematype.d.ts | 8 +++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 86e4d2668a4..7ca2dfa90f1 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -870,3 +870,15 @@ function gh12431() { type Example = InferSchemaType; expectType<{ testDate?: Date, testDecimal?: Types.Decimal128 }>({} as Example); } + +function gh12420() { + const TestSchema = new Schema( + { + comments: { type: [String], default: () => undefined } + } + ); + + expectType<{ + comments?: string[] + }>({} as InferSchemaType); +} diff --git a/types/inferschematype.d.ts b/types/inferschematype.d.ts index a0406388f00..27090b89eb4 100644 --- a/types/inferschematype.d.ts +++ b/types/inferschematype.d.ts @@ -60,6 +60,12 @@ declare module 'mongoose' { : unknown; } +type IsPathDefaultUndefined = PathType extends { default: undefined } ? + true : + PathType extends { default: (...args: any[]) => undefined } ? + true : + false; + /** * @summary Checks if a document path is required or optional. * @param {P} P Document path. @@ -69,7 +75,7 @@ type IsPathRequired = P extends { required: true | [true, string | undefined] } | ArrayConstructor | any[] ? true : P extends (Record) - ? P extends { default: undefined } + ? IsPathDefaultUndefined

extends true ? false : true : P extends (Record) From cea218c04439c0937a7acfa3e148afdefd60fa76 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Wed, 2 Nov 2022 12:30:32 -0400 Subject: [PATCH 036/112] initial commit --- lib/error/validator.js | 9 +++++---- lib/schematype.js | 14 +++++++------- test/schema.validation.test.js | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/lib/error/validator.js b/lib/error/validator.js index 6d54fe7f4f7..ba4195264a1 100644 --- a/lib/error/validator.js +++ b/lib/error/validator.js @@ -12,15 +12,16 @@ class ValidatorError extends MongooseError { * Schema validator error * * @param {Object} properties + * @param {Object} doc * @api private */ - constructor(properties) { + constructor(properties, doc) { let msg = properties.message; if (!msg) { msg = MongooseError.messages.general.default; } - const message = formatMessage(msg, properties); + const message = formatMessage(msg, properties, doc); super(message); properties = Object.assign({}, properties, { message: message }); @@ -75,9 +76,9 @@ ValidatorError.prototype.formatMessage = formatMessage; * @api private */ -function formatMessage(msg, properties) { +function formatMessage(msg, properties, doc) { if (typeof msg === 'function') { - return msg(properties); + return msg(properties, doc); } const propertyNames = Object.keys(properties); diff --git a/lib/schematype.js b/lib/schematype.js index 21d2f034755..6c1863febe5 100644 --- a/lib/schematype.js +++ b/lib/schematype.js @@ -1290,7 +1290,7 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) { validatorProperties.value = value; if (validator instanceof RegExp) { - validate(validator.test(value), validatorProperties); + validate(validator.test(value), validatorProperties, scope); continue; } @@ -1299,7 +1299,7 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) { } if (value === undefined && validator !== this.requiredValidator) { - validate(true, validatorProperties); + validate(true, validatorProperties, scope); continue; } @@ -1319,19 +1319,19 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) { if (ok != null && typeof ok.then === 'function') { ok.then( - function(ok) { validate(ok, validatorProperties); }, + function(ok) { validate(ok, validatorProperties, scope); }, function(error) { validatorProperties.reason = error; validatorProperties.message = error.message; ok = false; - validate(ok, validatorProperties); + validate(ok, validatorProperties, scope); }); } else { - validate(ok, validatorProperties); + validate(ok, validatorProperties, scope); } } - function validate(ok, validatorProperties) { + function validate(ok, validatorProperties, scope) { if (err) { return; } @@ -1343,7 +1343,7 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) { } } else { const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError; - err = new ErrorConstructor(validatorProperties); + err = new ErrorConstructor(validatorProperties, scope); err[validatorErrorSymbol] = true; immediate(function() { fn(err); diff --git a/test/schema.validation.test.js b/test/schema.validation.test.js index 0d292339aca..22cec7e708c 100644 --- a/test/schema.validation.test.js +++ b/test/schema.validation.test.js @@ -1330,6 +1330,26 @@ describe('schema', function() { }); }); + it('Allows for doc to be passed as another parameter gh-12564', function(done) { + const s = mongoose.Schema({ + n: { + type: String, + // required: true, + required: [true, function(properties, doc) { + return 'fail ' + properties.path + ' on doc ' + doc; + }] + }, + field: String + }); + const M = mongoose.model('gh6523-2', s); + const m = new M({ field: 'Yo' }); + + m.validate(function(error) { + assert.notEqual('fail n on doc undefined', error.errors['n'].message); + done(); + }); + }); + it('evaluate message function for required field gh6523', function(done) { const s = mongoose.Schema({ n: { From 0b78e822945c854b5fc97f2fe07e8160ae2c5b47 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 2 Nov 2022 12:32:17 -0400 Subject: [PATCH 037/112] fix(types): add UUID to types Fix #12593 Re: #12268 Re: #3208 --- test/types/schema.test.ts | 7 +++++++ types/inferschematype.d.ts | 18 ++++++++++-------- types/schematypes.d.ts | 5 +++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 86e4d2668a4..f5a938e2fb8 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -870,3 +870,10 @@ function gh12431() { type Example = InferSchemaType; expectType<{ testDate?: Date, testDecimal?: Types.Decimal128 }>({} as Example); } + +function gh12593() { + const testSchema = new Schema({ x: { type: Schema.Types.UUID } }); + + type Example = InferSchemaType; + expectType<{ x?: Buffer }>({} as Example); +} diff --git a/types/inferschematype.d.ts b/types/inferschematype.d.ts index a0406388f00..4051b861be7 100644 --- a/types/inferschematype.d.ts +++ b/types/inferschematype.d.ts @@ -171,11 +171,13 @@ type ResolvePathType extends true ? Types.Decimal128 : IfEquals extends true ? Types.Decimal128 : - PathValueType extends MapConstructor ? Map> : - PathValueType extends ArrayConstructor ? any[] : - PathValueType extends typeof Schema.Types.Mixed ? any: - IfEquals extends true ? any: - IfEquals extends true ? any: - PathValueType extends typeof SchemaType ? PathValueType['prototype'] : - PathValueType extends Record ? ObtainDocumentType : - unknown; + PathValueType extends 'uuid' | 'UUID' | typeof Schema.Types.UUID ? Buffer : + IfEquals extends true ? Buffer : + PathValueType extends MapConstructor ? Map> : + PathValueType extends ArrayConstructor ? any[] : + PathValueType extends typeof Schema.Types.Mixed ? any: + IfEquals extends true ? any: + IfEquals extends true ? any: + PathValueType extends typeof SchemaType ? PathValueType['prototype'] : + PathValueType extends Record ? ObtainDocumentType : + unknown; diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index 899660d9fe6..7267939764c 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -422,6 +422,11 @@ declare module 'mongoose' { /** Adds an uppercase [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set). */ uppercase(shouldApply?: boolean): this; } + + class UUID extends SchemaType { + /** This schema type's name, to defend against minifiers that mangle function names. */ + static schemaName: 'UUID'; + } } } } From 33d577dca9fa8565e0db0c8591e6da929eedc56c Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Wed, 2 Nov 2022 12:39:00 -0400 Subject: [PATCH 038/112] fix test --- test/schema.validation.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/schema.validation.test.js b/test/schema.validation.test.js index 22cec7e708c..7c90b7ef97b 100644 --- a/test/schema.validation.test.js +++ b/test/schema.validation.test.js @@ -1341,7 +1341,7 @@ describe('schema', function() { }, field: String }); - const M = mongoose.model('gh6523-2', s); + const M = mongoose.model('gh-12564', s); const m = new M({ field: 'Yo' }); m.validate(function(error) { From 1f6864f04f362ea4692ab2685f6014e067bcb2df Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 2 Nov 2022 12:40:50 -0400 Subject: [PATCH 039/112] test: address some code review comments to streamline tests --- test/types/schema.test.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 7ca2dfa90f1..2ab4698e4bc 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -412,6 +412,7 @@ export function autoTypedSchema() { array5: any[]; array6: string[]; array7?: string[]; + array8?: string[]; decimal1?: Types.Decimal128; decimal2?: Types.Decimal128; decimal3?: Types.Decimal128; @@ -458,6 +459,7 @@ export function autoTypedSchema() { array5: [], array6: { type: [String] }, array7: { type: [String], default: undefined }, + array8: { type: [String], default: () => undefined }, decimal1: Schema.Types.Decimal128, decimal2: 'Decimal128', decimal3: 'decimal128' @@ -870,15 +872,3 @@ function gh12431() { type Example = InferSchemaType; expectType<{ testDate?: Date, testDecimal?: Types.Decimal128 }>({} as Example); } - -function gh12420() { - const TestSchema = new Schema( - { - comments: { type: [String], default: () => undefined } - } - ); - - expectType<{ - comments?: string[] - }>({} as InferSchemaType); -} From f90e73d89344257c365134d58ace0a5f81eb89d4 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 2 Nov 2022 12:47:54 -0400 Subject: [PATCH 040/112] chore: release 6.7.1 --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0852af0eacf..b625c0cba1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +6.7.1 / 2022-11-02 +================== + * fix(query): select Map field with select: false when explicitly requested #12616 #12603 [lpizzinidev](https://github.com/lpizzinidev) + * fix: correctly find paths underneath single nested document with an array of mixed #12605 #12530 + * fix(populate): better support for populating maps of arrays of refs #12601 #12494 + * fix(types): add missing create constructor signature override type #12585 [naorpeled](https://github.com/naorpeled) + * fix(types): make array paths optional in inferred type of array default returns undefined #12649 #12420 + * fix(types): improve ValidateOpts type #12606 [Freezystem](https://github.com/Freezystem) + * docs: add Lodash guide highlighting issues with cloneDeep() #12609 + * docs: removed v5 link from v6 docs #12641 #12624 [lpizzinidev](https://github.com/lpizzinidev) + * docs: removed outdated connection example #12618 [lpizzinidev](https://github.com/lpizzinidev) + 6.7.0 / 2022-10-24 ================== * feat: upgrade to mongodb driver 4.11.0 #12446 diff --git a/package.json b/package.json index 3cf33237eb8..e1dd615e0a8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mongoose", "description": "Mongoose MongoDB ODM", - "version": "6.7.0", + "version": "6.7.1", "author": "Guillermo Rauch ", "keywords": [ "mongodb", From fb1e09a8de92656a2bc65504c57d0ec9a2538c57 Mon Sep 17 00:00:00 2001 From: Kevin Date: Wed, 2 Nov 2022 11:02:21 -0700 Subject: [PATCH 041/112] fix links in nested docs/typescript/*.md --- docs/typescript/schemas.md | 6 +++--- docs/typescript/statics-and-methods.md | 4 ++-- docs/typescript/statics.md | 2 +- docs/typescript/virtuals.md | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/typescript/schemas.md b/docs/typescript/schemas.md index 2a0db24770b..0a1ef78abf2 100644 --- a/docs/typescript/schemas.md +++ b/docs/typescript/schemas.md @@ -1,6 +1,6 @@ # Schemas in TypeScript -Mongoose [schemas](../docs/guide.html) are how you tell Mongoose what your documents look like. +Mongoose [schemas](../../docs/guide.html) are how you tell Mongoose what your documents look like. Mongoose schemas are separate from TypeScript interfaces, so you need to define both a _document interface_ and a _schema_ until V6.3.1. Mongoose supports auto typed schemas so you don't need to define additional typescript interface anymore but you are still able to do so. Mongoose provides a `InferSchemaType`, which infers the type of the auto typed schema document when needed. @@ -95,7 +95,7 @@ The second generic param, `M`, is the model used with the schema. Mongoose uses The third generic param, `TInstanceMethods` is used to add types for instance methods defined in the schema. -The 4th param, `TQueryHelpers`, is used to add types for [chainable query helpers](../docs/typescript/query-helpers.html). +The 4th param, `TQueryHelpers`, is used to add types for [chainable query helpers](../../docs/typescript/query-helpers.html). ## Schema vs Interface fields @@ -141,7 +141,7 @@ const schema = new Schema>({ }); ``` -This is because Mongoose has numerous features that add paths to your schema that should be included in the `DocType` interface without you explicitly putting these paths in the `Schema()` constructor. For example, [timestamps](https://masteringjs.io/tutorials/mongoose/timestamps) and [plugins](../docs/plugins.html). +This is because Mongoose has numerous features that add paths to your schema that should be included in the `DocType` interface without you explicitly putting these paths in the `Schema()` constructor. For example, [timestamps](https://masteringjs.io/tutorials/mongoose/timestamps) and [plugins](../../docs/plugins.html). ## Arrays diff --git a/docs/typescript/statics-and-methods.md b/docs/typescript/statics-and-methods.md index 17d7b0f3bac..946ad8d8dfd 100644 --- a/docs/typescript/statics-and-methods.md +++ b/docs/typescript/statics-and-methods.md @@ -5,7 +5,7 @@ With a little extra configuration, you can also register methods and statics in ## Methods -To define an [instance method](../docs/guide.html#methods) in TypeScript, create a new interface representing your instance methods. +To define an [instance method](../../docs/guide.html#methods) in TypeScript, create a new interface representing your instance methods. You need to pass that interface as the 3rd generic parameter to the `Schema` constructor **and** as the 3rd generic parameter to `Model` as shown below. ```typescript @@ -41,7 +41,7 @@ const fullName: string = user.fullName(); // 'Jean-Luc Picard' ## Statics -Mongoose [models](../docs/models.html) do **not** have an explicit generic parameter for [statics](../docs/guide.html#statics). +Mongoose [models](../../docs/models.html) do **not** have an explicit generic parameter for [statics](../../docs/guide.html#statics). If your model has statics, we recommend creating an interface that [extends](https://www.typescriptlang.org/docs/handbook/interfaces.html) Mongoose's `Model` interface as shown below. ```typescript diff --git a/docs/typescript/statics.md b/docs/typescript/statics.md index 8624a14c192..67192115694 100644 --- a/docs/typescript/statics.md +++ b/docs/typescript/statics.md @@ -1,6 +1,6 @@ # Statics in TypeScript -Mongoose [models](../docs/models.html) do **not** have an explicit generic parameter for [statics](../docs/guide.html#statics). +Mongoose [models](../../docs/models.html) do **not** have an explicit generic parameter for [statics](../../docs/guide.html#statics). If your model has statics, we recommend creating an interface that [extends](https://www.typescriptlang.org/docs/handbook/interfaces.html) Mongoose's `Model` interface as shown below. ```typescript diff --git a/docs/typescript/virtuals.md b/docs/typescript/virtuals.md index e89032b53e7..c36166d91bf 100644 --- a/docs/typescript/virtuals.md +++ b/docs/typescript/virtuals.md @@ -1,6 +1,6 @@ # Virtuals in TypeScript -[Virtuals](../docs/tutorials/virtuals.html) are computed properties: you can access virtuals on hydrated Mongoose documents, but virtuals are **not** stored in MongoDB. +[Virtuals](../../docs/tutorials/virtuals.html) are computed properties: you can access virtuals on hydrated Mongoose documents, but virtuals are **not** stored in MongoDB. Mongoose supports auto typed virtuals so you don't need to define additional typescript interface anymore but you are still able to do so. ### Automatically Inferred Types: @@ -29,7 +29,7 @@ const schema = new Schema( ``` ### Set virtuals type manually: -You shouldn't define virtuals in your TypeScript [document interface](../docs/typescript.html). +You shouldn't define virtuals in your TypeScript [document interface](../../docs/typescript.html). Instead, you should define a separate interface for your virtuals, and pass this interface to `Model` and `Schema`. For example, suppose you have a `UserDoc` interface, and you want to define a `fullName` virtual. From 7f18c8594d0dbbc79d919bfa079c314777911ba3 Mon Sep 17 00:00:00 2001 From: Kevin Date: Wed, 2 Nov 2022 11:05:32 -0700 Subject: [PATCH 042/112] fix links in nested docs/tutorials/*.md --- docs/tutorials/dates.md | 4 ++-- docs/tutorials/findoneandupdate.md | 4 ++-- docs/tutorials/getters-setters.md | 6 +++--- docs/tutorials/lean.md | 20 ++++++++++---------- docs/tutorials/ssl.md | 4 ++-- docs/tutorials/virtuals.md | 24 ++++++++++++------------ 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/tutorials/dates.md b/docs/tutorials/dates.md index 650b26afe76..969ee9b44ee 100644 --- a/docs/tutorials/dates.md +++ b/docs/tutorials/dates.md @@ -13,7 +13,7 @@ const userSchema = new mongoose.Schema({ const User = mongoose.model('User', userSchema); ``` -When you create a user [document](../docs/documents.html), Mongoose will cast +When you create a user [document](../../docs/documents.html), Mongoose will cast the value to a [native JavaScript date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) using the [`Date()` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Syntax). @@ -21,7 +21,7 @@ using the [`Date()` constructor](https://developer.mozilla.org/en-US/docs/Web/Ja [require:Date Tutorial.*Example 1.2] ``` -An invalid date will lead to a `CastError` when you [validate the document](../docs/validation.html). +An invalid date will lead to a `CastError` when you [validate the document](../../docs/validation.html). ```javascript [require:Date Tutorial.*Example 1.3] diff --git a/docs/tutorials/findoneandupdate.md b/docs/tutorials/findoneandupdate.md index ae18024386e..a094a543bcb 100644 --- a/docs/tutorials/findoneandupdate.md +++ b/docs/tutorials/findoneandupdate.md @@ -1,6 +1,6 @@ # How to Use `findOneAndUpdate()` in Mongoose -The [`findOneAndUpdate()` function in Mongoose](../docs/api.html#query_Query-findOneAndUpdate) has a wide variety of use cases. [You should use `save()` to update documents where possible](https://masteringjs.io/tutorials/mongoose/update), but there are some cases where you need to use [`findOneAndUpdate()`](https://masteringjs.io/tutorials/mongoose/findoneandupdate). In this tutorial, you'll see how to use `findOneAndUpdate()`, and learn when you need to use it. +The [`findOneAndUpdate()` function in Mongoose](../../docs/api.html#query_Query-findOneAndUpdate) has a wide variety of use cases. [You should use `save()` to update documents where possible](https://masteringjs.io/tutorials/mongoose/update), but there are some cases where you need to use [`findOneAndUpdate()`](https://masteringjs.io/tutorials/mongoose/findoneandupdate). In this tutorial, you'll see how to use `findOneAndUpdate()`, and learn when you need to use it. * [Getting Started](#getting-started) * [Atomic Updates](#atomic-updates) @@ -36,7 +36,7 @@ which has the same option. With the exception of an [unindexed upsert](https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/#upsert-with-unique-index), [`findOneAndUpdate()` is atomic](https://docs.mongodb.com/manual/core/write-operations-atomicity/#atomicity). That means you can assume the document doesn't change between when MongoDB finds the document and when it updates the document, _unless_ you're doing an [upsert](#upsert). -For example, if you're using `save()` to update a document, the document can change in MongoDB in between when you load the document using `findOne()` and when you save the document using `save()` as show below. For many use cases, the `save()` race condition is a non-issue. But you can work around it with `findOneAndUpdate()` (or [transactions](../docs/transactions.html)) if you need to. +For example, if you're using `save()` to update a document, the document can change in MongoDB in between when you load the document using `findOne()` and when you save the document using `save()` as show below. For many use cases, the `save()` race condition is a non-issue. But you can work around it with `findOneAndUpdate()` (or [transactions](../../docs/transactions.html)) if you need to. ```javascript [require:Tutorial.*findOneAndUpdate.*save race condition] diff --git a/docs/tutorials/getters-setters.md b/docs/tutorials/getters-setters.md index 33d142c38df..1ad4ab44bdf 100644 --- a/docs/tutorials/getters-setters.md +++ b/docs/tutorials/getters-setters.md @@ -1,6 +1,6 @@ # Getters/Setters in Mongoose -Mongoose getters and setters allow you to execute custom logic when getting or setting a property on a [Mongoose document](../docs/documents.html). Getters let you transform data in MongoDB into a more user friendly form, and setters let you transform user data before it gets to MongoDB. +Mongoose getters and setters allow you to execute custom logic when getting or setting a property on a [Mongoose document](../../docs/documents.html). Getters let you transform data in MongoDB into a more user friendly form, and setters let you transform user data before it gets to MongoDB. ## Getters @@ -37,7 +37,7 @@ const userSchema = new Schema({ }, { toJSON: { getters: false } }); ``` -To skip getters on a one-off basis, use [`user.get()` with the `getters` option set to `false`](../docs/api/document.html#document_Document-get) as shown below. +To skip getters on a one-off basis, use [`user.get()` with the `getters` option set to `false`](../../docs/api/document.html#document_Document-get) as shown below. ```javascript [require:getters/setters.*getters.*skip] @@ -53,7 +53,7 @@ make it easy to search without worrying about case. Below is an example [require:getters/setters.*setters.*basic] ``` -Mongoose also runs setters on update operations, like [`updateOne()`](../docs/api/query.html#query_Query-updateOne). Mongoose will +Mongoose also runs setters on update operations, like [`updateOne()`](../../docs/api/query.html#query_Query-updateOne). Mongoose will [upsert a document](https://masteringjs.io/tutorials/mongoose/upsert) with a lowercased `email` in the below example. diff --git a/docs/tutorials/lean.md b/docs/tutorials/lean.md index a9153d16318..8da88558fa9 100644 --- a/docs/tutorials/lean.md +++ b/docs/tutorials/lean.md @@ -1,9 +1,9 @@ # Faster Mongoose Queries With Lean -The [lean option](../docs/api.html#query_Query-lean) tells Mongoose to skip -[hydrating](../docs/api.html#model_Model-hydrate) the result documents. This +The [lean option](../../docs/api.html#query_Query-lean) tells Mongoose to skip +[hydrating](../../docs/api.html#model_Model-hydrate) the result documents. This makes queries faster and less memory intensive, but the result documents are -plain old JavaScript objects (POJOs), **not** [Mongoose documents](../docs/documents.html). +plain old JavaScript objects (POJOs), **not** [Mongoose documents](../../docs/documents.html). In this tutorial, you'll learn more about the tradeoffs of using `lean()`. * [Using Lean](#using-lean) @@ -14,7 +14,7 @@ In this tutorial, you'll learn more about the tradeoffs of using `lean()`.

Using Lean

By default, Mongoose queries return an instance of the -[Mongoose `Document` class](../docs/api.html#Document). Documents are much +[Mongoose `Document` class](../../docs/api.html#Document). Documents are much heavier than vanilla JavaScript objects, because they have a lot of internal state for change tracking. Enabling the `lean` option tells Mongoose to skip instantiating a full Mongoose document and just give you the POJO. @@ -54,7 +54,7 @@ and virtuals don't run if you enable `lean`.

Lean and Populate

-[Populate](../docs/populate.html) works with `lean()`. If you +[Populate](../../docs/populate.html) works with `lean()`. If you use both `populate()` and `lean()`, the `lean` option propagates to the populated documents as well. In the below example, both the top-level 'Group' documents and the populated 'Person' documents will be lean. @@ -63,7 +63,7 @@ populated documents as well. In the below example, both the top-level [require:Lean Tutorial.*conventional populate] ``` -[Virtual populate](../docs/populate.html#populate-virtuals) also works with lean. +[Virtual populate](../../docs/populate.html#populate-virtuals) also works with lean. ```javascript [require:Lean Tutorial.*virtual populate] @@ -74,9 +74,9 @@ populated documents as well. In the below example, both the top-level If you're executing a query and sending the results without modification to, say, an [Express response](http://expressjs.com/en/4x/api.html#res), you should use lean. In general, if you do not modify the query results and do not use -[custom getters](../docs/api.html#schematype_SchemaType-get), you should use +[custom getters](../../docs/api.html#schematype_SchemaType-get), you should use `lean()`. If you modify the query results or rely on features like getters -or [transforms](../docs/api.html#document_Document-toObject), you should not +or [transforms](../../docs/api.html#document_Document-toObject), you should not use `lean()`. Below is an example of an [Express route](http://expressjs.com/en/guide/routing.html) @@ -118,8 +118,8 @@ to add virtuals to your lean query results. ## Plugins -Using `lean()` bypasses all Mongoose features, including [virtuals](../docs/tutorials/virtuals.html), [getters/setters](../docs/tutorials/getters-setters.html), -and [defaults](../docs/api.html#schematype_SchemaType-default). If you want to +Using `lean()` bypasses all Mongoose features, including [virtuals](../../docs/tutorials/virtuals.html), [getters/setters](../../docs/tutorials/getters-setters.html), +and [defaults](../../docs/api.html#schematype_SchemaType-default). If you want to use these features with `lean()`, you need to use the corresponding plugin: - [mongoose-lean-virtuals](https://plugins.mongoosejs.io/plugins/lean-virtuals) diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index 41826fb38e9..017e1c2e19c 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -1,6 +1,6 @@ # SSL Connections -Mongoose supports connecting to [MongoDB clusters that require SSL connections](https://docs.mongodb.com/manual/tutorial/configure-ssl/). Setting the `ssl` option to `true` in [`mongoose.connect()`](../docs/api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using SSL: +Mongoose supports connecting to [MongoDB clusters that require SSL connections](https://docs.mongodb.com/manual/tutorial/configure-ssl/). Setting the `ssl` option to `true` in [`mongoose.connect()`](../../docs/api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using SSL: ```javascript mongoose.connect('mongodb://localhost:27017/test', { ssl: true }); @@ -67,7 +67,7 @@ MongooseServerSelectionError: Hostname/IP does not match certificate's altnames: ``` The SSL certificate's [common name](https://knowledge.digicert.com/solution/SO7239.html) **must** line up with the host name -in your connection string. If the SSL certificate is for `hostname2.mydomain.com`, your connection string must connect to `hostname2.mydomain.com`, not any other hostname or IP address that may be equivalent to `hostname2.mydomain.com`. For replica sets, this also means that the SSL certificate's common name must line up with the [machine's `hostname`](../docs/connections.html#replicaset-hostnames). +in your connection string. If the SSL certificate is for `hostname2.mydomain.com`, your connection string must connect to `hostname2.mydomain.com`, not any other hostname or IP address that may be equivalent to `hostname2.mydomain.com`. For replica sets, this also means that the SSL certificate's common name must line up with the [machine's `hostname`](../../docs/connections.html#replicaset-hostnames). ## X509 Auth diff --git a/docs/tutorials/virtuals.md b/docs/tutorials/virtuals.md index 50e5db25c6e..f7a5cf6bffa 100644 --- a/docs/tutorials/virtuals.md +++ b/docs/tutorials/virtuals.md @@ -18,22 +18,22 @@ want the email's domain. For example, the domain portion of 'test@gmail.com' is 'gmail.com'. Below is one way to implement the `domain` property using a virtual. -You define virtuals on a schema using the [`Schema#virtual()` function](../docs/api/schema.html#schema_Schema-virtual). +You define virtuals on a schema using the [`Schema#virtual()` function](../../docs/api/schema.html#schema_Schema-virtual). ```javascript [require:Virtuals.*basic] ``` -The `Schema#virtual()` function returns a [`VirtualType` object](../docs/api/virtualtype.html). Unlike normal document properties, +The `Schema#virtual()` function returns a [`VirtualType` object](../../docs/api/virtualtype.html). Unlike normal document properties, virtuals do not have any underlying value and Mongoose does not do any type coercion on virtuals. However, virtuals do have -[getters and setters](../docs/tutorials/getters-setters.html), which make +[getters and setters](../../docs/tutorials/getters-setters.html), which make them ideal for computed properties, like the `domain` example above. ## Virtual Setters You can also use virtuals to set multiple properties at once as an -alternative to [custom setters on normal properties](../docs/tutorials/getters-setters.html#setters). For example, suppose +alternative to [custom setters on normal properties](../../docs/tutorials/getters-setters.html#setters). For example, suppose you have two string properties: `firstName` and `lastName`. You can create a virtual property `fullName` that lets you set both of these properties at once. The key detail is that, in virtual getters and @@ -49,7 +49,7 @@ By default, Mongoose does not include virtuals when you convert a document to JS For example, if you pass a document to [Express' `res.json()` function](http://expressjs.com/en/4x/api.html#res.json), virtuals will **not** be included by default. To include virtuals in `res.json()`, you need to set the -[`toJSON` schema option](../docs/guide.html#toJSON) to `{ virtuals: true }`. +[`toJSON` schema option](../../docs/guide.html#toJSON) to `{ virtuals: true }`. ```javascript [require:Virtuals.*toJSON] @@ -58,7 +58,7 @@ To include virtuals in `res.json()`, you need to set the ## Virtuals in `console.log()` By default, Mongoose does **not** include virtuals in `console.log()` output. -To include virtuals in `console.log()`, you need to set the [`toObject` schema option](../docs/guide.html#toObject) to `{ virtuals: true }`, or use `toObject()` before printing the object. +To include virtuals in `console.log()`, you need to set the [`toObject` schema option](../../docs/guide.html#toObject) to `{ virtuals: true }`, or use `toObject()` before printing the object. ```javascript console.log(doc.toObject({ virtuals: true })); @@ -67,9 +67,9 @@ console.log(doc.toObject({ virtuals: true })); ## Virtuals with Lean Virtuals are properties on Mongoose documents. If you use the -[lean option](../docs/tutorials/lean.html), that means your queries return POJOs +[lean option](../../docs/tutorials/lean.html), that means your queries return POJOs rather than full Mongoose documents. That means no virtuals if you use -[`lean()`](../docs/api/query.html#query_Query-lean). +[`lean()`](../../docs/api/query.html#query_Query-lean). ```javascript [require:Virtuals.*lean] @@ -90,11 +90,11 @@ based on Mongoose virtuals. ``` If you want to query by a computed property, you should set the property using -a [custom setter](../docs/tutorials/getters-setters.html) or [pre save middleware](../docs/middleware.html). +a [custom setter](../../docs/tutorials/getters-setters.html) or [pre save middleware](../../docs/middleware.html). ## Populate -Mongoose also supports [populating virtuals](../docs/populate.html). A populated +Mongoose also supports [populating virtuals](../../docs/populate.html). A populated virtual contains documents from another collection. To define a populated virtual, you need to specify: @@ -107,8 +107,8 @@ virtual, you need to specify: ## Further Reading -* [Virtuals in Mongoose Schemas](../docs/guide.html#virtuals) -* [Populate Virtuals](../docs/populate.html#populate-virtuals) +* [Virtuals in Mongoose Schemas](../../docs/guide.html#virtuals) +* [Populate Virtuals](../../docs/populate.html#populate-virtuals) * [Mongoose Lean Virtuals plugin](https://plugins.mongoosejs.io/plugins/lean-virtuals) * [Getting Started With Mongoose Virtuals](https://masteringjs.io/tutorials/mongoose/virtuals) * [Understanding Virtuals in Mongoose](https://futurestud.io/tutorials/understanding-virtuals-in-mongoose) \ No newline at end of file From 554a2714bf86f73ae99b2a45362fb17b079d30f7 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Wed, 2 Nov 2022 16:03:40 -0400 Subject: [PATCH 043/112] made requested changes --- lib/error/validator.js | 2 +- test/schema.validation.test.js | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/error/validator.js b/lib/error/validator.js index ba4195264a1..4ca7316d7bf 100644 --- a/lib/error/validator.js +++ b/lib/error/validator.js @@ -12,7 +12,7 @@ class ValidatorError extends MongooseError { * Schema validator error * * @param {Object} properties - * @param {Object} doc + * @param {Document} doc * @api private */ constructor(properties, doc) { diff --git a/test/schema.validation.test.js b/test/schema.validation.test.js index 7c90b7ef97b..8fc34312119 100644 --- a/test/schema.validation.test.js +++ b/test/schema.validation.test.js @@ -1331,21 +1331,28 @@ describe('schema', function() { }); it('Allows for doc to be passed as another parameter gh-12564', function(done) { + let document = ''; const s = mongoose.Schema({ n: { type: String, - // required: true, - required: [true, function(properties, doc) { - return 'fail ' + properties.path + ' on doc ' + doc; - }] + validate: { + validator: function(v) { + return v != null; + }, + message: function(properties, doc) { + document = doc.toString(); + return 'fail ' + properties.path + ' on doc ' + doc; + } + } }, field: String }); const M = mongoose.model('gh-12564', s); - const m = new M({ field: 'Yo' }); + const m = new M({ n: null, field: 'Yo' }); m.validate(function(error) { - assert.notEqual('fail n on doc undefined', error.errors['n'].message); + assert.equal(error.errors['n'].message.includes(document), true); + assert.equal('fail n on doc ' + document, error.errors['n'].message); done(); }); }); From 243e4d4f14685e88c906dd26476c00e885bd278d Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 2 Nov 2022 16:59:17 -0400 Subject: [PATCH 044/112] test: add extra typescript test coverage for UUID schematype --- test/types/schema.test.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index f5a938e2fb8..84e963c96f3 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -871,9 +871,25 @@ function gh12431() { expectType<{ testDate?: Date, testDecimal?: Types.Decimal128 }>({} as Example); } -function gh12593() { +async function gh12593() { const testSchema = new Schema({ x: { type: Schema.Types.UUID } }); type Example = InferSchemaType; expectType<{ x?: Buffer }>({} as Example); + + const Test = model('Test', testSchema); + + const doc = await Test.findOne({ x: '4709e6d9-61fd-435e-b594-d748eb196d8f' }).orFail(); + expectType(doc.x); + + const doc2 = new Test({ x: '4709e6d9-61fd-435e-b594-d748eb196d8f' }); + expectType(doc2.x); + + const doc3 = await Test.findOne({}).orFail().lean(); + expectType(doc3.x); + + const arrSchema = new Schema({ arr: [{ type: Schema.Types.UUID }] }); + + type ExampleArr = InferSchemaType; + expectType<{ arr: Buffer[] }>({} as ExampleArr); } From 4ddeb468d5bfe13269511b57405b15ea820c69e0 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 2 Nov 2022 17:26:38 -0400 Subject: [PATCH 045/112] chore: clean up loadSponsorData --- docs/loadSponsorData.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/loadSponsorData.js b/docs/loadSponsorData.js index 168d0a13b45..84be29dcabd 100644 --- a/docs/loadSponsorData.js +++ b/docs/loadSponsorData.js @@ -5,9 +5,6 @@ const config = require('../.config'); const fs = require('fs'); const mongoose = require('../'); -const poralHost = 'https://staging.poral.io'; -const opencollectiveUrl = `${poralHost}/invoke/${config.poralId}/generateSponsors`; - run().catch(err => { console.error(err); process.exit(-1); @@ -91,6 +88,12 @@ async function run() { sponsor.alt = override.alt; } } + + const additionalSponsors = await OpenCollectiveSponsor.find({}). + then(docs => docs.filter(doc => doc.openCollectiveId == null)); + for (const sponsor of additionalSponsors) { + opencollectiveSponsors.push(sponsor); + } if (opencollectiveSponsors != null) { fs.writeFileSync(`${__dirname}/data/opencollective.json`, JSON.stringify(opencollectiveSponsors, null, ' ')); From ef95f3daae0fa93429c2f471f01c355a875953bf Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Wed, 2 Nov 2022 17:45:25 -0400 Subject: [PATCH 046/112] init --- lib/model.js | 6 ++++++ test/model.populate.test.js | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/lib/model.js b/lib/model.js index 8fd7bdfbdd2..2b7e14ea3df 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4656,6 +4656,12 @@ const excludeIdRegGlobal = /\s?-_id\s?/g; function populate(model, docs, options, callback) { const populateOptions = { ...options }; + if (options.localField || options.foreignField) { + // reassign options._localModel.schema.virtuals[virtual].options.localField on populateOptions + } + if (options.foreignField) { + // reassign options._localModel.schema.virtuals[virtual].options.foreignField on populateOptions + } if (options.strictPopulate == null) { if (options._localModel != null && options._localModel.schema._userProvidedOptions.strictPopulate != null) { populateOptions.strictPopulate = options._localModel.schema._userProvidedOptions.strictPopulate; diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 58c808c2fb1..162831704a1 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10828,5 +10828,28 @@ describe('model: populate:', function() { assert.ok(err); assert.ok(err.message.includes('strictPopulate'), err.message); }); + it('allows overwriting localField and foreignField when populating a virtual gh-6963', async function() { + const testSchema = Schema({ name: String }, { toJSON: { virtuals: true }, toObject: { virtuals: true } }); + const userSchema = Schema({ name: String, field: { type: mongoose.Schema.Types.ObjectId, ref: 'Test' } }); + testSchema.virtual('test', { + ref: 'gh6963-2', + localField: '_id', + foreignField: 'field' + }); + + const Test = db.model('gh6963', testSchema); + const User = db.model('gh6963-2', userSchema); + + const entry = await Test.create({ + name: 'Test' + }); + await User.create({ + name: 'User', + field: entry._id + }); + + const res = await Test.findOne().populate('test'); + assert.equal(res.test.length, 1); + }); }); }); From 4e953ea3bfa6a526f094b82e53b15d7cdf11a3fe Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 29 Oct 2022 11:06:32 +0200 Subject: [PATCH 047/112] feat(model): add mergePlugins option to discriminator --- lib/helpers/model/discriminator.js | 9 +++++--- lib/model.js | 3 ++- test/model.discriminator.test.js | 37 ++++++++++++++++++++++++++++++ test/types/discriminator.test.ts | 2 +- types/models.d.ts | 1 + 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/lib/helpers/model/discriminator.js b/lib/helpers/model/discriminator.js index a178093a6dc..574df112930 100644 --- a/lib/helpers/model/discriminator.js +++ b/lib/helpers/model/discriminator.js @@ -19,12 +19,13 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = { * ignore */ -module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins, mergeHooks) { +module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins, mergeHooks, mergePlugins) { if (!(schema && schema.instanceOfSchema)) { throw new Error('You must pass a valid discriminator Schema'); } mergeHooks = mergeHooks == null ? true : mergeHooks; + mergePlugins = mergePlugins == null ? true : mergePlugins; if (model.schema.discriminatorMapping && !model.schema.discriminatorMapping.isRoot) { @@ -34,7 +35,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu if (applyPlugins) { const applyPluginsToDiscriminators = get(model.base, - 'options.applyPluginsToDiscriminators', false) || !mergeHooks; + 'options.applyPluginsToDiscriminators', false) || !mergeHooks || !mergePlugins; // Even if `applyPluginsToDiscriminators` isn't set, we should still apply // global plugins to schemas embedded in the discriminator schema (gh-7370) model.base._applyPlugins(schema, { @@ -185,7 +186,9 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu schema.s.hooks = model.schema.s.hooks.merge(schema.s.hooks); } - schema.plugins = Array.prototype.slice.call(baseSchema.plugins); + if (mergePlugins) { + schema.plugins = Array.prototype.slice.call(baseSchema.plugins); + } schema.callQueue = baseSchema.callQueue.concat(schema.callQueue); delete schema._requiredpaths; // reset just in case Schema#requiredPaths() was called on either schema } diff --git a/lib/model.js b/lib/model.js index 27dd89ee5a7..4741a49e773 100644 --- a/lib/model.js +++ b/lib/model.js @@ -1215,6 +1215,7 @@ Model.exists = function exists(filter, options, callback) { * @param {Boolean} [options.clone=true] By default, `discriminator()` clones the given `schema`. Set to `false` to skip cloning. * @param {Boolean} [options.overwriteModels=false] by default, Mongoose does not allow you to define a discriminator with the same name as another discriminator. Set this to allow overwriting discriminators with the same name. * @param {Boolean} [options.mergeHooks=true] By default, Mongoose merges the base schema's hooks with the discriminator schema's hooks. Set this option to `false` to make Mongoose use the discriminator schema's hooks instead. + * @param {Boolean} [options.mergePlugins=true] By default, Mongoose merges the base schema's plugins with the discriminator schema's plugins. Set this option to `false` to make Mongoose use the discriminator schema's plugins instead. * @return {Model} The newly created discriminator model * @api public */ @@ -1242,7 +1243,7 @@ Model.discriminator = function(name, schema, options) { schema = schema.clone(); } - schema = discriminator(this, name, schema, value, true, options.mergeHooks); + schema = discriminator(this, name, schema, value, true, options.mergeHooks, options.mergePlugins); if (this.db.models[name] && !schema.options.overwriteModels) { throw new OverwriteModelError(name); } diff --git a/test/model.discriminator.test.js b/test/model.discriminator.test.js index 919101de4bf..874e59b9259 100644 --- a/test/model.discriminator.test.js +++ b/test/model.discriminator.test.js @@ -2039,4 +2039,41 @@ describe('model', function() { schema.pre('save', function testHook12472() {}); } }); + + it('supports `mergePlugins` option to use the discriminator schema\'s plugins over the base schema\'s (gh-12604)', function() { + let pluginTimes = 0; + const shapeDef = { name: String }; + const shapeSchema = Schema(shapeDef, { discriminatorKey: 'kind' }); + shapeSchema.plugin(myPlugin, { opts1: true }); + + const Shape = db.model('Test', shapeSchema); + + const triangleSchema = Schema({ ...shapeDef, sides: { type: Number, enum: [3] } }); + triangleSchema.plugin(myPlugin, { opts2: true }); + const Triangle = Shape.discriminator( + 'Triangle', + triangleSchema + ); + const squareSchema = Schema({ ...shapeDef, sides: { type: Number, enum: [4] } }); + squareSchema.plugin(myPlugin, { opts3: true }); + const Square = Shape.discriminator( + 'Square', + squareSchema, + { mergeHooks: false, mergePlugins: false } + ); + + assert.equal(Triangle.schema.s.hooks._pres.get('save').filter(hook => hook.fn.name === 'testHook12604').length, 2); + assert.equal(Square.schema.s.hooks._pres.get('save').filter(hook => hook.fn.name === 'testHook12604').length, 1); + + const squareFilteredPlugins = Square.schema.plugins.filter((obj) => obj.fn.name === 'myPlugin'); + assert.equal(squareFilteredPlugins.length, 1); + assert.equal(squareFilteredPlugins[0].opts['opts3'], true); + + assert.equal(pluginTimes, 3); + + function myPlugin(schema) { + pluginTimes += 1; + schema.pre('save', function testHook12604() {}); + } + }); }); diff --git a/test/types/discriminator.test.ts b/test/types/discriminator.test.ts index 1f32fd1149b..0519345322c 100644 --- a/test/types/discriminator.test.ts +++ b/test/types/discriminator.test.ts @@ -21,7 +21,7 @@ doc.email = 'hello'; const Disc2 = Base.discriminator( 'Disc2', new Schema({ email: { type: String } }), - { value: 'test', mergeHooks: false } + { value: 'test', mergeHooks: false, mergePlugins: false } ); function test(): void { diff --git a/types/models.d.ts b/types/models.d.ts index 8c479d2a1ca..de5dad33b91 100644 --- a/types/models.d.ts +++ b/types/models.d.ts @@ -6,6 +6,7 @@ declare module 'mongoose' { clone?: boolean; overwriteModels?: boolean; mergeHooks?: boolean; + mergePlugins?: boolean; } export interface AcceptsDiscriminator { From 9789338f9bac321f881b978b885a1eed4bf08edd Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Tue, 1 Nov 2022 10:23:38 +0100 Subject: [PATCH 048/112] applied requested changes used applyPlugins option in discriminator helper instead of creating new option mergePlugins --- lib/helpers/model/discriminator.js | 8 +++----- lib/model.js | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/helpers/model/discriminator.js b/lib/helpers/model/discriminator.js index 574df112930..96443002ab1 100644 --- a/lib/helpers/model/discriminator.js +++ b/lib/helpers/model/discriminator.js @@ -19,13 +19,12 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = { * ignore */ -module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins, mergeHooks, mergePlugins) { +module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins, mergeHooks) { if (!(schema && schema.instanceOfSchema)) { throw new Error('You must pass a valid discriminator Schema'); } mergeHooks = mergeHooks == null ? true : mergeHooks; - mergePlugins = mergePlugins == null ? true : mergePlugins; if (model.schema.discriminatorMapping && !model.schema.discriminatorMapping.isRoot) { @@ -35,7 +34,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu if (applyPlugins) { const applyPluginsToDiscriminators = get(model.base, - 'options.applyPluginsToDiscriminators', false) || !mergeHooks || !mergePlugins; + 'options.applyPluginsToDiscriminators', false) || !mergeHooks; // Even if `applyPluginsToDiscriminators` isn't set, we should still apply // global plugins to schemas embedded in the discriminator schema (gh-7370) model.base._applyPlugins(schema, { @@ -185,8 +184,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu if (mergeHooks) { schema.s.hooks = model.schema.s.hooks.merge(schema.s.hooks); } - - if (mergePlugins) { + if (applyPlugins) { schema.plugins = Array.prototype.slice.call(baseSchema.plugins); } schema.callQueue = baseSchema.callQueue.concat(schema.callQueue); diff --git a/lib/model.js b/lib/model.js index 4741a49e773..8f876bc3321 100644 --- a/lib/model.js +++ b/lib/model.js @@ -1233,6 +1233,7 @@ Model.discriminator = function(name, schema, options) { options = options || {}; const value = utils.isPOJO(options) ? options.value : options; const clone = typeof options.clone === 'boolean' ? options.clone : true; + const mergePlugins = typeof options.mergePlugins === 'boolean' ? options.mergePlugins : true; _checkContext(this, 'discriminator'); @@ -1243,7 +1244,7 @@ Model.discriminator = function(name, schema, options) { schema = schema.clone(); } - schema = discriminator(this, name, schema, value, true, options.mergeHooks, options.mergePlugins); + schema = discriminator(this, name, schema, value, mergePlugins, options.mergeHooks); if (this.db.models[name] && !schema.options.overwriteModels) { throw new OverwriteModelError(name); } From 1ff26548d5af8168988193693157e8867a378716 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Thu, 3 Nov 2022 10:51:45 +0100 Subject: [PATCH 049/112] test trigger --- test/model.discriminator.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/model.discriminator.test.js b/test/model.discriminator.test.js index 874e59b9259..a9b164be1d4 100644 --- a/test/model.discriminator.test.js +++ b/test/model.discriminator.test.js @@ -2054,6 +2054,7 @@ describe('model', function() { 'Triangle', triangleSchema ); + const squareSchema = Schema({ ...shapeDef, sides: { type: Number, enum: [4] } }); squareSchema.plugin(myPlugin, { opts3: true }); const Square = Shape.discriminator( From edca782890e25901155ab628395df4b8bdd7694c Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Thu, 3 Nov 2022 10:57:17 +0100 Subject: [PATCH 050/112] fix lint --- test/model.discriminator.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/model.discriminator.test.js b/test/model.discriminator.test.js index a9b164be1d4..3e34bfa7b62 100644 --- a/test/model.discriminator.test.js +++ b/test/model.discriminator.test.js @@ -2054,7 +2054,7 @@ describe('model', function() { 'Triangle', triangleSchema ); - + const squareSchema = Schema({ ...shapeDef, sides: { type: Number, enum: [4] } }); squareSchema.plugin(myPlugin, { opts3: true }); const Square = Shape.discriminator( From 3cc3d16842b2bff8ad1ba8e27620a6070bee04b2 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 4 Nov 2022 08:14:41 -0700 Subject: [PATCH 051/112] chore: find replace '../../docs/' to '../' to simplify relative links --- docs/tutorials/dates.md | 4 ++-- docs/tutorials/findoneandupdate.md | 4 ++-- docs/tutorials/getters-setters.md | 6 +++--- docs/tutorials/lean.md | 20 ++++++++++---------- docs/tutorials/ssl.md | 4 ++-- docs/tutorials/virtuals.md | 24 ++++++++++++------------ 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/tutorials/dates.md b/docs/tutorials/dates.md index 969ee9b44ee..4d1dffefcb0 100644 --- a/docs/tutorials/dates.md +++ b/docs/tutorials/dates.md @@ -13,7 +13,7 @@ const userSchema = new mongoose.Schema({ const User = mongoose.model('User', userSchema); ``` -When you create a user [document](../../docs/documents.html), Mongoose will cast +When you create a user [document](../documents.html), Mongoose will cast the value to a [native JavaScript date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) using the [`Date()` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Syntax). @@ -21,7 +21,7 @@ using the [`Date()` constructor](https://developer.mozilla.org/en-US/docs/Web/Ja [require:Date Tutorial.*Example 1.2] ``` -An invalid date will lead to a `CastError` when you [validate the document](../../docs/validation.html). +An invalid date will lead to a `CastError` when you [validate the document](../validation.html). ```javascript [require:Date Tutorial.*Example 1.3] diff --git a/docs/tutorials/findoneandupdate.md b/docs/tutorials/findoneandupdate.md index a094a543bcb..ea863dcbe18 100644 --- a/docs/tutorials/findoneandupdate.md +++ b/docs/tutorials/findoneandupdate.md @@ -1,6 +1,6 @@ # How to Use `findOneAndUpdate()` in Mongoose -The [`findOneAndUpdate()` function in Mongoose](../../docs/api.html#query_Query-findOneAndUpdate) has a wide variety of use cases. [You should use `save()` to update documents where possible](https://masteringjs.io/tutorials/mongoose/update), but there are some cases where you need to use [`findOneAndUpdate()`](https://masteringjs.io/tutorials/mongoose/findoneandupdate). In this tutorial, you'll see how to use `findOneAndUpdate()`, and learn when you need to use it. +The [`findOneAndUpdate()` function in Mongoose](../api.html#query_Query-findOneAndUpdate) has a wide variety of use cases. [You should use `save()` to update documents where possible](https://masteringjs.io/tutorials/mongoose/update), but there are some cases where you need to use [`findOneAndUpdate()`](https://masteringjs.io/tutorials/mongoose/findoneandupdate). In this tutorial, you'll see how to use `findOneAndUpdate()`, and learn when you need to use it. * [Getting Started](#getting-started) * [Atomic Updates](#atomic-updates) @@ -36,7 +36,7 @@ which has the same option. With the exception of an [unindexed upsert](https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/#upsert-with-unique-index), [`findOneAndUpdate()` is atomic](https://docs.mongodb.com/manual/core/write-operations-atomicity/#atomicity). That means you can assume the document doesn't change between when MongoDB finds the document and when it updates the document, _unless_ you're doing an [upsert](#upsert). -For example, if you're using `save()` to update a document, the document can change in MongoDB in between when you load the document using `findOne()` and when you save the document using `save()` as show below. For many use cases, the `save()` race condition is a non-issue. But you can work around it with `findOneAndUpdate()` (or [transactions](../../docs/transactions.html)) if you need to. +For example, if you're using `save()` to update a document, the document can change in MongoDB in between when you load the document using `findOne()` and when you save the document using `save()` as show below. For many use cases, the `save()` race condition is a non-issue. But you can work around it with `findOneAndUpdate()` (or [transactions](../transactions.html)) if you need to. ```javascript [require:Tutorial.*findOneAndUpdate.*save race condition] diff --git a/docs/tutorials/getters-setters.md b/docs/tutorials/getters-setters.md index 1ad4ab44bdf..4b237622960 100644 --- a/docs/tutorials/getters-setters.md +++ b/docs/tutorials/getters-setters.md @@ -1,6 +1,6 @@ # Getters/Setters in Mongoose -Mongoose getters and setters allow you to execute custom logic when getting or setting a property on a [Mongoose document](../../docs/documents.html). Getters let you transform data in MongoDB into a more user friendly form, and setters let you transform user data before it gets to MongoDB. +Mongoose getters and setters allow you to execute custom logic when getting or setting a property on a [Mongoose document](../documents.html). Getters let you transform data in MongoDB into a more user friendly form, and setters let you transform user data before it gets to MongoDB. ## Getters @@ -37,7 +37,7 @@ const userSchema = new Schema({ }, { toJSON: { getters: false } }); ``` -To skip getters on a one-off basis, use [`user.get()` with the `getters` option set to `false`](../../docs/api/document.html#document_Document-get) as shown below. +To skip getters on a one-off basis, use [`user.get()` with the `getters` option set to `false`](../api/document.html#document_Document-get) as shown below. ```javascript [require:getters/setters.*getters.*skip] @@ -53,7 +53,7 @@ make it easy to search without worrying about case. Below is an example [require:getters/setters.*setters.*basic] ``` -Mongoose also runs setters on update operations, like [`updateOne()`](../../docs/api/query.html#query_Query-updateOne). Mongoose will +Mongoose also runs setters on update operations, like [`updateOne()`](../api/query.html#query_Query-updateOne). Mongoose will [upsert a document](https://masteringjs.io/tutorials/mongoose/upsert) with a lowercased `email` in the below example. diff --git a/docs/tutorials/lean.md b/docs/tutorials/lean.md index 8da88558fa9..5c053c45c2e 100644 --- a/docs/tutorials/lean.md +++ b/docs/tutorials/lean.md @@ -1,9 +1,9 @@ # Faster Mongoose Queries With Lean -The [lean option](../../docs/api.html#query_Query-lean) tells Mongoose to skip -[hydrating](../../docs/api.html#model_Model-hydrate) the result documents. This +The [lean option](../api.html#query_Query-lean) tells Mongoose to skip +[hydrating](../api.html#model_Model-hydrate) the result documents. This makes queries faster and less memory intensive, but the result documents are -plain old JavaScript objects (POJOs), **not** [Mongoose documents](../../docs/documents.html). +plain old JavaScript objects (POJOs), **not** [Mongoose documents](../documents.html). In this tutorial, you'll learn more about the tradeoffs of using `lean()`. * [Using Lean](#using-lean) @@ -14,7 +14,7 @@ In this tutorial, you'll learn more about the tradeoffs of using `lean()`.

Using Lean

By default, Mongoose queries return an instance of the -[Mongoose `Document` class](../../docs/api.html#Document). Documents are much +[Mongoose `Document` class](../api.html#Document). Documents are much heavier than vanilla JavaScript objects, because they have a lot of internal state for change tracking. Enabling the `lean` option tells Mongoose to skip instantiating a full Mongoose document and just give you the POJO. @@ -54,7 +54,7 @@ and virtuals don't run if you enable `lean`.

Lean and Populate

-[Populate](../../docs/populate.html) works with `lean()`. If you +[Populate](../populate.html) works with `lean()`. If you use both `populate()` and `lean()`, the `lean` option propagates to the populated documents as well. In the below example, both the top-level 'Group' documents and the populated 'Person' documents will be lean. @@ -63,7 +63,7 @@ populated documents as well. In the below example, both the top-level [require:Lean Tutorial.*conventional populate] ``` -[Virtual populate](../../docs/populate.html#populate-virtuals) also works with lean. +[Virtual populate](../populate.html#populate-virtuals) also works with lean. ```javascript [require:Lean Tutorial.*virtual populate] @@ -74,9 +74,9 @@ populated documents as well. In the below example, both the top-level If you're executing a query and sending the results without modification to, say, an [Express response](http://expressjs.com/en/4x/api.html#res), you should use lean. In general, if you do not modify the query results and do not use -[custom getters](../../docs/api.html#schematype_SchemaType-get), you should use +[custom getters](../api.html#schematype_SchemaType-get), you should use `lean()`. If you modify the query results or rely on features like getters -or [transforms](../../docs/api.html#document_Document-toObject), you should not +or [transforms](../api.html#document_Document-toObject), you should not use `lean()`. Below is an example of an [Express route](http://expressjs.com/en/guide/routing.html) @@ -118,8 +118,8 @@ to add virtuals to your lean query results. ## Plugins -Using `lean()` bypasses all Mongoose features, including [virtuals](../../docs/tutorials/virtuals.html), [getters/setters](../../docs/tutorials/getters-setters.html), -and [defaults](../../docs/api.html#schematype_SchemaType-default). If you want to +Using `lean()` bypasses all Mongoose features, including [virtuals](../tutorials/virtuals.html), [getters/setters](../tutorials/getters-setters.html), +and [defaults](../api.html#schematype_SchemaType-default). If you want to use these features with `lean()`, you need to use the corresponding plugin: - [mongoose-lean-virtuals](https://plugins.mongoosejs.io/plugins/lean-virtuals) diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index 017e1c2e19c..e6863640d9d 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -1,6 +1,6 @@ # SSL Connections -Mongoose supports connecting to [MongoDB clusters that require SSL connections](https://docs.mongodb.com/manual/tutorial/configure-ssl/). Setting the `ssl` option to `true` in [`mongoose.connect()`](../../docs/api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using SSL: +Mongoose supports connecting to [MongoDB clusters that require SSL connections](https://docs.mongodb.com/manual/tutorial/configure-ssl/). Setting the `ssl` option to `true` in [`mongoose.connect()`](../api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using SSL: ```javascript mongoose.connect('mongodb://localhost:27017/test', { ssl: true }); @@ -67,7 +67,7 @@ MongooseServerSelectionError: Hostname/IP does not match certificate's altnames: ``` The SSL certificate's [common name](https://knowledge.digicert.com/solution/SO7239.html) **must** line up with the host name -in your connection string. If the SSL certificate is for `hostname2.mydomain.com`, your connection string must connect to `hostname2.mydomain.com`, not any other hostname or IP address that may be equivalent to `hostname2.mydomain.com`. For replica sets, this also means that the SSL certificate's common name must line up with the [machine's `hostname`](../../docs/connections.html#replicaset-hostnames). +in your connection string. If the SSL certificate is for `hostname2.mydomain.com`, your connection string must connect to `hostname2.mydomain.com`, not any other hostname or IP address that may be equivalent to `hostname2.mydomain.com`. For replica sets, this also means that the SSL certificate's common name must line up with the [machine's `hostname`](../connections.html#replicaset-hostnames). ## X509 Auth diff --git a/docs/tutorials/virtuals.md b/docs/tutorials/virtuals.md index f7a5cf6bffa..e7c07ba70e8 100644 --- a/docs/tutorials/virtuals.md +++ b/docs/tutorials/virtuals.md @@ -18,22 +18,22 @@ want the email's domain. For example, the domain portion of 'test@gmail.com' is 'gmail.com'. Below is one way to implement the `domain` property using a virtual. -You define virtuals on a schema using the [`Schema#virtual()` function](../../docs/api/schema.html#schema_Schema-virtual). +You define virtuals on a schema using the [`Schema#virtual()` function](../api/schema.html#schema_Schema-virtual). ```javascript [require:Virtuals.*basic] ``` -The `Schema#virtual()` function returns a [`VirtualType` object](../../docs/api/virtualtype.html). Unlike normal document properties, +The `Schema#virtual()` function returns a [`VirtualType` object](../api/virtualtype.html). Unlike normal document properties, virtuals do not have any underlying value and Mongoose does not do any type coercion on virtuals. However, virtuals do have -[getters and setters](../../docs/tutorials/getters-setters.html), which make +[getters and setters](../tutorials/getters-setters.html), which make them ideal for computed properties, like the `domain` example above. ## Virtual Setters You can also use virtuals to set multiple properties at once as an -alternative to [custom setters on normal properties](../../docs/tutorials/getters-setters.html#setters). For example, suppose +alternative to [custom setters on normal properties](../tutorials/getters-setters.html#setters). For example, suppose you have two string properties: `firstName` and `lastName`. You can create a virtual property `fullName` that lets you set both of these properties at once. The key detail is that, in virtual getters and @@ -49,7 +49,7 @@ By default, Mongoose does not include virtuals when you convert a document to JS For example, if you pass a document to [Express' `res.json()` function](http://expressjs.com/en/4x/api.html#res.json), virtuals will **not** be included by default. To include virtuals in `res.json()`, you need to set the -[`toJSON` schema option](../../docs/guide.html#toJSON) to `{ virtuals: true }`. +[`toJSON` schema option](../guide.html#toJSON) to `{ virtuals: true }`. ```javascript [require:Virtuals.*toJSON] @@ -58,7 +58,7 @@ To include virtuals in `res.json()`, you need to set the ## Virtuals in `console.log()` By default, Mongoose does **not** include virtuals in `console.log()` output. -To include virtuals in `console.log()`, you need to set the [`toObject` schema option](../../docs/guide.html#toObject) to `{ virtuals: true }`, or use `toObject()` before printing the object. +To include virtuals in `console.log()`, you need to set the [`toObject` schema option](../guide.html#toObject) to `{ virtuals: true }`, or use `toObject()` before printing the object. ```javascript console.log(doc.toObject({ virtuals: true })); @@ -67,9 +67,9 @@ console.log(doc.toObject({ virtuals: true })); ## Virtuals with Lean Virtuals are properties on Mongoose documents. If you use the -[lean option](../../docs/tutorials/lean.html), that means your queries return POJOs +[lean option](../tutorials/lean.html), that means your queries return POJOs rather than full Mongoose documents. That means no virtuals if you use -[`lean()`](../../docs/api/query.html#query_Query-lean). +[`lean()`](../api/query.html#query_Query-lean). ```javascript [require:Virtuals.*lean] @@ -90,11 +90,11 @@ based on Mongoose virtuals. ``` If you want to query by a computed property, you should set the property using -a [custom setter](../../docs/tutorials/getters-setters.html) or [pre save middleware](../../docs/middleware.html). +a [custom setter](../tutorials/getters-setters.html) or [pre save middleware](../middleware.html). ## Populate -Mongoose also supports [populating virtuals](../../docs/populate.html). A populated +Mongoose also supports [populating virtuals](../populate.html). A populated virtual contains documents from another collection. To define a populated virtual, you need to specify: @@ -107,8 +107,8 @@ virtual, you need to specify: ## Further Reading -* [Virtuals in Mongoose Schemas](../../docs/guide.html#virtuals) -* [Populate Virtuals](../../docs/populate.html#populate-virtuals) +* [Virtuals in Mongoose Schemas](../guide.html#virtuals) +* [Populate Virtuals](../populate.html#populate-virtuals) * [Mongoose Lean Virtuals plugin](https://plugins.mongoosejs.io/plugins/lean-virtuals) * [Getting Started With Mongoose Virtuals](https://masteringjs.io/tutorials/mongoose/virtuals) * [Understanding Virtuals in Mongoose](https://futurestud.io/tutorials/understanding-virtuals-in-mongoose) \ No newline at end of file From 0a57f216a1041c620b37cc0e912085c63ca676cb Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 4 Nov 2022 09:02:42 -0700 Subject: [PATCH 052/112] chore: replace '../docs/' with '' and '../../docs/' with '../' to simplify all relative links --- docs/change-streams.md | 4 +- docs/connections.md | 12 ++--- docs/deprecations.md | 8 ++-- docs/documents.md | 6 +-- docs/faq.md | 2 +- docs/geojson.md | 6 +-- docs/guide.md | 40 ++++++++-------- docs/guides.md | 66 +++++++++++++------------- docs/index.md | 10 ++-- docs/middleware.md | 34 ++++++------- docs/migrating_to_5.md | 2 +- docs/migrating_to_6.md | 2 +- docs/models.md | 2 +- docs/plugins.md | 8 ++-- docs/populate.md | 6 +-- docs/queries.md | 42 ++++++++-------- docs/schematypes.md | 18 +++---- docs/transactions.md | 16 +++---- docs/typescript.md | 12 ++--- docs/typescript/schemas.md | 6 +-- docs/typescript/statics-and-methods.md | 4 +- docs/typescript/statics.md | 2 +- docs/typescript/virtuals.md | 4 +- docs/validation.md | 12 ++--- simplify-relative-links.sh | 20 ++++++++ 25 files changed, 182 insertions(+), 162 deletions(-) create mode 100755 simplify-relative-links.sh diff --git a/docs/change-streams.md b/docs/change-streams.md index 122ac267e68..0f82af7e1d6 100644 --- a/docs/change-streams.md +++ b/docs/change-streams.md @@ -1,7 +1,7 @@ ## Change Streams [Change streams](https://www.mongodb.com/developer/quickstart/nodejs-change-streams-triggers/) let you listen for updates to documents in a given model's collection, or even documents in an entire database. -Unlike [middleware](../docs/middleware.html), change streams are a MongoDB server construct, which means they pick up changes from anywhere. +Unlike [middleware](middleware.html), change streams are a MongoDB server construct, which means they pick up changes from anywhere. Even if you update a document from a MongoDB GUI, your Mongoose change stream will be notified. The `watch()` function creates a change stream. @@ -50,7 +50,7 @@ For local development, we recommend [mongodb-memory-server](https://www.npmjs.co ### Iterating using `next()` -If you want to iterate through a change stream in a [AWS Lambda function](../docs/lambda.html), do **not** use event emitters to listen to the change stream. +If you want to iterate through a change stream in a [AWS Lambda function](lambda.html), do **not** use event emitters to listen to the change stream. You need to make sure you close your change stream when your Lambda function is done executing, because your change stream may end up in an inconsistent state if Lambda stops your container while the change stream is pulling data from MongoDB. Change streams also have a `next()` function that lets you explicitly wait for the next change to come in. diff --git a/docs/connections.md b/docs/connections.md index 154393c84c7..ae6e5cd8c32 100644 --- a/docs/connections.md +++ b/docs/connections.md @@ -71,11 +71,11 @@ mongoose.set('bufferCommands', false); ``` Note that buffering is also responsible for waiting until Mongoose -creates collections if you use the [`autoCreate` option](../docs/guide.html#autoCreate). +creates collections if you use the [`autoCreate` option](guide.html#autoCreate). If you disable buffering, you should also disable the `autoCreate` -option and use [`createCollection()`](../docs/api/model.html#model_Model-createCollection) -to create [capped collections](../docs/guide.html#capped) or -[collections with collations](../docs/guide.html#collation). +option and use [`createCollection()`](api/model.html#model_Model-createCollection) +to create [capped collections](guide.html#capped) or +[collections with collations](guide.html#collation). ```javascript const schema = new Schema({ @@ -139,7 +139,7 @@ A full list of options can be found on the [MongoDB Node.js driver docs for `Mon 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](../docs/faq.html#callback_never_executes) +* `bufferCommands` - This is a mongoose-specific option (not passed to the MongoDB driver) that disables [Mongoose's buffering mechanism](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.username` 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). @@ -460,4 +460,4 @@ mongoose.createConnection(uri);

Next Up

-Now that we've covered connections, let's take a look at [models](../docs/models.html). +Now that we've covered connections, let's take a look at [models](models.html). diff --git a/docs/deprecations.md b/docs/deprecations.md index 4407167f423..3224dbaa2bf 100644 --- a/docs/deprecations.md +++ b/docs/deprecations.md @@ -28,7 +28,7 @@ deleteMany, or bulkWrite instead. ``` To remove this deprecation warning, replace any usage of `remove()` with -`deleteMany()`, _unless_ you specify the [`single` option to `remove()`](../docs/api.html#model_Model-remove). The `single` +`deleteMany()`, _unless_ you specify the [`single` option to `remove()`](api.html#model_Model-remove). The `single` option limited `remove()` to deleting at most one document, so you should replace `remove(filter, { single: true })` with `deleteOne(filter)`. @@ -46,9 +46,9 @@ MyModel.deleteOne({ answer: 42 });

update()

-Like `remove()`, the [`update()` function](../docs/api.html#model_Model-update) is deprecated in favor -of the more explicit [`updateOne()`](../docs/api.html#model_Model-updateOne), [`updateMany()`](../docs/api.html#model_Model-updateMany), and [`replaceOne()`](../docs/api.html#model_Model-replaceOne) functions. You should replace -`update()` with `updateOne()`, unless you use the [`multi` or `overwrite` options](../docs/api.html#model_Model-update). +Like `remove()`, the [`update()` function](api.html#model_Model-update) is deprecated in favor +of the more explicit [`updateOne()`](api.html#model_Model-updateOne), [`updateMany()`](api.html#model_Model-updateMany), and [`replaceOne()`](api.html#model_Model-replaceOne) functions. You should replace +`update()` with `updateOne()`, unless you use the [`multi` or `overwrite` options](api.html#model_Model-update). ``` collection.update is deprecated. Use updateOne, updateMany, or bulkWrite diff --git a/docs/documents.md b/docs/documents.md index 837c19e40b0..8459d7a1bfc 100644 --- a/docs/documents.md +++ b/docs/documents.md @@ -140,7 +140,7 @@ Read the [validation](./validation.html) guide for more details. There are 2 different ways to overwrite a document (replacing all keys in the document). One way is to use the -[`Document#overwrite()` function](../docs/api/document.html#document_Document-overwrite) +[`Document#overwrite()` function](api/document.html#document_Document-overwrite) followed by `save()`. ```javascript @@ -151,7 +151,7 @@ doc.overwrite({ name: 'Jean-Luc Picard' }); await doc.save(); ``` -The other way is to use [`Model.replaceOne()`](../docs/api/model.html#model_Model-replaceOne). +The other way is to use [`Model.replaceOne()`](api/model.html#model_Model-replaceOne). ```javascript // Sets `name` and unsets all other properties @@ -161,4 +161,4 @@ await Person.replaceOne({ _id }, { name: 'Jean-Luc Picard' }); ### Next Up Now that we've covered Documents, let's take a look at -[Subdocuments](../docs/subdocs.html). +[Subdocuments](subdocs.html). diff --git a/docs/faq.md b/docs/faq.md index 70a12cf7488..e0cd2a00a29 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -396,7 +396,7 @@ Consider using a regex like `/^[a-f0-9]{24}$/` to test whether a string is exact **A**. In order to avoid executing a separate query for each document returned from the `find` query, Mongoose instead queries using (numDocuments * limit) as the limit. If you need the correct limit, you should use the -[perDocumentLimit](../docs/populate.html#limit-vs-perDocumentLimit) option (new in Mongoose 5.9.0). Just keep in +[perDocumentLimit](populate.html#limit-vs-perDocumentLimit) option (new in Mongoose 5.9.0). Just keep in mind that populate() will execute a separate query for each document.
diff --git a/docs/geojson.md b/docs/geojson.md index 0ab628f553e..4167c548ad3 100644 --- a/docs/geojson.md +++ b/docs/geojson.md @@ -46,7 +46,7 @@ const citySchema = new mongoose.Schema({ }); ``` -Using [subdocuments](../docs/subdocs.html), you can define a common `pointSchema` and reuse it everywhere you want to store a GeoJSON point. +Using [subdocuments](subdocs.html), you can define a common `pointSchema` and reuse it everywhere you want to store a GeoJSON point. ```javascript const pointSchema = new mongoose.Schema({ @@ -127,7 +127,7 @@ a polygon representing the state of Colorado using [require:geojson.*driver query] ``` -Mongoose also has a [`within()` helper](../docs/api.html#query_Query-within) +Mongoose also has a [`within()` helper](api.html#query_Query-within) that's a shorthand for `$geoWithin`. ```javascript @@ -144,7 +144,7 @@ a 2dsphere index on a GeoJSON point: [require:geojson.*index$] ``` -You can also define a geospatial index using the [`Schema#index()` function](../docs/api/schema.html#schema_Schema-index) +You can also define a geospatial index using the [`Schema#index()` function](api/schema.html#schema_Schema-index) as shown below. ```javascript diff --git a/docs/guide.md b/docs/guide.md index 08a8f72e032..fad5017a897 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -1,7 +1,7 @@ ## Schemas If you haven't yet done so, please take a minute to read the [quickstart](./index.html) to get an idea of how Mongoose works. -If you are migrating from 5.x to 6.x please take a moment to read the [migration guide](../docs/migrating_to_6.html). +If you are migrating from 5.x to 6.x please take a moment to read the [migration guide](migrating_to_6.html).
  • Defining your schema
  • @@ -183,7 +183,7 @@ ways to add a static: - Add a function property to the second argument of the schema-constructor (`statics`) - Add a function property to `schema.statics` -- Call the [`Schema#static()` function](../docs/api.html#schema_Schema-static) +- Call the [`Schema#static()` function](api.html#schema_Schema-static) ```javascript @@ -449,7 +449,7 @@ console.log(person); // { n: 'Not Val' } ``` You can also declare aliases on nested paths. It is easier to use nested -schemas and [subdocuments](../docs/subdocs.html), but you can also declare +schemas and [subdocuments](subdocs.html), but you can also declare nested path aliases inline as long as you use the full nested path `nested.myProp` as the alias. @@ -506,9 +506,9 @@ Valid options:

    option: autoIndex

    -By default, Mongoose's [`init()` function](../docs/api.html#model_Model-init) +By default, Mongoose's [`init()` function](api.html#model_Model-init) creates all the indexes defined in your model's schema by calling -[`Model.createIndexes()`](../docs/api.html#model_Model-createIndexes) +[`Model.createIndexes()`](api.html#model_Model-createIndexes) after you successfully connect to MongoDB. Creating indexes automatically is great for development and test environments. But index builds can also create significant load on your production database. If you want to manage indexes @@ -521,7 +521,7 @@ Clock.ensureIndexes(callback); ``` The `autoIndex` option is set to `true` by default. You can change this -default by setting [`mongoose.set('autoIndex', false);`](../docs/api/mongoose.html#mongoose_Mongoose-set) +default by setting [`mongoose.set('autoIndex', false);`](api/mongoose.html#mongoose_Mongoose-set)

    option: autoCreate

    @@ -529,7 +529,7 @@ Before Mongoose builds indexes, it calls `Model.createCollection()` to create th Calling `createCollection()` sets the [collection's default collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) based on the [collation option](#collation) and establishes the collection as a capped collection if you set the [`capped` schema option](#capped). -You can disable this behavior by setting `autoCreate` to `false` using [`mongoose.set('autoCreate', false)`](../docs/api/mongoose.html#mongoose_Mongoose-set). +You can disable this behavior by setting `autoCreate` to `false` using [`mongoose.set('autoCreate', false)`](api/mongoose.html#mongoose_Mongoose-set). Like `autoIndex`, `autoCreate` is helpful for development and test environments, but you may want to disable it for production to avoid unnecessary database calls. Unfortunately, `createCollection()` cannot change an existing collection. @@ -609,7 +609,7 @@ const dataSchema = new Schema({..}, { collection: 'data' });

    option: discriminatorKey

    -When you define a [discriminator](../docs/discriminators.html), Mongoose adds a path to your +When you define a [discriminator](discriminators.html), Mongoose adds a path to your schema that stores which discriminator a document is an instance of. By default, Mongoose adds an `__t` path, but you can set `discriminatorKey` to overwrite this default. @@ -650,8 +650,8 @@ console.log(p.id); // undefined

    option: _id

    Mongoose assigns each of your schemas an `_id` field by default if one -is not passed into the [Schema](../docs/api.html#schema-js) constructor. -The type assigned is an [ObjectId](../docs/api.html#schema_Schema-Types) +is not passed into the [Schema](api.html#schema-js) constructor. +The type assigned is an [ObjectId](api.html#schema_Schema-Types) to coincide with MongoDB's default behavior. If you don't want an `_id` added to your schema at all, you may disable it using this option. @@ -724,7 +724,7 @@ sam.$isEmpty('inventory'); // false

    option: read

    -Allows setting [query#read](../docs/api.html#query_Query-read) options at the +Allows setting [query#read](api.html#query_Query-read) options at the schema level, providing us a way to apply default [ReadPreferences](http://docs.mongodb.org/manual/applications/replication/#replica-set-read-preference) to all queries derived from a model. @@ -911,11 +911,11 @@ console.log(m.toJSON()); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom console.log(JSON.stringify(m)); // { "_id": "504e0cd7dd992d9be2f20b6f", "name": "Max Headroom is my name" } ``` -To see all available `toJSON/toObject` options, read [this](../docs/api.html#document_Document-toObject). +To see all available `toJSON/toObject` options, read [this](api.html#document_Document-toObject).

    option: toObject

    -Documents have a [toObject](../docs/api.html#document_Document-toObject) method +Documents have a [toObject](api.html#document_Document-toObject) method which converts the mongoose document into a plain JavaScript object. This method accepts a few options. Instead of applying these options on a per-document basis, we may declare the options at the schema level and have @@ -935,7 +935,7 @@ const m = new M({ name: 'Max Headroom' }); console.log(m); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' } ``` -To see all available `toObject` options, read [this](../docs/api.html#document_Document-toObject). +To see all available `toObject` options, read [this](api.html#document_Document-toObject).

    option: typeKey

    @@ -1035,7 +1035,7 @@ const thing = new Thing({ name: 'no versioning please' }); thing.save(); // { name: 'no versioning please' } ``` -Mongoose _only_ updates the version key when you use [`save()`](../docs/api.html#document_Document-save). +Mongoose _only_ updates the version key when you use [`save()`](api.html#document_Document-save). If you use `update()`, `findOneAndUpdate()`, etc. Mongoose will **not** update the version key. As a workaround, you can use the below middleware. @@ -1350,12 +1350,12 @@ new Parent({ child: {} }).validateSync().errors;

    With ES6 Classes

    -Schemas have a [`loadClass()` method](../docs/api/schema.html#schema_Schema-loadClass) +Schemas have a [`loadClass()` method](api/schema.html#schema_Schema-loadClass) that you can use to create a Mongoose schema from an [ES6 class](https://thecodebarbarian.com/an-overview-of-es6-classes): -* [ES6 class methods](https://masteringjs.io/tutorials/fundamentals/class#methods) become [Mongoose methods](../docs/guide.html#methods) -* [ES6 class statics](https://masteringjs.io/tutorials/fundamentals/class#statics) become [Mongoose statics](../docs/guide.html#statics) -* [ES6 getters and setters](https://masteringjs.io/tutorials/fundamentals/class#getterssetters) become [Mongoose virtuals](../docs/tutorials/virtuals.html) +* [ES6 class methods](https://masteringjs.io/tutorials/fundamentals/class#methods) become [Mongoose methods](guide.html#methods) +* [ES6 class statics](https://masteringjs.io/tutorials/fundamentals/class#statics) become [Mongoose statics](guide.html#statics) +* [ES6 getters and setters](https://masteringjs.io/tutorials/fundamentals/class#getterssetters) become [Mongoose virtuals](tutorials/virtuals.html) Here's an example of using `loadClass()` to create a schema from an ES6 class: @@ -1398,4 +1398,4 @@ of use cases, including e-commerce, wikis, and appointment bookings.

    Next Up

    -Now that we've covered `Schemas`, let's take a look at [SchemaTypes](../docs/schematypes.html). +Now that we've covered `Schemas`, let's take a look at [SchemaTypes](schematypes.html). diff --git a/docs/guides.md b/docs/guides.md index b3577132006..defcc5e56a3 100644 --- a/docs/guides.md +++ b/docs/guides.md @@ -5,46 +5,46 @@ integrating Mongoose with external tools and frameworks. ### Mongoose Core Concepts -* [Schemas](../docs/guide.html) -* [SchemaTypes](../docs/schematypes.html) -* [Connections](../docs/connections.html) -* [Models](../docs/models.html) -* [Documents](../docs/documents.html) -* [Subdocuments](../docs/subdocs.html) -* [Queries](../docs/queries.html) -* [Validation](../docs/validation.html) -* [Middleware](../docs/middleware.html) -* [Populate](../docs/populate.html) -* [Discriminators](../docs/discriminators.html) -* [Plugins](../docs/plugins.html) -* [Faster Mongoose Queries With Lean](../docs/tutorials/lean.html) -* [Query Casting](../docs/tutorials/query_casting.html) -* [findOneAndUpdate](../docs/tutorials/findoneandupdate.html) -* [Getters and Setters](../docs/tutorials/getters-setters.html) -* [Virtuals](../docs/tutorials/virtuals.html) +* [Schemas](guide.html) +* [SchemaTypes](schematypes.html) +* [Connections](connections.html) +* [Models](models.html) +* [Documents](documents.html) +* [Subdocuments](subdocs.html) +* [Queries](queries.html) +* [Validation](validation.html) +* [Middleware](middleware.html) +* [Populate](populate.html) +* [Discriminators](discriminators.html) +* [Plugins](plugins.html) +* [Faster Mongoose Queries With Lean](tutorials/lean.html) +* [Query Casting](tutorials/query_casting.html) +* [findOneAndUpdate](tutorials/findoneandupdate.html) +* [Getters and Setters](tutorials/getters-setters.html) +* [Virtuals](tutorials/virtuals.html) ### Advanced Topics -* [Working with Dates](../docs/tutorials/dates.html) -* [Custom Casting For Built-in Types](../docs/tutorials/custom-casting.html) -* [Custom SchemaTypes](../docs/customschematypes.html) -* [Advanced Schemas](../docs/advanced_schemas.html) +* [Working with Dates](tutorials/dates.html) +* [Custom Casting For Built-in Types](tutorials/custom-casting.html) +* [Custom SchemaTypes](customschematypes.html) +* [Advanced Schemas](advanced_schemas.html) ### Integrations -* [Promises](../docs/promises.html) -* [Lodash](../docs/lodash.html) -* [AWS Lambda](../docs/lambda.html) -* [Browser Library](../docs/browser.html) -* [GeoJSON](../docs/geojson.html) -* [Transactions](../docs/transactions.html) -* [MongoDB Driver Deprecation Warnings](../docs/deprecations.html) -* [Testing with Jest](../docs/jest.html) -* [SSL Connections](../docs/tutorials/ssl.html) +* [Promises](promises.html) +* [Lodash](lodash.html) +* [AWS Lambda](lambda.html) +* [Browser Library](browser.html) +* [GeoJSON](geojson.html) +* [Transactions](transactions.html) +* [MongoDB Driver Deprecation Warnings](deprecations.html) +* [Testing with Jest](jest.html) +* [SSL Connections](tutorials/ssl.html) ### Migration Guides -* [Mongoose 5.x to 6.x](../docs/migrating_to_6.html) -* [Mongoose 4.x to 5.x](../docs/migrating_to_5.html) -* [Mongoose 3.x to 4.x](../docs/migration.html) +* [Mongoose 5.x to 6.x](migrating_to_6.html) +* [Mongoose 4.x to 5.x](migrating_to_5.html) +* [Mongoose 3.x to 4.x](migration.html) diff --git a/docs/index.md b/docs/index.md index 2f274878862..6d3a4da0b0e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -40,7 +40,7 @@ async function main() { For brevity, let's assume that all following code is within the `main()` function. -With Mongoose, everything is derived from a [Schema](../docs/guide.html). +With Mongoose, everything is derived from a [Schema](guide.html). Let's get a reference to it and define our kittens. ```javascript @@ -49,7 +49,7 @@ const kittySchema = new mongoose.Schema({ }); ``` -So far so good. We've got a schema with one property, `name`, which will be a `String`. The next step is compiling our schema into a [Model](../docs/models.html). +So far so good. We've got a schema with one property, `name`, which will be a `String`. The next step is compiling our schema into a [Model](models.html). ```javascript const Kitten = mongoose.model('Kitten', kittySchema); @@ -88,7 +88,7 @@ fluffy.speak(); // "Meow name is fluffy" ``` We have talking kittens! But we still haven't saved anything to MongoDB. -Each document can be saved to the database by calling its [save](../docs/api.html#model_Model-save) method. The first argument to the callback will be an error if any occurred. +Each document can be saved to the database by calling its [save](api.html#model_Model-save) method. The first argument to the callback will be an error if any occurred. ```javascript await fluffy.save(); @@ -96,7 +96,7 @@ fluffy.speak(); ``` Say time goes by and we want to display all the kittens we've seen. -We can access all of the kitten documents through our Kitten [model](../docs/models.html). +We can access all of the kitten documents through our Kitten [model](models.html). ```javascript const kittens = await Kitten.find(); @@ -104,7 +104,7 @@ console.log(kittens); ``` We just logged all of the kittens in our db to the console. -If we want to filter our kittens by name, Mongoose supports MongoDBs rich [querying](../docs/queries.html) syntax. +If we want to filter our kittens by name, Mongoose supports MongoDBs rich [querying](queries.html) syntax. ```javascript await Kitten.find({ name: /^fluff/ }); diff --git a/docs/middleware.md b/docs/middleware.md index 3a03fda8f7e..f8e713a5384 100644 --- a/docs/middleware.md +++ b/docs/middleware.md @@ -28,12 +28,12 @@ Document middleware is supported for the following document functions. In Mongoose, a document is an instance of a `Model` class. In document middleware functions, `this` refers to the document. -* [validate](../docs/api/document.html#document_Document-validate) -* [save](../docs/api/model.html#model_Model-save) -* [remove](../docs/api/model.html#model_Model-remove) -* [updateOne](../docs/api/document.html#document_Document-updateOne) -* [deleteOne](../docs/api/model.html#model_Model-deleteOne) -* [init](../docs/api/document.html#document_Document-init) (note: init hooks are [synchronous](#synchronous)) +* [validate](api/document.html#document_Document-validate) +* [save](api/model.html#model_Model-save) +* [remove](api/model.html#model_Model-remove) +* [updateOne](api/document.html#document_Document-updateOne) +* [deleteOne](api/model.html#model_Model-deleteOne) +* [init](api/document.html#document_Document-init) (note: init hooks are [synchronous](#synchronous)) Query middleware is supported for the following Query functions. Query middleware executes when you call `exec()` or `then()` on a Query object, or `await` on a Query object. @@ -186,7 +186,7 @@ error `err1` and then throw an error `err2`, mongoose will report `err1`.

    Post middleware

    -[post](../docs/api.html#schema_Schema-post) middleware are executed _after_ +[post](api.html#schema_Schema-post) middleware are executed _after_ the hooked method and all of its `pre` middleware have completed. ```javascript @@ -229,7 +229,7 @@ schema.post('save', function(doc, next) {

    Define Middleware Before Compiling Models

    -Calling `pre()` or `post()` after [compiling a model](../docs/models.html#compiling) +Calling `pre()` or `post()` after [compiling a model](models.html#compiling) does **not** work in Mongoose in general. For example, the below `pre('save')` middleware will not fire. @@ -247,8 +247,8 @@ const user = new User({ name: 'test' }); user.save(); ``` -This means that you must add all middleware and [plugins](../docs/plugins.html) -**before** calling [`mongoose.model()`](../docs/api/mongoose.html#mongoose_Mongoose-model). +This means that you must add all middleware and [plugins](plugins.html) +**before** calling [`mongoose.model()`](api/mongoose.html#mongoose_Mongoose-model). The below script will print out "Hello from pre save": ```javascript @@ -266,7 +266,7 @@ user.save(); As a consequence, be careful about exporting Mongoose models from the same file that you define your schema. If you choose to use this pattern, you -must define [global plugins](../docs/api/mongoose.html#mongoose_Mongoose-plugin) +must define [global plugins](api/mongoose.html#mongoose_Mongoose-plugin) **before** calling `require()` on your model file. ```javascript @@ -314,10 +314,10 @@ doc.remove(); Model.remove(); ``` -You can pass options to [`Schema.pre()`](../docs/api.html#schema_Schema-pre) -and [`Schema.post()`](../docs/api.html#schema_Schema-post) to switch whether -Mongoose calls your `remove()` hook for [`Document.remove()`](../docs/api.html#model_Model-remove) -or [`Model.remove()`](../docs/api.html#model_Model-remove). Note here that you need to set both `document` and `query` properties in the passed object: +You can pass options to [`Schema.pre()`](api.html#schema_Schema-pre) +and [`Schema.post()`](api.html#schema_Schema-post) to switch whether +Mongoose calls your `remove()` hook for [`Document.remove()`](api.html#model_Model-remove) +or [`Model.remove()`](api.html#model_Model-remove). Note here that you need to set both `document` and `query` properties in the passed object: ```javascript // Only document middleware @@ -382,7 +382,7 @@ schema.pre('findOneAndUpdate', async function() { However, if you define `pre('updateOne')` document middleware, `this` will be the document being updated. That's because `pre('updateOne')` -document middleware hooks into [`Document#updateOne()`](../docs/api/document.html#document_Document-updateOne) +document middleware hooks into [`Document#updateOne()`](api/document.html#document_Document-updateOne) rather than `Query#updateOne()`. ```javascript @@ -510,4 +510,4 @@ rejections.

    Next Up

    Now that we've covered middleware, let's take a look at Mongoose's approach -to faking JOINs with its query [population](../docs/populate.html) helper. +to faking JOINs with its query [population](populate.html) helper. diff --git a/docs/migrating_to_5.md b/docs/migrating_to_5.md index 17f50029bbd..8797b859d91 100644 --- a/docs/migrating_to_5.md +++ b/docs/migrating_to_5.md @@ -465,7 +465,7 @@ In Mongoose 5.x, the above code will correctly overwrite `'baseball'` with `{ $n Mongoose 5.x uses version 3.x of the [MongoDB Node.js driver](http://npmjs.com/package/mongodb). MongoDB driver 3.x changed the format of -the result of [`bulkWrite()` calls](../docs/api.html#model_Model-bulkWrite) so there is no longer a top-level `nInserted`, `nModified`, etc. property. The new result object structure is [described here](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~BulkWriteOpResult). +the result of [`bulkWrite()` calls](api.html#model_Model-bulkWrite) so there is no longer a top-level `nInserted`, `nModified`, etc. property. The new result object structure is [described here](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~BulkWriteOpResult). ```javascript const Model = mongoose.model('Test', new Schema({ name: String })); diff --git a/docs/migrating_to_6.md b/docs/migrating_to_6.md index b46780b49ea..c964705dd86 100644 --- a/docs/migrating_to_6.md +++ b/docs/migrating_to_6.md @@ -9,7 +9,7 @@ There are several [backwards-breaking changes](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) you should be aware of when migrating from Mongoose 5.x to Mongoose 6.x. -If you're still on Mongoose 4.x, please read the [Mongoose 4.x to 5.x migration guide](../docs/migrating_to_5.html) and upgrade to Mongoose 5.x first. +If you're still on Mongoose 4.x, please read the [Mongoose 4.x to 5.x migration guide](migrating_to_5.html) and upgrade to Mongoose 5.x first. * [Version Requirements](#version-requirements) * [MongoDB Driver 4.0](#mongodb-driver-40) diff --git a/docs/models.md b/docs/models.md index be9c2a8e6bc..5d405ee6089 100644 --- a/docs/models.md +++ b/docs/models.md @@ -207,4 +207,4 @@ The [API docs](./api.html#model_Model) cover many additional methods available l ## Next Up -Now that we've covered `Models`, let's take a look at [Documents](../docs/documents.html). +Now that we've covered `Models`, let's take a look at [Documents](documents.html). diff --git a/docs/plugins.md b/docs/plugins.md index febbb7af79b..e68f88270db 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -65,8 +65,8 @@ const Player = mongoose.model('Player', playerSchema);

    Apply Plugins Before Compiling Models

    -Because many plugins rely on [middleware](../docs/middleware.html), you should make sure to apply plugins **before** -you call `mongoose.model()` or `conn.model()`. Otherwise, [any middleware the plugin registers won't get applied](../docs/middleware.html#defining). +Because many plugins rely on [middleware](middleware.html), you should make sure to apply plugins **before** +you call `mongoose.model()` or `conn.model()`. Otherwise, [any middleware the plugin registers won't get applied](middleware.html#defining). ```javascript // loadedAt.js @@ -101,8 +101,8 @@ gameSchema.plugin(loadedAtPlugin); The Mongoose team maintains several plugins that add cool new features to Mongoose. Here's a couple: -* [mongoose-autopopulate](http://plugins.mongoosejs.io/plugins/autopopulate): Always [`populate()`](../docs/populate.html) certain fields in your Mongoose schemas. -* [mongoose-lean-virtuals](http://plugins.mongoosejs.io/plugins/lean-virtuals): Attach virtuals to the results of Mongoose queries when using [`.lean()`](../docs/api.html#query_Query-lean). +* [mongoose-autopopulate](http://plugins.mongoosejs.io/plugins/autopopulate): Always [`populate()`](populate.html) certain fields in your Mongoose schemas. +* [mongoose-lean-virtuals](http://plugins.mongoosejs.io/plugins/lean-virtuals): Attach virtuals to the results of Mongoose queries when using [`.lean()`](api.html#query_Query-lean). * [mongoose-cast-aggregation](https://www.npmjs.com/package/mongoose-cast-aggregation) You can find a full list of officially supported plugins on [Mongoose's plugins search site](https://plugins.mongoosejs.io/). diff --git a/docs/populate.md b/docs/populate.md index 178a9958c38..0ed241f4492 100644 --- a/docs/populate.md +++ b/docs/populate.md @@ -140,7 +140,7 @@ story.populated('author'); // undefined ``` A common reason for checking whether a path is populated is getting the `author` -id. However, for your convenience, Mongoose adds a [`_id` getter to ObjectId instances](../docs/api/mongoose.html#mongoose_Mongoose-set) +id. However, for your convenience, Mongoose adds a [`_id` getter to ObjectId instances](api/mongoose.html#mongoose_Mongoose-set) so you can use `story.author._id` regardless of whether `author` is populated. ```javascript @@ -476,7 +476,7 @@ This is known as a "cross-database populate," because it enables you to populate across MongoDB databases and even across MongoDB instances. If you don't have access to the model instance when defining your `eventSchema`, -you can also pass [the model instance as an option to `populate()`](../docs/api/model.html#model_Model-populate). +you can also pass [the model instance as an option to `populate()`](api/model.html#model_Model-populate). ```javascript const events = await Event. @@ -743,7 +743,7 @@ AuthorSchema.virtual('posts', {

    Populating Maps

    -[Maps](../docs/schematypes.html#maps) are a type that represents an object with arbitrary +[Maps](schematypes.html#maps) are a type that represents an object with arbitrary string keys. For example, in the below schema, `members` is a map from strings to ObjectIds. ```javascript diff --git a/docs/queries.md b/docs/queries.md index 797e1830342..6e6643766f9 100644 --- a/docs/queries.md +++ b/docs/queries.md @@ -3,23 +3,23 @@ Mongoose [models](./models.html) provide several static helper functions for [CRUD operations](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete). Each of these functions returns a -[mongoose `Query` object](../docs/api.html#Query). - -- [`Model.deleteMany()`](../docs/api.html#model_Model-deleteMany) -- [`Model.deleteOne()`](../docs/api.html#model_Model-deleteOne) -- [`Model.find()`](../docs/api.html#model_Model-find) -- [`Model.findById()`](../docs/api.html#model_Model-findById) -- [`Model.findByIdAndDelete()`](../docs/api.html#model_Model-findByIdAndDelete) -- [`Model.findByIdAndRemove()`](../docs/api.html#model_Model-findByIdAndRemove) -- [`Model.findByIdAndUpdate()`](../docs/api.html#model_Model-findByIdAndUpdate) -- [`Model.findOne()`](../docs/api.html#model_Model-findOne) -- [`Model.findOneAndDelete()`](../docs/api.html#model_Model-findOneAndDelete) -- [`Model.findOneAndRemove()`](../docs/api.html#model_Model-findOneAndRemove) -- [`Model.findOneAndReplace()`](../docs/api.html#model_Model-findOneAndReplace) -- [`Model.findOneAndUpdate()`](../docs/api.html#model_Model-findOneAndUpdate) -- [`Model.replaceOne()`](../docs/api.html#model_Model-replaceOne) -- [`Model.updateMany()`](../docs/api.html#model_Model-updateMany) -- [`Model.updateOne()`](../docs/api.html#model_Model-updateOne) +[mongoose `Query` object](api.html#Query). + +- [`Model.deleteMany()`](api.html#model_Model-deleteMany) +- [`Model.deleteOne()`](api.html#model_Model-deleteOne) +- [`Model.find()`](api.html#model_Model-find) +- [`Model.findById()`](api.html#model_Model-findById) +- [`Model.findByIdAndDelete()`](api.html#model_Model-findByIdAndDelete) +- [`Model.findByIdAndRemove()`](api.html#model_Model-findByIdAndRemove) +- [`Model.findByIdAndUpdate()`](api.html#model_Model-findByIdAndUpdate) +- [`Model.findOne()`](api.html#model_Model-findOne) +- [`Model.findOneAndDelete()`](api.html#model_Model-findOneAndDelete) +- [`Model.findOneAndRemove()`](api.html#model_Model-findOneAndRemove) +- [`Model.findOneAndReplace()`](api.html#model_Model-findOneAndReplace) +- [`Model.findOneAndUpdate()`](api.html#model_Model-findOneAndUpdate) +- [`Model.replaceOne()`](api.html#model_Model-replaceOne) +- [`Model.updateMany()`](api.html#model_Model-updateMany) +- [`Model.updateOne()`](api.html#model_Model-updateOne) A mongoose query can be executed in one of two ways. First, if you pass in a `callback` function, Mongoose will execute the query asynchronously @@ -200,7 +200,7 @@ of inactivity. You can read more about working around session idle timeouts in t

    Versus Aggregation

    -[Aggregation](../docs/api.html#aggregate_Aggregate) can +[Aggregation](api.html#aggregate_Aggregate) can do many of the same things that queries can. For example, below is how you can use `aggregate()` to find docs where `name.last = 'Ghost'`: @@ -212,7 +212,7 @@ However, just because you can use `aggregate()` doesn't mean you should. In general, you should use queries where possible, and only use `aggregate()` when you absolutely need to. -Unlike query results, Mongoose does **not** [`hydrate()`](../docs/api/model.html#model_Model-hydrate) +Unlike query results, Mongoose does **not** [`hydrate()`](api/model.html#model_Model-hydrate) aggregation results. Aggregation results are always POJOs, not Mongoose documents. @@ -223,7 +223,7 @@ docs[0] instanceof mongoose.Document; // false ``` Also, unlike query filters, Mongoose also doesn't -[cast](../docs/tutorials/query_casting.html) aggregation pipelines. That means +[cast](tutorials/query_casting.html) aggregation pipelines. That means you're responsible for ensuring the values you pass in to an aggregation pipeline have the correct type. @@ -242,4 +242,4 @@ const aggRes = await Person.aggregate([{ $match: { _id: idString } }])

    Next Up

    -Now that we've covered `Queries`, let's take a look at [Validation](../docs/validation.html). +Now that we've covered `Queries`, let's take a look at [Validation](validation.html). diff --git a/docs/schematypes.md b/docs/schematypes.md index d4bb251dd74..3448e32d9f2 100644 --- a/docs/schematypes.md +++ b/docs/schematypes.md @@ -127,7 +127,7 @@ const schema = new Schema({ }); ``` -As a consequence, [you need a little extra work to define a property named `type` in your schema](../docs/faq.html#type-key). +As a consequence, [you need a little extra work to define a property named `type` in your schema](faq.html#type-key). For example, suppose you're building a stock portfolio app, and you want to store the asset's `type` (stock, bond, ETF, etc.). Naively, you might define your schema as shown below: @@ -209,7 +209,7 @@ types. * `set`: function, defines a custom setter for this property using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). * `alias`: string, mongoose >= 4.10.0 only. Defines a [virtual](./guide.html#virtuals) with the given name that gets/sets this path. * `immutable`: boolean, defines path as immutable. Mongoose prevents you from changing immutable paths unless the parent document has `isNew: true`. -* `transform`: function, Mongoose calls this function when you call [`Document#toJSON()`](../docs/api/document.html#document_Document-toJSON) function, including when you [`JSON.stringify()`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript) a document. +* `transform`: function, Mongoose calls this function when you call [`Document#toJSON()`](api/document.html#document_Document-toJSON) function, including when you [`JSON.stringify()`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript) a document. ```javascript const numberSchema = new Schema({ @@ -261,14 +261,14 @@ const schema2 = new Schema({ * `enum`: Array, creates a [validator](./validation.html) that checks if the value is in the given array. * `minLength`: Number, creates a [validator](./validation.html) that checks if the value length is not less than the given number * `maxLength`: Number, creates a [validator](./validation.html) that checks if the value length is not greater than the given number -* `populate`: Object, sets default [populate options](../docs/populate.html#query-conditions) +* `populate`: Object, sets default [populate options](populate.html#query-conditions)
    Number
    * `min`: Number, creates a [validator](./validation.html) that checks if the value is greater than or equal to the given minimum. * `max`: Number, creates a [validator](./validation.html) that checks if the value is less than or equal to the given maximum. * `enum`: Array, creates a [validator](./validation.html) that checks if the value is strictly equal to one of the values in the given array. -* `populate`: Object, sets default [populate options](../docs/populate.html#query-conditions) +* `populate`: Object, sets default [populate options](populate.html#query-conditions)
    Date
    @@ -278,7 +278,7 @@ const schema2 = new Schema({
    ObjectId
    -* `populate`: Object, sets default [populate options](../docs/populate.html#query-conditions) +* `populate`: Object, sets default [populate options](populate.html#query-conditions)

    Usage Notes

    @@ -333,7 +333,7 @@ call it and assign the returned value to the path. The values `null` and `undefined` are not cast. NaN, strings that cast to NaN, arrays, and objects that don't have a `valueOf()` function -will all result in a [CastError](../docs/validation.html#cast-errors) once validated, meaning that it will not throw on initialization, only when validated. +will all result in a [CastError](validation.html#cast-errors) once validated, meaning that it will not throw on initialization, only when validated.

    Dates

    @@ -443,7 +443,7 @@ Mongoose casts the below values to `false`: * `'0'` * `'no'` -Any other value causes a [CastError](../docs/validation.html#cast-errors). +Any other value causes a [CastError](validation.html#cast-errors). You can modify what values Mongoose converts to true or false using the `convertToTrue` and `convertToFalse` properties, which are [JavaScript sets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). @@ -566,7 +566,7 @@ Map types are stored as [BSON objects in MongoDB](https://en.wikipedia.org/wiki/ Keys in a BSON object are ordered, so this means the [insertion order](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Description) property of maps is maintained. -Mongoose supports a special `$*` syntax to [populate](../docs/populate.html) all elements in a map. +Mongoose supports a special `$*` syntax to [populate](populate.html) all elements in a map. For example, suppose your `socialMediaHandles` map contains a `ref`: ```javascript @@ -720,4 +720,4 @@ including what validators it has and what the type is. ### Next Up -Now that we've covered `SchemaTypes`, let's take a look at [Connections](../docs/connections.html). +Now that we've covered `SchemaTypes`, let's take a look at [Connections](connections.html). diff --git a/docs/transactions.md b/docs/transactions.md index 825b9d3b12f..3eee83ba1a9 100644 --- a/docs/transactions.md +++ b/docs/transactions.md @@ -12,8 +12,8 @@ If you haven't already, import mongoose: import mongoose from 'mongoose'; ``` -To create a transaction, you first need to create a session using or [`Mongoose#startSession`](../docs/api/mongoose.html#mongoose_Mongoose-startSession) -or [`Connection#startSession()`](../docs/api/connection.html#connection_Connection-startSession). +To create a transaction, you first need to create a session using or [`Mongoose#startSession`](api/mongoose.html#mongoose_Mongoose-startSession) +or [`Connection#startSession()`](api/connection.html#connection_Connection-startSession). ```javascript // Using Mongoose's default connection @@ -51,11 +51,11 @@ The `Connection#transaction()` function informs Mongoose change tracking that th

    With Mongoose Documents and save()

    -If you get a [Mongoose document](../docs/documents.html) from [`findOne()`](../docs/api.html#findone_findOne) -or [`find()`](../docs/api.html#find_find) using a session, the document will -keep a reference to the session and use that session for [`save()`](../docs/api.html#document_Document-save). +If you get a [Mongoose document](documents.html) from [`findOne()`](api.html#findone_findOne) +or [`find()`](api.html#find_find) using a session, the document will +keep a reference to the session and use that session for [`save()`](api.html#document_Document-save). -To get/set the session associated with a given document, use [`doc.$session()`](../docs/api.html#document_Document-$session). +To get/set the session associated with a given document, use [`doc.$session()`](api.html#document_Document-$session). ```javascript [require:transactions.*save] @@ -64,8 +64,8 @@ To get/set the session associated with a given document, use [`doc.$session()`](

    With the Aggregation Framework

    The `Model.aggregate()` function also supports transactions. Mongoose -aggregations have a [`session()` helper](../docs/api.html#aggregate_Aggregate-session) -that sets the [`session` option](../docs/api.html#aggregate_Aggregate-option). +aggregations have a [`session()` helper](api.html#aggregate_Aggregate-session) +that sets the [`session` option](api.html#aggregate_Aggregate-option). Below is an example of executing an aggregation within a transaction. ```javascript diff --git a/docs/typescript.md b/docs/typescript.md index c7728629d96..1f96873c7af 100644 --- a/docs/typescript.md +++ b/docs/typescript.md @@ -9,9 +9,9 @@ This guide describes Mongoose's recommended approach to working with Mongoose in To get started with Mongoose in TypeScript, you need to: 1. Create an interface representing a document in MongoDB. -2. Create a [Schema](../docs/guide.html) corresponding to the document interface. +2. Create a [Schema](guide.html) corresponding to the document interface. 3. Create a Model. -4. [Connect to MongoDB](../docs/connections.html). +4. [Connect to MongoDB](connections.html). ```typescript import { Schema, model, connect } from 'mongoose'; @@ -91,7 +91,7 @@ const userSchema = new Schema({ }); ``` -That's because `Schema.Types.ObjectId` is a [class that inherits from SchemaType](../docs/schematypes.html), **not** the class you use to create a new MongoDB ObjectId. +That's because `Schema.Types.ObjectId` is a [class that inherits from SchemaType](schematypes.html), **not** the class you use to create a new MongoDB ObjectId. ### Using `extends Document` @@ -111,10 +111,10 @@ interface IUser extends Document { ``` This approach works, but we recommend your document interface _not_ extend `Document`. -Using `extends Document` makes it difficult for Mongoose to infer which properties are present on [query filters](../docs/queries.html), [lean documents](../docs/tutorials/lean.html), and other cases. +Using `extends Document` makes it difficult for Mongoose to infer which properties are present on [query filters](queries.html), [lean documents](tutorials/lean.html), and other cases. We recommend your document interface contain the properties defined in your schema and line up with what your documents look like in MongoDB. -Although you can add [instance methods](../docs/guide.html#methods) to your document interface, we do not recommend doing so. +Although you can add [instance methods](guide.html#methods) to your document interface, we do not recommend doing so. ### Using Custom Bindings @@ -129,4 +129,4 @@ However, before you do, please [open an issue on Mongoose's GitHub page](https:/ ### Next Up -Now that you've seen the basics of how to use Mongoose in TypeScript, let's take a look at [statics in TypeScript](../docs/typescript/statics-and-methods.html). +Now that you've seen the basics of how to use Mongoose in TypeScript, let's take a look at [statics in TypeScript](typescript/statics-and-methods.html). diff --git a/docs/typescript/schemas.md b/docs/typescript/schemas.md index 0a1ef78abf2..00f72fb7d2a 100644 --- a/docs/typescript/schemas.md +++ b/docs/typescript/schemas.md @@ -1,6 +1,6 @@ # Schemas in TypeScript -Mongoose [schemas](../../docs/guide.html) are how you tell Mongoose what your documents look like. +Mongoose [schemas](../guide.html) are how you tell Mongoose what your documents look like. Mongoose schemas are separate from TypeScript interfaces, so you need to define both a _document interface_ and a _schema_ until V6.3.1. Mongoose supports auto typed schemas so you don't need to define additional typescript interface anymore but you are still able to do so. Mongoose provides a `InferSchemaType`, which infers the type of the auto typed schema document when needed. @@ -95,7 +95,7 @@ The second generic param, `M`, is the model used with the schema. Mongoose uses The third generic param, `TInstanceMethods` is used to add types for instance methods defined in the schema. -The 4th param, `TQueryHelpers`, is used to add types for [chainable query helpers](../../docs/typescript/query-helpers.html). +The 4th param, `TQueryHelpers`, is used to add types for [chainable query helpers](typescript/query-helpers.html). ## Schema vs Interface fields @@ -141,7 +141,7 @@ const schema = new Schema>({ }); ``` -This is because Mongoose has numerous features that add paths to your schema that should be included in the `DocType` interface without you explicitly putting these paths in the `Schema()` constructor. For example, [timestamps](https://masteringjs.io/tutorials/mongoose/timestamps) and [plugins](../../docs/plugins.html). +This is because Mongoose has numerous features that add paths to your schema that should be included in the `DocType` interface without you explicitly putting these paths in the `Schema()` constructor. For example, [timestamps](https://masteringjs.io/tutorials/mongoose/timestamps) and [plugins](../plugins.html). ## Arrays diff --git a/docs/typescript/statics-and-methods.md b/docs/typescript/statics-and-methods.md index 946ad8d8dfd..5b83a7ab1ac 100644 --- a/docs/typescript/statics-and-methods.md +++ b/docs/typescript/statics-and-methods.md @@ -5,7 +5,7 @@ With a little extra configuration, you can also register methods and statics in ## Methods -To define an [instance method](../../docs/guide.html#methods) in TypeScript, create a new interface representing your instance methods. +To define an [instance method](guide.html#methods) in TypeScript, create a new interface representing your instance methods. You need to pass that interface as the 3rd generic parameter to the `Schema` constructor **and** as the 3rd generic parameter to `Model` as shown below. ```typescript @@ -41,7 +41,7 @@ const fullName: string = user.fullName(); // 'Jean-Luc Picard' ## Statics -Mongoose [models](../../docs/models.html) do **not** have an explicit generic parameter for [statics](../../docs/guide.html#statics). +Mongoose [models](../models.html) do **not** have an explicit generic parameter for [statics](guide.html#statics). If your model has statics, we recommend creating an interface that [extends](https://www.typescriptlang.org/docs/handbook/interfaces.html) Mongoose's `Model` interface as shown below. ```typescript diff --git a/docs/typescript/statics.md b/docs/typescript/statics.md index 67192115694..e7a10c6845b 100644 --- a/docs/typescript/statics.md +++ b/docs/typescript/statics.md @@ -1,6 +1,6 @@ # Statics in TypeScript -Mongoose [models](../../docs/models.html) do **not** have an explicit generic parameter for [statics](../../docs/guide.html#statics). +Mongoose [models](../models.html) do **not** have an explicit generic parameter for [statics](guide.html#statics). If your model has statics, we recommend creating an interface that [extends](https://www.typescriptlang.org/docs/handbook/interfaces.html) Mongoose's `Model` interface as shown below. ```typescript diff --git a/docs/typescript/virtuals.md b/docs/typescript/virtuals.md index c36166d91bf..95b6ca1886b 100644 --- a/docs/typescript/virtuals.md +++ b/docs/typescript/virtuals.md @@ -1,6 +1,6 @@ # Virtuals in TypeScript -[Virtuals](../../docs/tutorials/virtuals.html) are computed properties: you can access virtuals on hydrated Mongoose documents, but virtuals are **not** stored in MongoDB. +[Virtuals](tutorials/virtuals.html) are computed properties: you can access virtuals on hydrated Mongoose documents, but virtuals are **not** stored in MongoDB. Mongoose supports auto typed virtuals so you don't need to define additional typescript interface anymore but you are still able to do so. ### Automatically Inferred Types: @@ -29,7 +29,7 @@ const schema = new Schema( ``` ### Set virtuals type manually: -You shouldn't define virtuals in your TypeScript [document interface](../../docs/typescript.html). +You shouldn't define virtuals in your TypeScript [document interface](../typescript.html). Instead, you should define a separate interface for your virtuals, and pass this interface to `Model` and `Schema`. For example, suppose you have a `UserDoc` interface, and you want to define a `fullName` virtual. diff --git a/docs/validation.md b/docs/validation.md index 95ca8b7f41c..baa1c3b3724 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -62,7 +62,7 @@ Mongoose replaces `{VALUE}` with the value being validated. A common gotcha for beginners is that the `unique` option for schemas is *not* a validator. It's a convenient helper for building [MongoDB unique indexes](https://docs.mongodb.com/manual/core/index-unique/). -See the [FAQ](../docs/faq.html) for more information. +See the [FAQ](faq.html) for more information. ```javascript [require:The `unique` Option is Not a Validator] @@ -142,10 +142,10 @@ nested objects are not fully fledged paths. ### Update Validators In the above examples, you learned about document validation. Mongoose also -supports validation for [`update()`](../docs/api.html#query_Query-update), -[`updateOne()`](../docs/api.html#query_Query-updateOne), -[`updateMany()`](../docs/api.html#query_Query-updateMany), -and [`findOneAndUpdate()`](../docs/api.html#query_Query-findOneAndUpdate) operations. +supports validation for [`update()`](api.html#query_Query-update), +[`updateOne()`](api.html#query_Query-updateOne), +[`updateMany()`](api.html#query_Query-updateMany), +and [`findOneAndUpdate()`](api.html#query_Query-findOneAndUpdate) operations. Update validators are off by default - you need to specify the `runValidators` option. @@ -210,4 +210,4 @@ of the array. ### Next Up -Now that we've covered `Validation`, let's take a look at [Middleware](../docs/middleware.html). +Now that we've covered `Validation`, let's take a look at [Middleware](middleware.html). diff --git a/simplify-relative-links.sh b/simplify-relative-links.sh new file mode 100755 index 00000000000..38a3f62d012 --- /dev/null +++ b/simplify-relative-links.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# find and replace in each markdown file: +# 1. pattern: "(../docs/.*)" becomes "(.*)" +# example: "(../docs/middleware.html)" becomes "(middleware.html)" +# example: "(../docs/middleware.html#something)" becomes "(middleware.html#something)" +# example: "(../docs/typescript/nested.html)" becomes "(typescript/nested.html)" +# 2. pattern: "(../../docs/.*)" becomes "(../.*)" +# example: "(../../docs/middleware.html)" becomes "(../middleware.html)" +# the parenthesis help guarantee that we are replacing markdown links +# warning: may need to run several times as these sed commands will only match one per line + +# get all the documentation markdown files +files=$(find docs -regextype posix-extended -regex '^.*\.md') + +for file in $files; +do + echo "find and replacing for" $file + sed -i 's/(\.\.\/docs\/\(.*\))/(\1)/' $file + sed -i 's/(\.\.\/\.\.\/docs\/\(.*\))/(\1)/' $file +done From f7a955db2f68ab1a57de4b8b2b2c9a55b931f3e0 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 4 Nov 2022 09:03:08 -0700 Subject: [PATCH 053/112] chore: remove semplify-relative-links.sh temporary script --- simplify-relative-links.sh | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100755 simplify-relative-links.sh diff --git a/simplify-relative-links.sh b/simplify-relative-links.sh deleted file mode 100755 index 38a3f62d012..00000000000 --- a/simplify-relative-links.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# find and replace in each markdown file: -# 1. pattern: "(../docs/.*)" becomes "(.*)" -# example: "(../docs/middleware.html)" becomes "(middleware.html)" -# example: "(../docs/middleware.html#something)" becomes "(middleware.html#something)" -# example: "(../docs/typescript/nested.html)" becomes "(typescript/nested.html)" -# 2. pattern: "(../../docs/.*)" becomes "(../.*)" -# example: "(../../docs/middleware.html)" becomes "(../middleware.html)" -# the parenthesis help guarantee that we are replacing markdown links -# warning: may need to run several times as these sed commands will only match one per line - -# get all the documentation markdown files -files=$(find docs -regextype posix-extended -regex '^.*\.md') - -for file in $files; -do - echo "find and replacing for" $file - sed -i 's/(\.\.\/docs\/\(.*\))/(\1)/' $file - sed -i 's/(\.\.\/\.\.\/docs\/\(.*\))/(\1)/' $file -done From ae14d0e52630bf65d255f52bf6baa6ef056d148e Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 4 Nov 2022 14:31:14 -0400 Subject: [PATCH 054/112] fix(types): allow setting SchemaTypeOptions' `index` property to IndexOptions Fix #12562 --- test/types/schema.test.ts | 25 +++++++++++++++++++++++++ types/schematypes.d.ts | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 2ab4698e4bc..b0e148afce5 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -872,3 +872,28 @@ function gh12431() { type Example = InferSchemaType; expectType<{ testDate?: Date, testDecimal?: Types.Decimal128 }>({} as Example); } + +function gh12562() { + const emailRegExp = /@/; + const userSchema = new Schema( + { + email: { + type: String, + trim: true, + validate: { + validator: (value: string) => emailRegExp.test(value), + message: 'Email is not valid' + }, + index: { // uncomment the index object and for me trim was throwing an error + partialFilterExpression: { + email: { + $exists: true, + $ne: null + } + } + }, + select: false + } + } + ); +} diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index 899660d9fe6..093651d1408 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -100,7 +100,7 @@ declare module 'mongoose' { * If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will * build an index on this path when the model is compiled. */ - index?: boolean | IndexDirection; + index?: boolean | IndexDirection | IndexOptions; /** * If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose From aed6497d5c83bbaf4ad8736e08978f0269541e84 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:05:54 -0400 Subject: [PATCH 055/112] Can overwrite foreignField for the query --- .../populate/assignRawDocsToIdStructure.js | 1 - .../populate/getModelsMapForPopulate.js | 3 --- lib/model.js | 15 +++++-------- lib/schema.js | 2 -- test/model.populate.test.js | 22 ++++++++++++++----- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/lib/helpers/populate/assignRawDocsToIdStructure.js b/lib/helpers/populate/assignRawDocsToIdStructure.js index a4d5f137c39..fbff9d10480 100644 --- a/lib/helpers/populate/assignRawDocsToIdStructure.js +++ b/lib/helpers/populate/assignRawDocsToIdStructure.js @@ -61,7 +61,6 @@ function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, re } sid = String(id); - doc = resultDocs[sid]; // If user wants separate copies of same doc, use this option if (options.clone && doc != null) { diff --git a/lib/helpers/populate/getModelsMapForPopulate.js b/lib/helpers/populate/getModelsMapForPopulate.js index d767c369578..9f034e5b84c 100644 --- a/lib/helpers/populate/getModelsMapForPopulate.js +++ b/lib/helpers/populate/getModelsMapForPopulate.js @@ -450,7 +450,6 @@ function _virtualPopulate(model, docs, options, _virtualRes) { localField = localField[0]; foreignField = foreignField[0]; } - data.localField = localField; data.foreignField = foreignField; data.match = match; @@ -526,7 +525,6 @@ function addModelNamesToMap(model, map, available, modelNames, options, data, re const currentOptions = { model: Model }; - if (data.isVirtual && get(data.virtual, 'options.options')) { currentOptions.options = utils.clone(data.virtual.options.options); } else if (schemaOptions != null) { @@ -537,7 +535,6 @@ function addModelNamesToMap(model, map, available, modelNames, options, data, re // Used internally for checking what model was used to populate this // path. options[populateModelSymbol] = Model; - available[modelName] = { model: Model, options: currentOptions, diff --git a/lib/model.js b/lib/model.js index 2b7e14ea3df..dcd6c66a4ac 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4604,7 +4604,6 @@ Model.populate = function(docs, paths, callback) { // normalized paths paths = utils.populate(paths); - // data that should persist across subPopulate calls const cache = {}; @@ -4656,12 +4655,6 @@ const excludeIdRegGlobal = /\s?-_id\s?/g; function populate(model, docs, options, callback) { const populateOptions = { ...options }; - if (options.localField || options.foreignField) { - // reassign options._localModel.schema.virtuals[virtual].options.localField on populateOptions - } - if (options.foreignField) { - // reassign options._localModel.schema.virtuals[virtual].options.foreignField on populateOptions - } if (options.strictPopulate == null) { if (options._localModel != null && options._localModel.schema._userProvidedOptions.strictPopulate != null) { populateOptions.strictPopulate = options._localModel.schema._userProvidedOptions.strictPopulate; @@ -4732,8 +4725,11 @@ function populate(model, docs, options, callback) { } hasOne = true; + if (populateOptions.foreignField) { + mod.foreignField.clear(); + mod.foreignField.add(populateOptions.foreignField) + } const match = createPopulateQueryFilter(ids, mod.match, mod.foreignField, mod.model, mod.options.skipInvalidIds); - if (assignmentOpts.excludeId) { // override the exclusion from the query so we can use the _id // for document matching during assignment. we'll delete the @@ -4830,7 +4826,6 @@ function _execPopulateQuery(mod, match, select, assignmentOpts, callback) { } else if (queryOptions.limit != null) { queryOptions.limit = queryOptions.limit * mod.ids.length; } - const query = mod.model.find(match, select, queryOptions); // If we're doing virtual populate and projection is inclusive and foreign // field is not selected, automatically select it because mongoose needs it. @@ -4887,6 +4882,7 @@ function _execPopulateQuery(mod, match, select, assignmentOpts, callback) { } callback(null, docs); }); + } /*! @@ -4917,7 +4913,6 @@ function _assign(model, vals, mod, assignmentOpts) { if (val == null) { continue; } - for (const foreignField of mod.foreignField) { _val = utils.getValue(foreignField, val); if (Array.isArray(_val)) { diff --git a/lib/schema.js b/lib/schema.js index ba8435e0e66..40dccd66dcd 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -552,7 +552,6 @@ Schema.prototype.defaultOptions = function(options) { * @return {Schema} the Schema instance * @api public */ - Schema.prototype.discriminator = function(name, schema) { this._applyDiscriminators = Object.assign(this._applyDiscriminators || {}, { [name]: schema }); @@ -2070,7 +2069,6 @@ Schema.prototype.virtual = function(name, options) { if (name instanceof VirtualType || getConstructorName(name) === 'VirtualType') { return this.virtual(name.path, name.options); } - options = new VirtualOptions(options); if (utils.hasUserDefinedProperty(options, ['ref', 'refPath'])) { diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 162831704a1..dd7d6262b5a 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10829,8 +10829,8 @@ describe('model: populate:', function() { assert.ok(err.message.includes('strictPopulate'), err.message); }); it('allows overwriting localField and foreignField when populating a virtual gh-6963', async function() { - const testSchema = Schema({ name: String }, { toJSON: { virtuals: true }, toObject: { virtuals: true } }); - const userSchema = Schema({ name: String, field: { type: mongoose.Schema.Types.ObjectId, ref: 'Test' } }); + const testSchema = Schema({ name: String, uuid: mongoose.Schema.Types.ObjectId }, { toJSON: { virtuals: true }, toObject: { virtuals: true } }); + const userSchema = Schema({ name: String, field: { type: mongoose.Schema.Types.ObjectId, ref: 'gh6963' }, change: { type: mongoose.Schema.Types.ObjectId, ref: 'gh6963' } }); testSchema.virtual('test', { ref: 'gh6963-2', localField: '_id', @@ -10841,15 +10841,25 @@ describe('model: populate:', function() { const User = db.model('gh6963-2', userSchema); const entry = await Test.create({ - name: 'Test' + name: 'Test', + uuid: mongoose.Types.ObjectId() + }); + const otherEntry = await Test.create({ + name: 'Other Test', + uuid: mongoose.Types.ObjectId() }); await User.create({ name: 'User', - field: entry._id + field: entry._id, + change: otherEntry._id }); - - const res = await Test.findOne().populate('test'); + const res = await Test.findOne({ _id: otherEntry._id }).populate({ path: 'test', foreignField: 'change' }); + const other = await Test.findOne({ _id: entry._id }).populate({ path: 'test', foreignField: 'change' }); assert.equal(res.test.length, 1); + assert.equal(other.test.length, 0) + // make sure its not broken + const response = await Test.findOne({ _id: entry._id }).populate('test'); + assert.equal(response.test.length, 1) }); }); }); From 6b96f27622638a83900d44cd19542c93f105ec64 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:12:14 -0400 Subject: [PATCH 056/112] Update model.populate.test.js --- test/model.populate.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/model.populate.test.js b/test/model.populate.test.js index dd7d6262b5a..5fc7ac58e81 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10860,6 +10860,8 @@ describe('model: populate:', function() { // make sure its not broken const response = await Test.findOne({ _id: entry._id }).populate('test'); assert.equal(response.test.length, 1) + // =================localField====================== + // ============localFieldAndForeignField============ }); }); }); From fa1f5544609b72486fba256d2f78cf2172f9e94a Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 4 Nov 2022 13:24:28 -0700 Subject: [PATCH 057/112] find replace '../tutorials/' with '' in all files under docs/tutorials/*.md --- docs/tutorials/lean.md | 2 +- docs/tutorials/virtuals.md | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/tutorials/lean.md b/docs/tutorials/lean.md index 5c053c45c2e..b1352ccee22 100644 --- a/docs/tutorials/lean.md +++ b/docs/tutorials/lean.md @@ -118,7 +118,7 @@ to add virtuals to your lean query results. ## Plugins -Using `lean()` bypasses all Mongoose features, including [virtuals](../tutorials/virtuals.html), [getters/setters](../tutorials/getters-setters.html), +Using `lean()` bypasses all Mongoose features, including [virtuals](virtuals.html), [getters/setters](getters-setters.html), and [defaults](../api.html#schematype_SchemaType-default). If you want to use these features with `lean()`, you need to use the corresponding plugin: diff --git a/docs/tutorials/virtuals.md b/docs/tutorials/virtuals.md index e7c07ba70e8..d8539037c67 100644 --- a/docs/tutorials/virtuals.md +++ b/docs/tutorials/virtuals.md @@ -3,13 +3,15 @@ In Mongoose, a virtual is a property that is **not** stored in MongoDB. Virtuals are typically used for computed properties on documents. -* [Your First Virtual](#your-first-virtual) -* [Virtual Setters](#virtual-setters) -* [Virtuals in JSON](#virtuals-in-json) -* [Virtuals with Lean](#virtuals-with-lean) -* [Limitations](#limitations) -* [Populate](#populate) -* [Further Reading](#further-reading) +- [Mongoose Virtuals](#mongoose-virtuals) + - [Your First Virtual](#your-first-virtual) + - [Virtual Setters](#virtual-setters) + - [Virtuals in JSON](#virtuals-in-json) + - [Virtuals in `console.log()`](#virtuals-in-consolelog) + - [Virtuals with Lean](#virtuals-with-lean) + - [Limitations](#limitations) + - [Populate](#populate) + - [Further Reading](#further-reading) ## Your First Virtual @@ -27,13 +29,13 @@ You define virtuals on a schema using the [`Schema#virtual()` function](../api/s The `Schema#virtual()` function returns a [`VirtualType` object](../api/virtualtype.html). Unlike normal document properties, virtuals do not have any underlying value and Mongoose does not do any type coercion on virtuals. However, virtuals do have -[getters and setters](../tutorials/getters-setters.html), which make +[getters and setters](getters-setters.html), which make them ideal for computed properties, like the `domain` example above. ## Virtual Setters You can also use virtuals to set multiple properties at once as an -alternative to [custom setters on normal properties](../tutorials/getters-setters.html#setters). For example, suppose +alternative to [custom setters on normal properties](getters-setters.html#setters). For example, suppose you have two string properties: `firstName` and `lastName`. You can create a virtual property `fullName` that lets you set both of these properties at once. The key detail is that, in virtual getters and @@ -67,7 +69,7 @@ console.log(doc.toObject({ virtuals: true })); ## Virtuals with Lean Virtuals are properties on Mongoose documents. If you use the -[lean option](../tutorials/lean.html), that means your queries return POJOs +[lean option](lean.html), that means your queries return POJOs rather than full Mongoose documents. That means no virtuals if you use [`lean()`](../api/query.html#query_Query-lean). @@ -90,7 +92,7 @@ based on Mongoose virtuals. ``` If you want to query by a computed property, you should set the property using -a [custom setter](../tutorials/getters-setters.html) or [pre save middleware](../middleware.html). +a [custom setter](getters-setters.html) or [pre save middleware](../middleware.html). ## Populate From fda5692d6b1f8349fba7170d329261c4496f8b3d Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 4 Nov 2022 13:28:17 -0700 Subject: [PATCH 058/112] fix: fix bad tutorials link in docs/typescript/virtuals.md --- docs/typescript/virtuals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/typescript/virtuals.md b/docs/typescript/virtuals.md index 95b6ca1886b..258cc59034e 100644 --- a/docs/typescript/virtuals.md +++ b/docs/typescript/virtuals.md @@ -1,6 +1,6 @@ # Virtuals in TypeScript -[Virtuals](tutorials/virtuals.html) are computed properties: you can access virtuals on hydrated Mongoose documents, but virtuals are **not** stored in MongoDB. +[Virtuals](../tutorials/virtuals.html) are computed properties: you can access virtuals on hydrated Mongoose documents, but virtuals are **not** stored in MongoDB. Mongoose supports auto typed virtuals so you don't need to define additional typescript interface anymore but you are still able to do so. ### Automatically Inferred Types: From 1f49f4b550ed0e903844f84864b852ccdab25220 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 4 Nov 2022 13:43:31 -0700 Subject: [PATCH 059/112] fix: broken 'further-reading' header link should be '#further-reading' --- docs/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide.md b/docs/guide.md index fad5017a897..b764da88544 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -1379,7 +1379,7 @@ console.log(schema.virtuals); // { myVirtual: VirtualType { ... } } Schemas are also [pluggable](./plugins.html) which allows us to package up reusable features into plugins that can be shared with the community or just between your projects. -

    Further Reading

    +

    Further Reading

    Here's an [alternative introduction to Mongoose schemas](https://masteringjs.io/tutorials/mongoose/schema). From 0fb4eb8c7b00d05b7046130473987f9333d7863d Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:44:03 -0400 Subject: [PATCH 060/112] can do local field --- lib/model.js | 11 ++++++++--- test/model.populate.test.js | 29 ++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/model.js b/lib/model.js index dcd6c66a4ac..8a247ab6f2a 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4664,6 +4664,10 @@ function populate(model, docs, options, callback) { populateOptions.strictPopulate = model.base.options.strictPopulate; } } + const originalLocalField = model.schema.virtuals[populateOptions.path].options.localField; + if (populateOptions.localField) { + model.schema.virtuals[populateOptions.path].options.localField = populateOptions.localField; + } // normalize single / multiple docs passed if (!Array.isArray(docs)) { @@ -4674,12 +4678,13 @@ function populate(model, docs, options, callback) { } const modelsMap = getModelsMapForPopulate(model, docs, populateOptions); + if (modelsMap instanceof MongooseError) { return immediate(function() { callback(modelsMap); }); } - + model.schema.virtuals[populateOptions.path].options.localField = originalLocalField; const len = modelsMap.length; let vals = []; @@ -4727,7 +4732,7 @@ function populate(model, docs, options, callback) { hasOne = true; if (populateOptions.foreignField) { mod.foreignField.clear(); - mod.foreignField.add(populateOptions.foreignField) + mod.foreignField.add(populateOptions.foreignField); } const match = createPopulateQueryFilter(ids, mod.match, mod.foreignField, mod.model, mod.options.skipInvalidIds); if (assignmentOpts.excludeId) { @@ -4882,7 +4887,7 @@ function _execPopulateQuery(mod, match, select, assignmentOpts, callback) { } callback(null, docs); }); - + } /*! diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 5fc7ac58e81..c603a811333 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10829,7 +10829,7 @@ describe('model: populate:', function() { assert.ok(err.message.includes('strictPopulate'), err.message); }); it('allows overwriting localField and foreignField when populating a virtual gh-6963', async function() { - const testSchema = Schema({ name: String, uuid: mongoose.Schema.Types.ObjectId }, { toJSON: { virtuals: true }, toObject: { virtuals: true } }); + const testSchema = Schema({ name: String, uuid: 'ObjectId' }, { toJSON: { virtuals: true }, toObject: { virtuals: true } }); const userSchema = Schema({ name: String, field: { type: mongoose.Schema.Types.ObjectId, ref: 'gh6963' }, change: { type: mongoose.Schema.Types.ObjectId, ref: 'gh6963' } }); testSchema.virtual('test', { ref: 'gh6963-2', @@ -10856,11 +10856,34 @@ describe('model: populate:', function() { const res = await Test.findOne({ _id: otherEntry._id }).populate({ path: 'test', foreignField: 'change' }); const other = await Test.findOne({ _id: entry._id }).populate({ path: 'test', foreignField: 'change' }); assert.equal(res.test.length, 1); - assert.equal(other.test.length, 0) + assert.equal(other.test.length, 0); // make sure its not broken const response = await Test.findOne({ _id: entry._id }).populate('test'); - assert.equal(response.test.length, 1) + assert.equal(response.test.length, 1); // =================localField====================== + const localEntry = await Test.create({ + name: 'local test', + uuid: mongoose.Types.ObjectId() + }); + const otherLocalEntry = await Test.create({ + name: 'other local test', + uuid: mongoose.Types.ObjectId() + }); + + await User.create({ + name: 'local user', + field: localEntry.uuid, + change: otherLocalEntry.uuid + }); + + const localTest = await Test.findOne({ _id: localEntry._id }).populate({ path: 'test', localField: 'uuid' }); + assert.equal(localTest.test.length, 1) + const otherLocalTest = await Test.findOne({ _id: otherLocalEntry._id }).populate({ path: 'test', localField: 'uuid' }); + assert.equal(otherLocalTest.test.length, 0); + // should be empty because the original local field was _id and we created a doc with uuids + const check = await Test.findOne({ _id: localEntry._id }).populate({ path: 'test' }); + assert.equal(check.test.length, 0); + // ============localFieldAndForeignField============ }); }); From 8cc3c07cf25b8c018039ee39144153f8cf98dccf Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:53:17 -0400 Subject: [PATCH 061/112] can do both --- test/model.populate.test.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/model.populate.test.js b/test/model.populate.test.js index c603a811333..f9286dca145 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10883,8 +10883,21 @@ describe('model: populate:', function() { // should be empty because the original local field was _id and we created a doc with uuids const check = await Test.findOne({ _id: localEntry._id }).populate({ path: 'test' }); assert.equal(check.test.length, 0); - // ============localFieldAndForeignField============ + const bothEntry = await Test.create({ name: 'Both', uuid: mongoose.Types.ObjectId() }); + const otherBothEntry = await Test.create({ name: 'Other Both', uuid: mongoose.Types.ObjectId() }); + await User.create({ + name: 'both user', + field: bothEntry.uuid, + change: otherBothEntry.uuid + }); + const bothTest = await Test.findOne({ _id: otherBothEntry._id }).populate({ path: 'test', localField: 'uuid', foreignField: 'change' }); + assert.equal(bothTest.test.length, 1); + const otherBothTest = await Test.findOne({ _id: bothEntry._id }).populate({ path: 'test', localField: 'uuid', foreignField: 'change' }); + assert.equal(otherBothTest.test.length, 0); + const normal = await Test.findOne({ _id: otherBothEntry._id }).populate({ path: 'test' }); + // should be empty because the original local field was _id and we created a doc with uuids + assert.equal(normal.test.length, 0); }); }); }); From 46c2a0baf05a387b722f9ad85f280ae7eb47b9a1 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 4 Nov 2022 14:25:44 -0700 Subject: [PATCH 062/112] fix: several broken links in schemas and statics-and-methods --- docs/typescript/schemas.md | 2 +- docs/typescript/statics-and-methods.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/typescript/schemas.md b/docs/typescript/schemas.md index 00f72fb7d2a..f6f1959ba69 100644 --- a/docs/typescript/schemas.md +++ b/docs/typescript/schemas.md @@ -95,7 +95,7 @@ The second generic param, `M`, is the model used with the schema. Mongoose uses The third generic param, `TInstanceMethods` is used to add types for instance methods defined in the schema. -The 4th param, `TQueryHelpers`, is used to add types for [chainable query helpers](typescript/query-helpers.html). +The 4th param, `TQueryHelpers`, is `used to add types for [chainable query helpers](query-helpers.html). ## Schema vs Interface fields diff --git a/docs/typescript/statics-and-methods.md b/docs/typescript/statics-and-methods.md index 5b83a7ab1ac..e49a8a520c5 100644 --- a/docs/typescript/statics-and-methods.md +++ b/docs/typescript/statics-and-methods.md @@ -5,7 +5,7 @@ With a little extra configuration, you can also register methods and statics in ## Methods -To define an [instance method](guide.html#methods) in TypeScript, create a new interface representing your instance methods. +To define an [instance method](../guide.html#methods) in TypeScript, create a new interface representing your instance methods. You need to pass that interface as the 3rd generic parameter to the `Schema` constructor **and** as the 3rd generic parameter to `Model` as shown below. ```typescript @@ -41,7 +41,7 @@ const fullName: string = user.fullName(); // 'Jean-Luc Picard' ## Statics -Mongoose [models](../models.html) do **not** have an explicit generic parameter for [statics](guide.html#statics). +Mongoose [models](../models.html) do **not** have an explicit generic parameter for [statics](../guide.html#statics). If your model has statics, we recommend creating an interface that [extends](https://www.typescriptlang.org/docs/handbook/interfaces.html) Mongoose's `Model` interface as shown below. ```typescript From a129efe4ae8d3b7797350a6589aa2b5ad370cea2 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 4 Nov 2022 14:58:25 -0700 Subject: [PATCH 063/112] fix: revert unecessary backtick --- docs/typescript/schemas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/typescript/schemas.md b/docs/typescript/schemas.md index f6f1959ba69..656c058d5c6 100644 --- a/docs/typescript/schemas.md +++ b/docs/typescript/schemas.md @@ -95,7 +95,7 @@ The second generic param, `M`, is the model used with the schema. Mongoose uses The third generic param, `TInstanceMethods` is used to add types for instance methods defined in the schema. -The 4th param, `TQueryHelpers`, is `used to add types for [chainable query helpers](query-helpers.html). +The 4th param, `TQueryHelpers`, is used to add types for [chainable query helpers](query-helpers.html). ## Schema vs Interface fields From 389550ed2d72382b37f0638796bef99b9f463156 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 4 Nov 2022 15:02:02 -0700 Subject: [PATCH 064/112] remove unecessary table of contents change --- docs/tutorials/virtuals.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/docs/tutorials/virtuals.md b/docs/tutorials/virtuals.md index d8539037c67..69e5e78280a 100644 --- a/docs/tutorials/virtuals.md +++ b/docs/tutorials/virtuals.md @@ -3,15 +3,13 @@ In Mongoose, a virtual is a property that is **not** stored in MongoDB. Virtuals are typically used for computed properties on documents. -- [Mongoose Virtuals](#mongoose-virtuals) - - [Your First Virtual](#your-first-virtual) - - [Virtual Setters](#virtual-setters) - - [Virtuals in JSON](#virtuals-in-json) - - [Virtuals in `console.log()`](#virtuals-in-consolelog) - - [Virtuals with Lean](#virtuals-with-lean) - - [Limitations](#limitations) - - [Populate](#populate) - - [Further Reading](#further-reading) +* [Your First Virtual](#your-first-virtual) +* [Virtual Setters](#virtual-setters) +* [Virtuals in JSON](#virtuals-in-json) +* [Virtuals with Lean](#virtuals-with-lean) +* [Limitations](#limitations) +* [Populate](#populate) +* [Further Reading](#further-reading) ## Your First Virtual From a061ccdf71e1fc24f716d4ce791281d6168cf639 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 4 Nov 2022 18:10:11 -0400 Subject: [PATCH 065/112] fix(types): correct handling for model Fix #12573 --- test/types/models.test.ts | 6 ++++++ types/index.d.ts | 1 - types/inferschematype.d.ts | 2 +- types/utility.d.ts | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/types/models.test.ts b/test/types/models.test.ts index c6678a5a0d1..153d86cbb4c 100644 --- a/test/types/models.test.ts +++ b/test/types/models.test.ts @@ -561,3 +561,9 @@ function findWithId() { TestModel.find(id); TestModel.findOne(id); } + +function gh12573ModelAny() { + const TestModel = model('Test', new Schema({})); + const doc = new TestModel(); + expectType(doc); +} diff --git a/types/index.d.ts b/types/index.d.ts index 97663a46d84..f7cf20b31ac 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -551,7 +551,6 @@ declare module 'mongoose' { export type SchemaDefinitionType = T extends Document ? Omit> : T; // Helpers to simplify checks - type IfAny = 0 extends (1 & IFTYPE) ? THENTYPE : ELSETYPE; type IfUnknown = unknown extends IFTYPE ? THENTYPE : IFTYPE; // tests for these two types are located in test/types/lean.test.ts diff --git a/types/inferschematype.d.ts b/types/inferschematype.d.ts index 27090b89eb4..3874e98b8a6 100644 --- a/types/inferschematype.d.ts +++ b/types/inferschematype.d.ts @@ -38,7 +38,7 @@ declare module 'mongoose' { * // result * type UserType = {userName?: string} */ - type InferSchemaType = ObtainSchemaGeneric; + type InferSchemaType = IfAny>; /** * @summary Obtains schema Generic type by using generic alias. diff --git a/types/utility.d.ts b/types/utility.d.ts index bfc531aa8f2..e5567b37b28 100644 --- a/types/utility.d.ts +++ b/types/utility.d.ts @@ -1,4 +1,5 @@ declare module 'mongoose' { + type IfAny = 0 extends (1 & IFTYPE) ? THENTYPE : ELSETYPE; type Unpacked = T extends (infer U)[] ? U : From cf8da8329e39550c9a6b2243cfcb5e8d93d012a2 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Sat, 5 Nov 2022 13:08:47 -0400 Subject: [PATCH 066/112] fix undefined issue --- lib/model.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/model.js b/lib/model.js index 8a247ab6f2a..f9a31a991ed 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4664,7 +4664,10 @@ function populate(model, docs, options, callback) { populateOptions.strictPopulate = model.base.options.strictPopulate; } } - const originalLocalField = model.schema.virtuals[populateOptions.path].options.localField; + let originalLocalField = ''; + if (model.schema.virtuals[populateOptions.path]) { + originalLocalField = model.schema.virtuals[populateOptions.path].options.localField; + } if (populateOptions.localField) { model.schema.virtuals[populateOptions.path].options.localField = populateOptions.localField; } @@ -4684,7 +4687,7 @@ function populate(model, docs, options, callback) { callback(modelsMap); }); } - model.schema.virtuals[populateOptions.path].options.localField = originalLocalField; + if (originalLocalField) model.schema.virtuals[populateOptions.path].options.localField = originalLocalField; const len = modelsMap.length; let vals = []; From c05c539b49947971fd3b6077236aa80f95d10aa2 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Sat, 5 Nov 2022 13:12:39 -0400 Subject: [PATCH 067/112] fix my lint --- lib/model.js | 2 +- test/model.populate.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/model.js b/lib/model.js index f9a31a991ed..e7451aac3f3 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4681,7 +4681,7 @@ function populate(model, docs, options, callback) { } const modelsMap = getModelsMapForPopulate(model, docs, populateOptions); - + if (modelsMap instanceof MongooseError) { return immediate(function() { callback(modelsMap); diff --git a/test/model.populate.test.js b/test/model.populate.test.js index f9286dca145..3b4726c15d0 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10877,7 +10877,7 @@ describe('model: populate:', function() { }); const localTest = await Test.findOne({ _id: localEntry._id }).populate({ path: 'test', localField: 'uuid' }); - assert.equal(localTest.test.length, 1) + assert.equal(localTest.test.length, 1); const otherLocalTest = await Test.findOne({ _id: otherLocalEntry._id }).populate({ path: 'test', localField: 'uuid' }); assert.equal(otherLocalTest.test.length, 0); // should be empty because the original local field was _id and we created a doc with uuids From 6c7833432bd71a429a6417b065639ebbdb3edcab Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 6 Nov 2022 20:20:13 -0500 Subject: [PATCH 068/112] fix(types): set `this` to doc type in `SchemaType.prototype.validate()` Fix #12590 --- test/types/schema.test.ts | 18 ++++++++++++++++++ types/index.d.ts | 2 +- types/schematypes.d.ts | 10 +++++++--- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index b0e148afce5..c818bedaf93 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -897,3 +897,21 @@ function gh12562() { } ); } + +function gh12590() { + const UserSchema = new Schema({ + _password: String + }); + + type User = InferSchemaType; + + expectType>(UserSchema.path('hashed_password')); + + UserSchema.path('hashed_password').validate(function(v: any) { + expectType>(this); + if (this._password && this._password.length < 8) { + this.invalidate('password', 'Password must be at least 8 characters.'); + } + }); + +} diff --git a/types/index.d.ts b/types/index.d.ts index 97663a46d84..4f7cc0e1393 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -258,8 +258,8 @@ declare module 'mongoose' { obj: SchemaDefinition>; /** Gets/sets schema paths. */ + path>>(path: string): ResultType; path(path: pathGeneric): SchemaType; - path(path: string): ResultType; path(path: string, constructor: any): this; /** Lists all paths and their type in the schema. */ diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index 093651d1408..513037cffe5 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -188,7 +188,11 @@ declare module 'mongoose' { [other: string]: any; } - class SchemaType { + interface Validator { + message?: string; type?: string; validator?: Function + } + + class SchemaType { /** SchemaType constructor */ constructor(path: string, options?: AnyObject, instance?: string); @@ -270,10 +274,10 @@ declare module 'mongoose' { unique(bool: boolean): this; /** The validators that Mongoose should run to validate properties at this SchemaType's path. */ - validators: { message?: string; type?: string; validator?: Function }[]; + validators: Validator[]; /** Adds validator(s) for this document path. */ - validate(obj: RegExp | Function | any, errorMsg?: string, type?: string): this; + validate(obj: RegExp | ((this: DocType, value: any, validatorProperties?: Validator) => any), errorMsg?: string, type?: string): this; } namespace Schema { From f9fb6123ab185d935e947d9637a0b9b1209e1052 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 6 Nov 2022 20:23:49 -0500 Subject: [PATCH 069/112] Update test/types/models.test.ts Co-authored-by: hasezoey --- test/types/models.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/types/models.test.ts b/test/types/models.test.ts index 153d86cbb4c..d31a447eee9 100644 --- a/test/types/models.test.ts +++ b/test/types/models.test.ts @@ -566,4 +566,6 @@ function gh12573ModelAny() { const TestModel = model('Test', new Schema({})); const doc = new TestModel(); expectType(doc); + const { fieldA } = doc; + expectType(fieldA); } From 78b91b4c36d5f8757421dc8def589b16ae4ff628 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 7 Nov 2022 12:02:53 -0500 Subject: [PATCH 070/112] test(types): address code review comments --- test/types/schema.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index c818bedaf93..6bf7bcd94d2 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -907,7 +907,7 @@ function gh12590() { expectType>(UserSchema.path('hashed_password')); - UserSchema.path('hashed_password').validate(function(v: any) { + UserSchema.path('hashed_password').validate(function(v) { expectType>(this); if (this._password && this._password.length < 8) { this.invalidate('password', 'Password must be at least 8 characters.'); From f1c433c0f90ad1a65c8b3795eefaaf02a64b849e Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 7 Nov 2022 12:20:22 -0500 Subject: [PATCH 071/112] chore: release 6.7.2 --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b625c0cba1b..d54e3a7223e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +6.7.2 / 2022-11-07 +================== + * fix(discriminator): skip copying base schema plugins if `applyPlugins == false` #12613 #12604 [lpizzinidev](https://github.com/lpizzinidev) + * fix(types): add UUID to types #12650 #12593 + * fix(types): allow setting SchemaTypeOptions' index property to IndexOptions #12562 + * fix(types): set this to doc type in SchemaType.prototype.validate() #12663 #12590 + * fix(types): correct handling for model #12659 #12573 + * fix(types): pre hook with deleteOne should resolve this as Query #12642 #12622 [lpizzinidev](https://github.com/lpizzinidev) + 6.7.1 / 2022-11-02 ================== * fix(query): select Map field with select: false when explicitly requested #12616 #12603 [lpizzinidev](https://github.com/lpizzinidev) diff --git a/package.json b/package.json index e1dd615e0a8..48899d57b59 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mongoose", "description": "Mongoose MongoDB ODM", - "version": "6.7.1", + "version": "6.7.2", "author": "Guillermo Rauch ", "keywords": [ "mongodb", From 4ca7d2fc6d1172b681a010c447017a7503e516b1 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 9 Nov 2022 21:17:05 -0500 Subject: [PATCH 072/112] fix(document): handle setting array to itself after saving and pushing a new value Fix #12656 --- lib/document.js | 34 +++++++++++++++++++++++++--------- test/document.test.js | 23 ++++++++++++++++++++++- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/lib/document.js b/lib/document.js index 824ac6cf96f..228b6cd0f2d 100644 --- a/lib/document.js +++ b/lib/document.js @@ -1468,13 +1468,7 @@ Document.prototype.$set = function $set(path, val, type, options) { const doc = this.$isSubdocument ? this.ownerDocument() : this; savedState = doc.$__.savedState; savedStatePath = this.$isSubdocument ? this.$__.fullPath + '.' + path : path; - if (savedState != null) { - const firstDot = savedStatePath.indexOf('.'); - const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot); - if (!savedState.hasOwnProperty(topLevelPath)) { - savedState[topLevelPath] = utils.clone(doc.$__getValue(topLevelPath)); - } - } + doc.$__saveInitialState(savedStatePath); } this.$__set(pathToMark, path, options, constructing, parts, schema, val, priorVal); @@ -1583,6 +1577,10 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru if (this.$isNew) { return true; } + // Is path already modified? If so, always modify. We may unmark modified later. + if (path in this.$__.activePaths.getStatePaths('modify')) { + return true; + } // Re: the note about gh-7196, `val` is the raw value without casting or // setters if the full path is under a single nested subdoc because we don't @@ -1780,11 +1778,10 @@ Document.prototype.$inc = function $inc(path, val) { const currentValue = this.$__getValue(path) || 0; - this.$__setValue(path, currentValue + val); - this.$__.primitiveAtomics = this.$__.primitiveAtomics || {}; this.$__.primitiveAtomics[path] = { $inc: val }; this.markModified(path); + this.$__setValue(path, currentValue + val); return this; }; @@ -1927,6 +1924,8 @@ Document.prototype.$__path = function(path) { */ Document.prototype.markModified = function(path, scope) { + this.$__saveInitialState(path); + this.$__.activePaths.modify(path); if (scope != null && !this.$isSubdocument) { this.$__.pathsToScopes = this.$__pathsToScopes || {}; @@ -1934,6 +1933,22 @@ Document.prototype.markModified = function(path, scope) { } }; +/*! + * ignore + */ + +Document.prototype.$__saveInitialState = function $__saveInitialState(path) { + const savedState = this.$__.savedState; + const savedStatePath = path; + if (savedState != null) { + const firstDot = savedStatePath.indexOf('.'); + const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot); + if (!savedState.hasOwnProperty(topLevelPath)) { + savedState[topLevelPath] = utils.clone(this.$__getValue(topLevelPath)); + } + } +}; + /** * Clears the modified state on the specified path. * @@ -3379,6 +3394,7 @@ Document.prototype.$__dirty = function() { schema: _this.$__path(path) }; }); + // gh-2558: if we had to set a default and the value is not undefined, // we have to save as well all = all.concat(this.$__.activePaths.map('default', function(path) { diff --git a/test/document.test.js b/test/document.test.js index 1a757bbde32..9468225919c 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -9191,7 +9191,6 @@ describe('document', function() { const Test = db.model('Test', schema); - const foo = new Test({ bar: 'bar' }); await foo.save(); assert.ok(!foo.isModified('bar')); @@ -11996,6 +11995,28 @@ describe('document', function() { title: 'The power of JavaScript' }); }); + + it('handles setting array to itself after saving and pushing a new value (gh-12656)', async function() { + const Test = db.model('Test', new Schema({ + list: [{ + a: Number + }] + })); + await Test.create({ list: [{ a: 1, b: 11 }] }); + + let doc = await Test.findOne(); + doc.list.push({ a: 2 }); + doc.list = [...doc.list]; + await doc.save(); + + doc.list.push({ a: 3 }); + doc.list = [...doc.list]; + await doc.save(); + + doc = await Test.findOne(); + assert.equal(doc.list.length, 3); + assert.deepStrictEqual(doc.list.map(el => el.a), [1, 2, 3]); + }); }); describe('Check if instance function that is supplied in schema option is availabe', function() { From dd199ccf26d45f87f6acdc9a2528f0f366998642 Mon Sep 17 00:00:00 2001 From: Raphael Papazikas Date: Fri, 11 Nov 2022 18:20:16 +0100 Subject: [PATCH 073/112] fix(schema): setupTimestampts check if base != null fix(setupTimestampts): add semicolon --- lib/helpers/timestamps/setupTimestamps.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/timestamps/setupTimestamps.js b/lib/helpers/timestamps/setupTimestamps.js index 99f3aeb256d..ed44e7d938c 100644 --- a/lib/helpers/timestamps/setupTimestamps.js +++ b/lib/helpers/timestamps/setupTimestamps.js @@ -28,7 +28,7 @@ module.exports = function setupTimestamps(schema, timestamps) { schema.$timestamps = { createdAt: createdAt, updatedAt: updatedAt }; if (createdAt && !schema.paths[createdAt]) { - const baseImmutableCreatedAt = schema.base.get('timestamps.createdAt.immutable'); + const baseImmutableCreatedAt = schema.base != null ? schema.base.get('timestamps.createdAt.immutable') : null; const immutable = baseImmutableCreatedAt != null ? baseImmutableCreatedAt : true; schemaAdditions[createdAt] = { [schema.options.typeKey || 'type']: Date, immutable }; } From c99c127857415b49ca18a7a5395fa5f31bac7a4e Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 12 Nov 2022 10:19:27 +0100 Subject: [PATCH 074/112] fix(document): Removed modelName from document types fix #12669 --- types/document.d.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/types/document.d.ts b/types/document.d.ts index 897527c45ca..057215daa39 100644 --- a/types/document.d.ts +++ b/types/document.d.ts @@ -190,9 +190,6 @@ declare module 'mongoose' { /** Returns the list of paths that have been modified. */ modifiedPaths(options?: { includeChildren?: boolean }): Array; - /** The name of the model */ - modelName: string; - /** * Overwrite all values in this document with the values of `obj`, except * for immutable properties. Behaves similarly to `set()`, except for it From 87d843d8fb05fce959808666dd15ce28231b875c Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sat, 12 Nov 2022 17:07:58 -0500 Subject: [PATCH 075/112] docs(document): explain that `$isNew` is `false` in post('save') hooks Fix #11990 --- lib/document.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/document.js b/lib/document.js index 228b6cd0f2d..727337aea81 100644 --- a/lib/document.js +++ b/lib/document.js @@ -219,6 +219,17 @@ function Document(obj, fields, skipId, options) { * * const user = await User.findOne({ name: 'John Smith' }); * user.$isNew; // false + * + * Mongoose sets `$isNew` to `false` immediately after `save()` succeeds. + * That means Mongoose sets `$isNew` to false **before** `post('save')` hooks run. + * In `post('save')` hooks, `$isNew` will be `false` if `save()` succeeded. + * + * #### Example: + * + * userSchema.post('save', function() { + * this.$isNew; // false + * }); + * await User.create({ name: 'John Smith' }); * * For subdocuments, `$isNew` is true if either the parent has `$isNew` set, * or if you create a new subdocument. From ed6740fa2febde83bfd9606512cf81b35205d7d9 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sat, 12 Nov 2022 17:19:11 -0500 Subject: [PATCH 076/112] docs: fix inverted explanation of `justOne` option for populate Fix #12599 --- lib/model.js | 2 +- types/populate.d.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/model.js b/lib/model.js index 8f876bc3321..bce27dc970d 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4556,7 +4556,7 @@ Model.validate = function validate(obj, pathsToValidate, context, callback) { * - match: optional query conditions to match * - model: optional name of the model to use for population * - options: optional query options like sort, limit, etc - * - justOne: optional boolean, if true Mongoose will always set `path` to an array. Inferred from schema by default. + * - justOne: optional boolean, if true Mongoose will always set `path` to a document or `null`. If false, Mongoose will always set `path` to a potentially empty array. Inferred from schema by default. * - strictPopulate: optional boolean, set to `false` to allow populating paths that aren't in the schema. * * #### Example: diff --git a/types/populate.d.ts b/types/populate.d.ts index 3d53cea140c..f30cd0eccec 100644 --- a/types/populate.d.ts +++ b/types/populate.d.ts @@ -26,8 +26,9 @@ declare module 'mongoose' { /** deep populate */ populate?: string | PopulateOptions | (string | PopulateOptions)[]; /** - * If true Mongoose will always set `path` to an array, if false Mongoose will - * always set `path` to a document. Inferred from schema by default. + * If true Mongoose will always set `path` to a document or `null`. + * If false Mongoose will always set `path` to a potentially empty array. + * Inferred from schema by default. */ justOne?: boolean; /** transform function to call on every populated doc */ From 349e03848a9f404b6d80cf1d4ec3e7fee1eb952f Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 13 Nov 2022 12:55:41 -0500 Subject: [PATCH 077/112] style: fix lint --- lib/document.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/document.js b/lib/document.js index 727337aea81..b7763d09de7 100644 --- a/lib/document.js +++ b/lib/document.js @@ -219,13 +219,13 @@ function Document(obj, fields, skipId, options) { * * const user = await User.findOne({ name: 'John Smith' }); * user.$isNew; // false - * + * * Mongoose sets `$isNew` to `false` immediately after `save()` succeeds. * That means Mongoose sets `$isNew` to false **before** `post('save')` hooks run. * In `post('save')` hooks, `$isNew` will be `false` if `save()` succeeded. - * + * * #### Example: - * + * * userSchema.post('save', function() { * this.$isNew; // false * }); From a5d2acf620608ce09b3a23fdbf286dc773b1f04c Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 13 Nov 2022 13:11:24 -0500 Subject: [PATCH 078/112] docs: address code review comments re: #12599 --- lib/model.js | 2 +- types/populate.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/model.js b/lib/model.js index bce27dc970d..8f381964cb4 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4556,7 +4556,7 @@ Model.validate = function validate(obj, pathsToValidate, context, callback) { * - match: optional query conditions to match * - model: optional name of the model to use for population * - options: optional query options like sort, limit, etc - * - justOne: optional boolean, if true Mongoose will always set `path` to a document or `null`. If false, Mongoose will always set `path` to a potentially empty array. Inferred from schema by default. + * - justOne: optional boolean, if true Mongoose will always set `path` to a document, or `null` if no document was found. If false, Mongoose will always set `path` to an array, which will be empty if no documents are found. Inferred from schema by default. * - strictPopulate: optional boolean, set to `false` to allow populating paths that aren't in the schema. * * #### Example: diff --git a/types/populate.d.ts b/types/populate.d.ts index f30cd0eccec..77575c6da0e 100644 --- a/types/populate.d.ts +++ b/types/populate.d.ts @@ -26,8 +26,8 @@ declare module 'mongoose' { /** deep populate */ populate?: string | PopulateOptions | (string | PopulateOptions)[]; /** - * If true Mongoose will always set `path` to a document or `null`. - * If false Mongoose will always set `path` to a potentially empty array. + * If true Mongoose will always set `path` to a document, or `null` if no document was found. + * If false Mongoose will always set `path` to an array, which will be empty if no documents are found. * Inferred from schema by default. */ justOne?: boolean; From c6d3b160fe0467e01c88f1caac94900f9a370e8f Mon Sep 17 00:00:00 2001 From: hasezoey Date: Mon, 14 Nov 2022 13:48:07 +0100 Subject: [PATCH 079/112] docs(CONTRIBUTING): update documentation reference to ".pug" files --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 895ca4587ae..9c7897da3b8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,7 +50,7 @@ If you have a question about Mongoose (not a bug report) please post it to eithe To contribute to the [API documentation](http://mongoosejs.com/docs/api.html) just make your changes to the inline documentation of the appropriate [source code](https://github.com/Automattic/mongoose/tree/master/lib) in the master branch and submit a [pull request](https://help.github.com/articles/using-pull-requests/). You might also use the github [Edit](https://github.com/blog/844-forking-with-the-edit-button) button. -To contribute to the [guide](http://mongoosejs.com/docs/guide.html) or [quick start](http://mongoosejs.com/docs/index.html) docs, make your changes to the appropriate `.pug` files in the [docs](https://github.com/Automattic/mongoose/tree/master/docs) directory of the master branch and submit a pull request. Again, the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button might work for you here. +To contribute to the [guide](http://mongoosejs.com/docs/guide.html) or [quick start](http://mongoosejs.com/docs/index.html) docs, make your changes to the appropriate `.pug` / `.md` files in the [docs](https://github.com/Automattic/mongoose/tree/master/docs) directory of the master branch and submit a pull request. Again, the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button might work for you here. If you'd like to preview your documentation changes, first commit your changes to your local master branch, then execute: @@ -84,4 +84,3 @@ Thank you to all the people who have already contributed to mongoose! Thank you to all our backers! [[Become a backer](https://opencollective.com/mongoose#backer)] - From 335e21c4c50dfb5c74a04fb21d91f3556b4575b5 Mon Sep 17 00:00:00 2001 From: hasezoey Date: Mon, 14 Nov 2022 13:50:11 +0100 Subject: [PATCH 080/112] docs(CONTRIBUTING): add section for documentation style guidelines re #12645 --- CONTRIBUTING.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9c7897da3b8..75c0ae02404 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,6 +59,12 @@ If you'd like to preview your documentation changes, first commit your changes t Visit `http://localhost:8089` and you should see the docs with your local changes. Make sure you `npm run docs:clean` before committing, because automated generated files to `docs/*` should **not** be in PRs. +#### Documentation Style Guidelines + +There are some guidelines to keep the style for the documentation consistent: + +- All links that refer to some other file in the mongoose documentation needs to be relative without a prefix unless required (use `guide.html` over `./guide.html` or `/docs/guide.html`) + ### Plugins website The [plugins](http://plugins.mongoosejs.io/) site is also an [open source project](https://github.com/vkarpov15/mongooseplugins) that you can get involved with. Feel free to fork and improve it as well! From afc6022385b982f0088b2376c60bc659e2a57512 Mon Sep 17 00:00:00 2001 From: hasezoey Date: Mon, 14 Nov 2022 13:50:46 +0100 Subject: [PATCH 081/112] docs(CONTRIBUTING): consistenize spacing --- CONTRIBUTING.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 75c0ae02404..c8e18067c1b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,6 +35,7 @@ If you have a question about Mongoose (not a bug report) please post it to eithe - Write typings-tests if you modify the typescript-typings. (tests are in the [test/types](https://github.com/Automattic/mongoose/tree/master/test/types) directory). ### Running the tests + - Open a terminal and navigate to the root of the project - execute `npm install` to install the necessary dependencies - execute `npm run mongo` to start a MongoDB instance on port 27017. This step is optional, if you have already a database running on port 27017. To spin up a specific mongo version, you can do it by executing `npm run mongo -- {version}`. E.g. you want to spin up a mongo 4.2.2 server, you execute `npm run mongo -- 4.2.2` @@ -69,22 +70,18 @@ There are some guidelines to keep the style for the documentation consistent: The [plugins](http://plugins.mongoosejs.io/) site is also an [open source project](https://github.com/vkarpov15/mongooseplugins) that you can get involved with. Feel free to fork and improve it as well! - ## Financial contributions We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/mongoose). Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed. - ## Credits - ### Contributors Thank you to all the people who have already contributed to mongoose! - ### Backers Thank you to all our backers! [[Become a backer](https://opencollective.com/mongoose#backer)] From 3e581f2deb70441fccc59b51ecd9aaa13d9aa93f Mon Sep 17 00:00:00 2001 From: hasezoey Date: Mon, 14 Nov 2022 14:05:13 +0100 Subject: [PATCH 082/112] docs: update remaining links to use no-prefix relative links fixes #12645 --- docs/async-await.md | 6 ++--- docs/connections.md | 8 +++--- docs/documents.md | 6 ++--- docs/faq.md | 10 +++---- docs/guide.md | 66 ++++++++++++++++++++++----------------------- docs/lodash.md | 4 +-- docs/middleware.md | 50 +++++++++++++++++----------------- docs/models.md | 20 +++++++------- docs/populate.md | 20 +++++++------- docs/queries.md | 16 +++++------ docs/schematypes.md | 44 +++++++++++++++--------------- docs/subdocs.md | 18 ++++++------- docs/validation.md | 22 +++++++-------- 13 files changed, 145 insertions(+), 145 deletions(-) diff --git a/docs/async-await.md b/docs/async-await.md index a142567c758..d554f7f8245 100644 --- a/docs/async-await.md +++ b/docs/async-await.md @@ -62,7 +62,7 @@ async function awaitUpdate() { } ``` -Note that the specific fulfillment values of different Mongoose methods vary, and may be affected by configuration. Please refer to the [API documentation](./api.html) for information about specific methods. +Note that the specific fulfillment values of different Mongoose methods vary, and may be affected by configuration. Please refer to the [API documentation](api.html) for information about specific methods. ### Async Functions @@ -108,7 +108,7 @@ Under the hood, [async/await is syntactic sugar](https://developer.mozilla.org/e Due to the surprisingly simple way promises are implemented in JavaScript, the keyword `await` will try to unwrap any object with a property whose key is the string ‘then’ and whose value is a function. Such objects belong to a broader class of objects called [thenables](https://masteringjs.io/tutorials/fundamentals/thenable). If the thenable being unwrapped is a genuine promise, e.g. an instance of the [Promise constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise), we enjoy several guarantees about how the object’s ‘then’ function will behave. -However, Mongoose provides several static helper methods that return a different class of thenable object called a [Query](./queries.html)--and [Queries are not promises](./queries.html#queries-are-not-promises). +However, Mongoose provides several static helper methods that return a different class of thenable object called a [Query](queries.html)--and [Queries are not promises](queries.html#queries-are-not-promises). Because Queries are also *thenables*, we can interact with a Query using async/await just as we would interact with a genuine promise, with one key difference: observing the fulfillment value of a genuine promise cannot under any circumstances change that value, but trying to re-observe the value of a Query may cause the Query to be re-executed. ```javascript @@ -148,4 +148,4 @@ async function observeQuery() { You are most likely to accidentally re-execute queries in this way when mixing callbacks with async/await. This is never necessary and should be avoided. - If you need a Query to return a fully-fledged promise instead of a thenable, you can use [Query#exec()](./api/query.html#query_Query-exec). \ No newline at end of file + If you need a Query to return a fully-fledged promise instead of a thenable, you can use [Query#exec()](api/query.html#query_Query-exec). diff --git a/docs/connections.md b/docs/connections.md index 38087362481..3f67e44642a 100644 --- a/docs/connections.md +++ b/docs/connections.md @@ -60,7 +60,7 @@ setTimeout(function() { }, 60000); ``` -To disable buffering, turn off the [`bufferCommands` option on your schema](./guide.html#bufferCommands). +To disable buffering, turn off the [`bufferCommands` option on your schema](guide.html#bufferCommands). If you have `bufferCommands` on and your connection is hanging, try turning `bufferCommands` off to see if you haven't opened a connection properly. You can also disable `bufferCommands` globally: @@ -178,7 +178,7 @@ See [this page](http://mongodb.github.io/node-mongodb-native/3.1/reference/faq/)

    Callback

    The `connect()` function also accepts a callback parameter and returns a -[promise](./promises.html). +[promise](promises.html). ```javascript mongoose.connect(uri, options, function(error) { @@ -379,8 +379,8 @@ The `mongoose.createConnection()` function takes the same arguments as const conn = mongoose.createConnection('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]', options); ``` -This [connection](./api.html#connection_Connection) object is then used to -create and retrieve [models](./api.html#model_Model). Models are +This [connection](api.html#connection_Connection) object is then used to +create and retrieve [models](api.html#model_Model). Models are **always** scoped to a single connection. ```javascript diff --git a/docs/documents.md b/docs/documents.md index 8459d7a1bfc..3447890a4c8 100644 --- a/docs/documents.md +++ b/docs/documents.md @@ -1,8 +1,8 @@ ## Documents -Mongoose [documents](./api/document.html) represent a one-to-one mapping +Mongoose [documents](api/document.html) represent a one-to-one mapping to documents as stored in MongoDB. Each document is an instance of its -[Model](./models.html). +[Model](models.html).
    • Documents vs Models
    • @@ -134,7 +134,7 @@ await Person.updateOne({}, { age: 'bar' }); await Person.updateOne({}, { age: -1 }, { runValidators: true }); ``` -Read the [validation](./validation.html) guide for more details. +Read the [validation](validation.html) guide for more details.

      Overwriting

      diff --git a/docs/faq.md b/docs/faq.md index e0cd2a00a29..c5ef5aa2c3c 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -119,7 +119,7 @@ console.log(new Model()); **A**. This is a performance optimization. These empty objects are not saved to the database, nor are they in the result `toObject()`, nor do they show -up in `JSON.stringify()` output unless you turn off the [`minimize` option](./guide.html#minimize). +up in `JSON.stringify()` output unless you turn off the [`minimize` option](guide.html#minimize). The reason for this behavior is that Mongoose's change detection and getters/setters are based on [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). @@ -128,11 +128,11 @@ the overhead of running `Object.defineProperty()` every time a document is creat mongoose defines properties on the `Model` prototype when the model is compiled. Because mongoose needs to define getters and setters for `nested.prop`, `nested` must always be defined as an object on a mongoose document, even if `nested` -is undefined on the underlying [POJO](./guide.html#minimize). +is undefined on the underlying [POJO](guide.html#minimize).
      -**Q**. I'm using an arrow function for a [virtual](./guide.html#virtuals), [middleware](./middleware.html), [getter](./api.html#schematype_SchemaType-get)/[setter](./api.html#schematype_SchemaType-set), or [method](./guide.html#methods) and the value of `this` is wrong. +**Q**. I'm using an arrow function for a [virtual](guide.html#virtuals), [middleware](middleware.html), [getter](api.html#schematype_SchemaType-get)/[setter](api.html#schematype_SchemaType-set), or [method](guide.html#methods) and the value of `this` is wrong. **A**. Arrow functions [handle the `this` keyword much differently than conventional functions](https://masteringjs.io/tutorials/fundamentals/arrow#why-not-arrow-functions). Mongoose getters/setters depend on `this` to give you access to the document that you're writing to, but this functionality does not work with arrow functions. Do **not** use arrow functions for mongoose getters/setters unless do not intend to access the document in the getter/setter. @@ -225,7 +225,7 @@ new Schema({ **Q**. All function calls on my models hang, what am I doing wrong? **A**. By default, mongoose will buffer your function calls until it can -connect to MongoDB. Read the [buffering section of the connection docs](./connections.html#buffering) +connect to MongoDB. Read the [buffering section of the connection docs](connections.html#buffering) for more information.
      @@ -245,7 +245,7 @@ mongoose.set('debug', { color: false }) mongoose.set('debug', { shell: true }) ``` -For more debugging options (streams, callbacks), see the ['debug' option under `.set()`](./api.html#mongoose_Mongoose-set). +For more debugging options (streams, callbacks), see the ['debug' option under `.set()`](api.html#mongoose_Mongoose-set).
      diff --git a/docs/guide.md b/docs/guide.md index b764da88544..f10b44dc5c9 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -1,6 +1,6 @@ ## Schemas -If you haven't yet done so, please take a minute to read the [quickstart](./index.html) to get an idea of how Mongoose works. +If you haven't yet done so, please take a minute to read the [quickstart](index.html) to get an idea of how Mongoose works. If you are migrating from 5.x to 6.x please take a moment to read the [migration guide](migrating_to_6.html).
        @@ -43,12 +43,12 @@ const blogSchema = new Schema({ ``` If you want to add additional keys later, use the -[Schema#add](./api.html#schema_Schema-add) method. +[Schema#add](api.html#schema_Schema-add) method. Each key in our code `blogSchema` defines a property in our documents which -will be cast to its associated [SchemaType](./api.html#schematype_SchemaType). +will be cast to its associated [SchemaType](api.html#schematype_SchemaType). For example, we've defined a property `title` which will be cast to the -[String](./api.html#schema-string-js) SchemaType and property `date` +[String](api.html#schema-string-js) SchemaType and property `date` which will be cast to a `Date` SchemaType. Notice above that if a property only requires a type, it can be specified using @@ -63,34 +63,34 @@ In these cases, Mongoose only creates actual schema paths for leaves in the tree. (like `meta.votes` and `meta.favs` above), and the branches do not have actual paths. A side-effect of this is that `meta` above cannot have its own validation. If validation is needed up the tree, a path -needs to be created up the tree - see the [Subdocuments](./subdocs.html) section -for more information on how to do this. Also read the [Mixed](./schematypes.html) +needs to be created up the tree - see the [Subdocuments](subdocs.html) section +for more information on how to do this. Also read the [Mixed](schematypes.html) subsection of the SchemaTypes guide for some gotchas. The permitted SchemaTypes are: -* [String](./schematypes.html#strings) -* [Number](./schematypes.html#numbers) -* [Date](./schematypes.html#dates) -* [Buffer](./schematypes.html#buffers) -* [Boolean](./schematypes.html#booleans) -* [Mixed](./schematypes.html#mixed) -* [ObjectId](./schematypes.html#objectids) -* [Array](./schematypes.html#arrays) -* [Decimal128](./api.html#mongoose_Mongoose-Decimal128) -* [Map](./schematypes.html#maps) +* [String](schematypes.html#strings) +* [Number](schematypes.html#numbers) +* [Date](schematypes.html#dates) +* [Buffer](schematypes.html#buffers) +* [Boolean](schematypes.html#booleans) +* [Mixed](schematypes.html#mixed) +* [ObjectId](schematypes.html#objectids) +* [Array](schematypes.html#arrays) +* [Decimal128](api.html#mongoose_Mongoose-Decimal128) +* [Map](schematypes.html#maps) -Read more about [SchemaTypes here](./schematypes.html). +Read more about [SchemaTypes here](schematypes.html). Schemas not only define the structure of your document and casting of properties, they also define document [instance methods](#methods), [static Model methods](#statics), [compound indexes](#indexes), -and document lifecycle hooks called [middleware](./middleware.html). +and document lifecycle hooks called [middleware](middleware.html).

        Creating a model

        To use our schema definition, we need to convert our `blogSchema` into a -[Model](./models.html) we can work with. +[Model](models.html) we can work with. To do so, we pass it into `mongoose.model(modelName, schema)`: ```javascript @@ -137,8 +137,8 @@ await doc.save(); // works

        Instance methods

        -Instances of `Models` are [documents](./documents.html). Documents have -many of their own [built-in instance methods](./api/document.html). +Instances of `Models` are [documents](documents.html). Documents have +many of their own [built-in instance methods](api/document.html). We may also define our own custom document instance methods. ```javascript @@ -172,8 +172,8 @@ dog.findSimilarTypes((err, dogs) => { }); ``` -* Overwriting a default mongoose document method may lead to unpredictable results. See [this](./api.html#schema_Schema-reserved) for more details. -* The example above uses the `Schema.methods` object directly to save an instance method. You can also use the `Schema.method()` helper as described [here](./api.html#schema_Schema-method). +* Overwriting a default mongoose document method may lead to unpredictable results. See [this](api.html#schema_Schema-reserved) for more details. +* The example above uses the `Schema.methods` object directly to save an instance method. You can also use the `Schema.method()` helper as described [here](api.html#schema_Schema-method). * Do **not** declare methods using ES6 arrow functions (`=>`). Arrow functions [explicitly prevent binding `this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_binding_of_this), so your method will **not** have access to the document and the above examples will not work.

        Statics

        @@ -217,7 +217,7 @@ Do **not** declare statics using ES6 arrow functions (`=>`). Arrow functions [ex You can also add query helper functions, which are like instance methods but for mongoose queries. Query helper methods let you extend mongoose's -[chainable query builder API](./queries.html). +[chainable query builder API](queries.html). ```javascript @@ -252,7 +252,7 @@ Animal.findOne().byName('fido').exec((err, animal) => {

        Indexes

        MongoDB supports [secondary indexes](http://docs.mongodb.org/manual/indexes/). -With mongoose, we define these indexes within our `Schema` [at](./api.html#schematype_SchemaType-index) [the](./api.html#schematype_SchemaType-unique) [path](./api.html#schematype_SchemaType-sparse) [level](./api.html#schemadateoptions_SchemaDateOptions-expires) or the `schema` level. +With mongoose, we define these indexes within our `Schema` [at](api.html#schematype_SchemaType-index) [the](api.html#schematype_SchemaType-unique) [path](api.html#schematype_SchemaType-sparse) [level](api.html#schemadateoptions_SchemaDateOptions-expires) or the `schema` level. Defining indexes at the schema level is necessary when creating [compound indexes](https://docs.mongodb.com/manual/core/index-compound/). @@ -266,7 +266,7 @@ const animalSchema = new Schema({ animalSchema.index({ name: 1, type: -1 }); // schema level ``` -See [SchemaType#index()](./api.html#schematype_SchemaType-index) for other index options. +See [SchemaType#index()](api.html#schematype_SchemaType-index) for other index options. When your application starts up, Mongoose automatically calls [`createIndex`](https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/#db.collection.createIndex) for each defined index in your schema. Mongoose will call `createIndex` for each index sequentially, and emit an 'index' event on the model when all the `createIndex` calls succeeded or when there was an error. @@ -300,11 +300,11 @@ Animal.on('index', error => { }); ``` -See also the [Model#ensureIndexes](./api.html#model_Model-ensureIndexes) method. +See also the [Model#ensureIndexes](api.html#model_Model-ensureIndexes) method.

        Virtuals

        -[Virtuals](./api.html#schema_Schema-virtual) are document properties that +[Virtuals](api.html#schema_Schema-virtual) are document properties that you can get and set but that do not get persisted to MongoDB. The getters are useful for formatting or combining fields, while setters are useful for de-composing a single value into multiple values for storage. @@ -337,7 +337,7 @@ But [concatenating](https://masteringjs.io/tutorials/fundamentals/string-concat) last name every time can get cumbersome. And what if you want to do some extra processing on the name, like [removing diacritics](https://www.npmjs.com/package/diacritics)? A -[virtual property getter](./api.html#virtualtype_VirtualType-get) lets you +[virtual property getter](api.html#virtualtype_VirtualType-get) lets you define a `fullName` property that won't get persisted to MongoDB. ```javascript @@ -374,7 +374,7 @@ If you use `toJSON()` or `toObject()` mongoose will *not* include virtuals by default. This includes the output of calling [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) on a Mongoose document, because [`JSON.stringify()` calls `toJSON()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Description). Pass `{ virtuals: true }` to either -[`toObject()`](./api.html#document_Document-toObject) or [`toJSON()`](./api.html#document_Document-toJSON). +[`toObject()`](api.html#document_Document-toObject) or [`toJSON()`](api.html#document_Document-toJSON). You can also add a custom setter to your virtual that will let you set both first name and last name via the `fullName` virtual. @@ -599,7 +599,7 @@ new Schema({..}, { capped: { size: 1024, max: 1000, autoIndexId: true } });

        option: collection

        Mongoose by default produces a collection name by passing the model name to -the [utils.toCollectionName](./api.html#utils_exports-toCollectionName) method. +the [utils.toCollectionName](api.html#utils_exports-toCollectionName) method. This method pluralizes the name. Set this option if you need a different name for your collection. @@ -1180,7 +1180,7 @@ thing.save(); // version is not incremented

        option: timestamps

        The `timestamps` option tells Mongoose to assign `createdAt` and `updatedAt` fields -to your schema. The type assigned is [Date](./api.html#schema-date-js). +to your schema. The type assigned is [Date](api.html#schema-date-js). By default, the names of the fields are `createdAt` and `updatedAt`. Customize the field names by setting `timestamps.createdAt` and `timestamps.updatedAt`. @@ -1376,7 +1376,7 @@ console.log(schema.virtuals); // { myVirtual: VirtualType { ... } }

        Pluggable

        -Schemas are also [pluggable](./plugins.html) which allows us to package up reusable features into +Schemas are also [pluggable](plugins.html) which allows us to package up reusable features into plugins that can be shared with the community or just between your projects.

        Further Reading

        diff --git a/docs/lodash.md b/docs/lodash.md index 9dad5b4ee51..3e7837920e3 100644 --- a/docs/lodash.md +++ b/docs/lodash.md @@ -8,7 +8,7 @@ However, there are a few caveats that you should know about. ## `cloneDeep()` You should not use [Lodash's `cloneDeep()` function](https://lodash.com/docs/4.17.15#cloneDeep) on any Mongoose objects. -This includes [connections](./connections.html), [model classes](./models.html), and [queries](./queries.html), but is _especially_ important for [documents](./documents.html). +This includes [connections](connections.html), [model classes](models.html), and [queries](queries.html), but is _especially_ important for [documents](documents.html). For example, you may be tempted to do the following: ```javascript @@ -36,4 +36,4 @@ const doc = await MyModel.findOne(); const newDoc = new MyModel().init(doc.toObject()); newDoc.myProperty = 'test'; await newDoc.save(); -``` \ No newline at end of file +``` diff --git a/docs/middleware.md b/docs/middleware.md index f8e713a5384..d6c016108a7 100644 --- a/docs/middleware.md +++ b/docs/middleware.md @@ -2,7 +2,7 @@ Middleware (also called pre and post *hooks*) are functions which are passed control during execution of asynchronous functions. Middleware is specified -on the schema level and is useful for writing [plugins](./plugins.html). +on the schema level and is useful for writing [plugins](plugins.html).
        • Types of Middleware
        • @@ -39,42 +39,42 @@ Query middleware is supported for the following Query functions. Query middleware executes when you call `exec()` or `then()` on a Query object, or `await` on a Query object. In query middleware functions, `this` refers to the query. -* [count](./api.html#query_Query-count) -* [countDocuments](./api/query.html#query_Query-countDocuments) -* [deleteMany](./api.html#query_Query-deleteMany) -* [deleteOne](./api.html#query_Query-deleteOne) -* [estimatedDocumentCount](./api/query.html#query_Query-estimatedDocumentCount) -* [find](./api.html#query_Query-find) -* [findOne](./api.html#query_Query-findOne) -* [findOneAndDelete](./api.html#query_Query-findOneAndDelete) -* [findOneAndRemove](./api.html#query_Query-findOneAndRemove) -* [findOneAndReplace](./api/query.html#query_Query-findOneAndReplace) -* [findOneAndUpdate](./api.html#query_Query-findOneAndUpdate) -* [remove](./api.html#model_Model-remove) -* [replaceOne](./api/query.html#query_Query-replaceOne) -* [update](./api.html#query_Query-update) -* [updateOne](./api.html#query_Query-updateOne) -* [updateMany](./api.html#query_Query-updateMany) +* [count](api.html#query_Query-count) +* [countDocuments](api/query.html#query_Query-countDocuments) +* [deleteMany](api.html#query_Query-deleteMany) +* [deleteOne](api.html#query_Query-deleteOne) +* [estimatedDocumentCount](api/query.html#query_Query-estimatedDocumentCount) +* [find](api.html#query_Query-find) +* [findOne](api.html#query_Query-findOne) +* [findOneAndDelete](api.html#query_Query-findOneAndDelete) +* [findOneAndRemove](api.html#query_Query-findOneAndRemove) +* [findOneAndReplace](api/query.html#query_Query-findOneAndReplace) +* [findOneAndUpdate](api.html#query_Query-findOneAndUpdate) +* [remove](api.html#model_Model-remove) +* [replaceOne](api/query.html#query_Query-replaceOne) +* [update](api.html#query_Query-update) +* [updateOne](api.html#query_Query-updateOne) +* [updateMany](api.html#query_Query-updateMany) Aggregate middleware is for `MyModel.aggregate()`. Aggregate middleware executes when you call `exec()` on an aggregate object. -In aggregate middleware, `this` refers to the [aggregation object](./api.html#model_Model-aggregate). +In aggregate middleware, `this` refers to the [aggregation object](api.html#model_Model-aggregate). -* [aggregate](./api.html#model_Model-aggregate) +* [aggregate](api.html#model_Model-aggregate) Model middleware is supported for the following model functions. Don't confuse model middleware and document middleware: model middleware hooks into _static_ functions on a `Model` class, document middleware hooks into _methods_ on a `Model` class. In model middleware functions, `this` refers to the model. -* [insertMany](./api.html#model_Model-insertMany) +* [insertMany](api.html#model_Model-insertMany) All middleware types support pre and post hooks. How pre and post hooks work is described in more detail below. **Note:** If you specify `schema.pre('remove')`, Mongoose will register this -middleware for [`doc.remove()`](./api.html#model_Model-remove) by default. If you -want your middleware to run on [`Query.remove()`](./api.html#query_Query-remove) -use [`schema.pre('remove', { query: true, document: false }, fn)`](./api.html#schema_Schema-pre). +middleware for [`doc.remove()`](api.html#model_Model-remove) by default. If you +want your middleware to run on [`Query.remove()`](api.html#query_Query-remove) +use [`schema.pre('remove', { query: true, document: false }, fn)`](api.html#schema_Schema-pre). **Note:** Unlike `schema.pre('remove')`, Mongoose registers `updateOne` and `deleteOne` middleware on `Query#updateOne()` and `Query#deleteOne()` by default. @@ -83,7 +83,7 @@ This means that both `doc.updateOne()` and `Model.updateOne()` trigger `updateOne` or `deleteOne` middleware as document middleware, use `schema.pre('updateOne', { document: true, query: false })`. -**Note:** The [`create()`](./api.html#model_Model-create) function fires `save()` hooks. +**Note:** The [`create()`](api.html#model_Model-create) function fires `save()` hooks.

          Pre

          @@ -492,7 +492,7 @@ pipeline from middleware. Certain Mongoose hooks are synchronous, which means they do **not** support functions that return promises or receive a `next()` callback. Currently, -only `init` hooks are synchronous, because the [`init()` function](./api.html#document_Document-init) +only `init` hooks are synchronous, because the [`init()` function](api.html#document_Document-init) is synchronous. Below is an example of using pre and post init hooks. ```javascript diff --git a/docs/models.md b/docs/models.md index 5d405ee6089..0837e416a52 100644 --- a/docs/models.md +++ b/docs/models.md @@ -1,8 +1,8 @@ # Models -[Models](./api.html#model-js) are fancy constructors compiled from +[Models](api.html#model-js) are fancy constructors compiled from `Schema` definitions. An instance of a model is called a -[document](./documents.html). Models are responsible for creating and +[document](documents.html). Models are responsible for creating and reading documents from the underlying MongoDB database. * [Compiling your first model](#compiling) @@ -34,7 +34,7 @@ before calling `.model()`! ## Constructing Documents -An instance of a model is called a [document](./documents.html). Creating +An instance of a model is called a [document](documents.html). Creating them and saving to the database is easy. ```javascript @@ -76,13 +76,13 @@ const Tank = connection.model('Tank', yourSchema); ## Querying -Finding documents is easy with Mongoose, which supports the [rich](http://www.mongodb.org/display/DOCS/Advanced+Queries) query syntax of MongoDB. Documents can be retrieved using a `model`'s [find](./api.html#model_Model-find), [findById](./api.html#model_Model-findById), [findOne](./api.html#model_Model-findOne), or [where](./api.html#model_Model-where) static methods. +Finding documents is easy with Mongoose, which supports the [rich](http://www.mongodb.org/display/DOCS/Advanced+Queries) query syntax of MongoDB. Documents can be retrieved using a `model`'s [find](api.html#model_Model-find), [findById](api.html#model_Model-findById), [findOne](api.html#model_Model-findOne), or [where](api.html#model_Model-where) static methods. ```javascript Tank.find({ size: 'small' }).where('createdDate').gt(oneYearAgo).exec(callback); ``` -See the chapter on [queries](./queries.html) for more details on how to use the [Query](./api.html#query-js) api. +See the chapter on [queries](queries.html) for more details on how to use the [Query](api.html#query-js) api. ## Deleting @@ -100,7 +100,7 @@ Tank.deleteOne({ size: 'large' }, function (err) { Each `model` has its own `update` method for modifying documents in the database without returning them to your application. See the -[API](./api.html#model_Model-updateOne) docs for more detail. +[API](api.html#model_Model-updateOne) docs for more detail. ```javascript Tank.updateOne({ size: 'large' }, { name: 'T-90' }, function(err, res) { @@ -110,7 +110,7 @@ Tank.updateOne({ size: 'large' }, { name: 'T-90' }, function(err, res) { ``` _If you want to update a single document in the db and return it to your -application, use [findOneAndUpdate](./api.html#model_Model-findOneAndUpdate) +application, use [findOneAndUpdate](api.html#model_Model-findOneAndUpdate) instead._ ## Change Streams @@ -155,9 +155,9 @@ You can read more about [change streams in mongoose in this blog post](http://th ## Views -[MongoDB Views](https://www.mongodb.com/docs/manual/core/views) are essentially read-only collections that contain data computed from other collections using [aggregations](./api/aggregate.html). +[MongoDB Views](https://www.mongodb.com/docs/manual/core/views) are essentially read-only collections that contain data computed from other collections using [aggregations](api/aggregate.html). In Mongoose, you should define a separate Model for each of your Views. -You can also create a View using [`createCollection()`](./api/model.html#model_Model-createCollection). +You can also create a View using [`createCollection()`](api/model.html#model_Model-createCollection). The following example shows how you can create a new `RedactedUser` View on a `User` Model that hides potentially sensitive information, like name and email. @@ -203,7 +203,7 @@ If you attempt to `save()` a document from a View, you will get an error from th ## Yet more -The [API docs](./api.html#model_Model) cover many additional methods available like [count](./api.html#model_Model-count), [mapReduce](./api.html#model_Model-mapReduce), [aggregate](./api.html#model_Model-aggregate), and [more](./api.html#model_Model-findOneAndRemove). +The [API docs](api.html#model_Model) cover many additional methods available like [count](api.html#model_Model-count), [mapReduce](api.html#model_Model-mapReduce), [aggregate](api.html#model_Model-aggregate), and [more](api.html#model_Model-findOneAndRemove). ## Next Up diff --git a/docs/populate.md b/docs/populate.md index 0ed241f4492..606e8e00aa1 100644 --- a/docs/populate.md +++ b/docs/populate.md @@ -25,7 +25,7 @@ const Story = mongoose.model('Story', storySchema); const Person = mongoose.model('Person', personSchema); ``` -So far we've created two [Models](./models.html). Our `Person` model has +So far we've created two [Models](models.html). Our `Person` model has its `stories` field set to an array of `ObjectId`s. The `ref` option is what tells Mongoose which model to use during population, in our case the `Story` model. All `_id`s we store here must be document `_id`s from @@ -108,7 +108,7 @@ is replaced with the mongoose document returned from the database by performing a separate query before returning the results. Arrays of refs work the same way. Just call the -[populate](./api.html#query_Query-populate) method on the query and an +[populate](api.html#query_Query-populate) method on the query and an array of documents will be returned _in place_ of the original `_id`s.

          Setting Populated Fields

          @@ -187,7 +187,7 @@ story.authors; // `[]` What if we only want a few specific fields returned for the populated documents? This can be accomplished by passing the usual -[field name syntax](./api.html#query_Query-select) as the second argument +[field name syntax](api.html#query_Query-select) as the second argument to the populate method: ```javascript @@ -372,10 +372,10 @@ Story. ``` The documents returned from -[query population](./api.html#query_Query-populate) become fully +[query population](api.html#query_Query-populate) become fully functional, `remove`able, `save`able documents unless the -[lean](./api.html#query_Query-lean) option is specified. Do not confuse -them with [sub docs](./subdocs.html). Take caution when calling its +[lean](api.html#query_Query-lean) option is specified. Do not confuse +them with [sub docs](subdocs.html). Take caution when calling its remove method because you'll be removing it from the database, not just the array. @@ -383,7 +383,7 @@ the array. If you have an existing mongoose document and want to populate some of its paths, you can use the -[Document#populate()](./api.html#document_Document-populate) method. +[Document#populate()](api.html#document_Document-populate) method. ```javascript const person = await Person.findOne({ name: 'Ian Fleming' }); @@ -408,8 +408,8 @@ person.populated('fans'); // Array of ObjectIds

          Populating multiple existing documents

          If we have one or many mongoose documents or even plain objects -(_like [mapReduce](./api.html#model_Model-mapReduce) output_), we may -populate them using the [Model.populate()](./api.html#model_Model-populate) +(_like [mapReduce](api.html#model_Model-mapReduce) output_), we may +populate them using the [Model.populate()](api.html#model_Model-populate) method. This is what `Document#populate()` and `Query#populate()` use to populate documents. @@ -970,4 +970,4 @@ const recipes = await Recipe.find().populate({ // Gets the ingredient's name in Spanish `name.es` recipes[0].ingredients[0].name; // 'Huevos' -``` \ No newline at end of file +``` diff --git a/docs/queries.md b/docs/queries.md index 6e6643766f9..7c7a4d89f53 100644 --- a/docs/queries.md +++ b/docs/queries.md @@ -1,6 +1,6 @@ ## Queries -Mongoose [models](./models.html) provide several static helper functions +Mongoose [models](models.html) provide several static helper functions for [CRUD operations](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete). Each of these functions returns a [mongoose `Query` object](api.html#Query). @@ -55,7 +55,7 @@ Mongoose executed the query and passed the results to `callback`. All callbacks `callback(error, result)`. If an error occurs executing the query, the `error` parameter will contain an error document, and `result` will be null. If the query is successful, the `error` parameter will be null, and the `result` will be populated with the results of the query. -Anywhere a callback is passed to a query in Mongoose, the callback follows the pattern `callback(error, results)`. What `results` is depends on the operation: For `findOne()` it is a [potentially-null single document](./api.html#model_Model-findOne), `find()` a [list of documents](./api.html#model_Model-find), `count()` [the number of documents](./api.html#model_Model-count), `update()` the [number of documents affected](./api.html#model_Model-update), etc. The [API docs for Models](./api.html#model-js) provide more detail on what is passed to the callbacks. +Anywhere a callback is passed to a query in Mongoose, the callback follows the pattern `callback(error, results)`. What `results` is depends on the operation: For `findOne()` it is a [potentially-null single document](api.html#model_Model-findOne), `find()` a [list of documents](api.html#model_Model-find), `count()` [the number of documents](api.html#model_Model-count), `update()` the [number of documents affected](api.html#model_Model-update), etc. The [API docs for Models](api.html#model-js) provide more detail on what is passed to the callbacks. Now let's look at what happens when no `callback` is passed: @@ -75,7 +75,7 @@ query.exec(function (err, person) { }); ``` -In the above code, the `query` variable is of type [Query](./api.html#query-js). +In the above code, the `query` variable is of type [Query](api.html#query-js). A `Query` enables you to build up a query using chaining syntax, rather than specifying a JSON object. The below 2 examples are equivalent. @@ -105,7 +105,7 @@ Person. exec(callback); ``` -A full list of [Query helper functions can be found in the API docs](./api.html#query-js). +A full list of [Query helper functions can be found in the API docs](api.html#query-js).

          @@ -156,16 +156,16 @@ await BlogPost.updateOne({ title: 'Introduction to Promises' }, update, (err, re

          References to other documents

          There are no joins in MongoDB but sometimes we still want references to -documents in other collections. This is where [population](./populate.html) +documents in other collections. This is where [population](populate.html) comes in. Read more about how to include documents from other collections in -your query results [here](./api.html#query_Query-populate). +your query results [here](api.html#query_Query-populate).

          Streaming

          You can [stream](http://nodejs.org/api/stream.html) query results from MongoDB. You need to call the -[Query#cursor()](./api.html#query_Query-cursor) function to return an instance of -[QueryCursor](./api.html#query_Query-cursor). +[Query#cursor()](api.html#query_Query-cursor) function to return an instance of +[QueryCursor](api.html#query_Query-cursor). ```javascript const cursor = Person.find({ occupation: /host/ }).cursor(); diff --git a/docs/schematypes.md b/docs/schematypes.md index 3448e32d9f2..68465e2dc31 100644 --- a/docs/schematypes.md +++ b/docs/schematypes.md @@ -1,12 +1,12 @@

          SchemaTypes

          SchemaTypes handle definition of path -[defaults](./api.html#schematype_SchemaType-default), -[validation](./api.html#schematype_SchemaType-validate), +[defaults](api.html#schematype_SchemaType-default), +[validation](api.html#schematype_SchemaType-validate), [getters](#getters), -[setters](./api.html#schematype_SchemaType-set), -[field selection defaults](./api.html#schematype_SchemaType-select) for -[queries](./api.html#query-js), +[setters](api.html#schematype_SchemaType-set), +[field selection defaults](api.html#schematype_SchemaType-select) for +[queries](api.html#query-js), and other general characteristics for Mongoose document properties. * [What is a SchemaType?](#what-is-a-schematype) @@ -50,7 +50,7 @@ Check out [Mongoose's plugins search](http://plugins.mongoosejs.io) to find plug - [Mixed](#mixed) - [ObjectId](#objectids) - [Array](#arrays) -- [Decimal128](./api.html#mongoose_Mongoose-Decimal128) +- [Decimal128](api.html#mongoose_Mongoose-Decimal128) - [Map](#maps) - [Schema](#schemas) @@ -201,13 +201,13 @@ types.
          All Schema Types
          -* `required`: boolean or function, if true adds a [required validator](./validation.html#built-in-validators) for this property +* `required`: boolean or function, if true adds a [required validator](validation.html#built-in-validators) for this property * `default`: Any or function, sets a default value for the path. If the value is a function, the return value of the function is used as the default. * `select`: boolean, specifies default [projections](https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/) for queries -* `validate`: function, adds a [validator function](./validation.html#built-in-validators) for this property +* `validate`: function, adds a [validator function](validation.html#built-in-validators) for this property * `get`: function, defines a custom getter for this property using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). * `set`: function, defines a custom setter for this property using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). -* `alias`: string, mongoose >= 4.10.0 only. Defines a [virtual](./guide.html#virtuals) with the given name that gets/sets this path. +* `alias`: string, mongoose >= 4.10.0 only. Defines a [virtual](guide.html#virtuals) with the given name that gets/sets this path. * `immutable`: boolean, defines path as immutable. Mongoose prevents you from changing immutable paths unless the parent document has `isNew: true`. * `transform`: function, Mongoose calls this function when you call [`Document#toJSON()`](api/document.html#document_Document-toJSON) function, including when you [`JSON.stringify()`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript) a document. @@ -257,23 +257,23 @@ const schema2 = new Schema({ * `lowercase`: boolean, whether to always call `.toLowerCase()` on the value * `uppercase`: boolean, whether to always call `.toUpperCase()` on the value * `trim`: boolean, whether to always call [`.trim()`](https://masteringjs.io/tutorials/fundamentals/trim-string) on the value -* `match`: RegExp, creates a [validator](./validation.html) that checks if the value matches the given regular expression -* `enum`: Array, creates a [validator](./validation.html) that checks if the value is in the given array. -* `minLength`: Number, creates a [validator](./validation.html) that checks if the value length is not less than the given number -* `maxLength`: Number, creates a [validator](./validation.html) that checks if the value length is not greater than the given number +* `match`: RegExp, creates a [validator](validation.html) that checks if the value matches the given regular expression +* `enum`: Array, creates a [validator](validation.html) that checks if the value is in the given array. +* `minLength`: Number, creates a [validator](validation.html) that checks if the value length is not less than the given number +* `maxLength`: Number, creates a [validator](validation.html) that checks if the value length is not greater than the given number * `populate`: Object, sets default [populate options](populate.html#query-conditions)
          Number
          -* `min`: Number, creates a [validator](./validation.html) that checks if the value is greater than or equal to the given minimum. -* `max`: Number, creates a [validator](./validation.html) that checks if the value is less than or equal to the given maximum. -* `enum`: Array, creates a [validator](./validation.html) that checks if the value is strictly equal to one of the values in the given array. +* `min`: Number, creates a [validator](validation.html) that checks if the value is greater than or equal to the given minimum. +* `max`: Number, creates a [validator](validation.html) that checks if the value is less than or equal to the given maximum. +* `enum`: Array, creates a [validator](validation.html) that checks if the value is strictly equal to one of the values in the given array. * `populate`: Object, sets default [populate options](populate.html#query-conditions)
          Date
          -* `min`: Date, creates a [validator](./validation.html) that checks if the value is greater than or equal to the given minimum. -* `max`: Date, creates a [validator](./validation.html) that checks if the value is less than or equal to the given maximum. +* `min`: Date, creates a [validator](validation.html) that checks if the value is greater than or equal to the given minimum. +* `max`: Date, creates a [validator](validation.html) that checks if the value is less than or equal to the given maximum. * `expires`: Number or String, creates a TTL index with the value expressed in seconds.
          ObjectId
          @@ -388,7 +388,7 @@ like, but Mongoose loses the ability to auto detect and save those changes. To tell Mongoose that the value of a Mixed type has changed, you need to call `doc.markModified(path)`, passing the path to the Mixed type you just changed. -To avoid these side-effects, a [Subdocument](./subdocs.html) path may be used +To avoid these side-effects, a [Subdocument](subdocs.html) path may be used instead. ```javascript @@ -460,8 +460,8 @@ console.log(new M({ b: 'nay' }).b); // false

          Arrays

          -Mongoose supports arrays of [SchemaTypes](./api.html#schema_Schema-Types) -and arrays of [subdocuments](./subdocs.html). Arrays of SchemaTypes are +Mongoose supports arrays of [SchemaTypes](api.html#schema_Schema-Types) +and arrays of [subdocuments](subdocs.html). Arrays of SchemaTypes are also called _primitive arrays_, and arrays of subdocuments are also called _document arrays_. @@ -656,7 +656,7 @@ schema.path('arr.0.url').get(v => `${root}${v}`);

          Schemas

          -To declare a path as another [schema](./guide.html#definition), +To declare a path as another [schema](guide.html#definition), set `type` to the sub-schema's instance. To set a default value based on the sub-schema's shape, simply set a default value, diff --git a/docs/subdocs.md b/docs/subdocs.md index 7068e9c14da..618dd72ee47 100644 --- a/docs/subdocs.md +++ b/docs/subdocs.md @@ -51,7 +51,7 @@ doc.child; ### What is a Subdocument? Subdocuments are similar to normal documents. Nested schemas can have -[middleware](./middleware.html), [custom validation logic](./validation.html), +[middleware](middleware.html), [custom validation logic](validation.html), virtuals, and any other feature top-level schemas can use. The major difference is that subdocuments are not saved individually, they are saved whenever their top-level parent @@ -68,7 +68,7 @@ parent.children[0].name = 'Matthew'; parent.save(callback); ``` -Subdocuments have `save` and `validate` [middleware](./middleware.html) +Subdocuments have `save` and `validate` [middleware](middleware.html) just like top-level documents. Calling `save()` on the parent document triggers the `save()` middleware for all its subdocuments, and the same for `validate()` middleware. @@ -223,7 +223,7 @@ doc.child; // { age: 0 } ### Finding a Subdocument Each subdocument has an `_id` by default. Mongoose document arrays have a -special [id](./api.html#types_documentarray_MongooseDocumentArray-id) method +special [id](api.html#types_documentarray_MongooseDocumentArray-id) method for searching a document array to find a document with a given `_id`. ```javascript @@ -233,9 +233,9 @@ const doc = parent.children.id(_id); ### Adding Subdocs to Arrays MongooseArray methods such as -[push](./api.html#mongoosearray_MongooseArray-push), -[unshift](./api.html#mongoosearray_MongooseArray-unshift), -[addToSet](./api.html#mongoosearray_MongooseArray-addToSet), +[push](api.html#mongoosearray_MongooseArray-push), +[unshift](api.html#mongoosearray_MongooseArray-unshift), +[addToSet](api.html#mongoosearray_MongooseArray-addToSet), and others cast arguments to their proper types transparently: ```javascript const Parent = mongoose.model('Parent'); @@ -253,7 +253,7 @@ parent.save(function (err) { }); ``` -You can also create a subdocument without adding it to an array by using the [`create()` method](./api/mongoosedocumentarray.html#mongoosedocumentarray_MongooseDocumentArray-create) of Document Arrays. +You can also create a subdocument without adding it to an array by using the [`create()` method](api/mongoosedocumentarray.html#mongoosedocumentarray_MongooseDocumentArray-create) of Document Arrays. ```javascript const newdoc = parent.children.create({ name: 'Aaron' }); @@ -262,7 +262,7 @@ const newdoc = parent.children.create({ name: 'Aaron' }); ### Removing Subdocs Each subdocument has its own -[remove](./api.html#types_embedded_EmbeddedDocument-remove) method. For +[remove](api.html#types_embedded_EmbeddedDocument-remove) method. For an array subdocument, this is equivalent to calling `.pull()` on the subdocument. For a single nested subdocument, `remove()` is equivalent to setting the subdocument to `null`. @@ -337,4 +337,4 @@ const parentSchema = new Schema({ ### Next Up Now that we've covered Subdocuments, let's take a look at -[querying](./queries.html). +[querying](queries.html). diff --git a/docs/validation.md b/docs/validation.md index baa1c3b3724..bae72dc0c14 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -2,13 +2,13 @@ Before we get into the specifics of validation syntax, please keep the following rules in mind: -- Validation is defined in the [SchemaType](./schematypes.html) -- Validation is [middleware](./middleware.html). Mongoose registers validation as a `pre('save')` hook on every schema by default. -- You can disable automatic validation before save by setting the [validateBeforeSave](./guide.html#validateBeforeSave) option +- Validation is defined in the [SchemaType](schematypes.html) +- Validation is [middleware](middleware.html). Mongoose registers validation as a `pre('save')` hook on every schema by default. +- You can disable automatic validation before save by setting the [validateBeforeSave](guide.html#validateBeforeSave) option - You can manually run validation using `doc.validate(callback)` or `doc.validateSync()` -- You can manually mark a field as invalid (causing validation to fail) by using [`doc.invalidate(...)`](./api.html#document_Document-invalidate) -- Validators are not run on undefined values. The only exception is the [`required` validator](./api.html#schematype_SchemaType-required). -- Validation is asynchronously recursive; when you call [Model#save](./api.html#model_Model-save), sub-document validation is executed as well. If an error occurs, your [Model#save](./api.html#model_Model-save) callback receives it +- You can manually mark a field as invalid (causing validation to fail) by using [`doc.invalidate(...)`](api.html#document_Document-invalidate) +- Validators are not run on undefined values. The only exception is the [`required` validator](api.html#schematype_SchemaType-required). +- Validation is asynchronously recursive; when you call [Model#save](api.html#model_Model-save), sub-document validation is executed as well. If an error occurs, your [Model#save](api.html#model_Model-save) callback receives it - Validation is customizable ```javascript @@ -33,9 +33,9 @@ Before we get into the specifics of validation syntax, please keep the following Mongoose has several built-in validators. -- All [SchemaTypes](./schematypes.html) have the built-in [required](./api.html#schematype_SchemaType-required) validator. The required validator uses the [SchemaType's `checkRequired()` function](./api.html#schematype_SchemaType-checkRequired) to determine if the value satisfies the required validator. -- [Numbers](./api.html#schema-number-js) have [`min` and `max`](./schematypes.html#number-validators) validators. -- [Strings](./api.html#schema-string-js) have [`enum`, `match`, `minLength`, and `maxLength`](./schematypes.html#string-validators) validators. +- All [SchemaTypes](schematypes.html) have the built-in [required](api.html#schematype_SchemaType-required) validator. The required validator uses the [SchemaType's `checkRequired()` function](api.html#schematype_SchemaType-checkRequired) to determine if the value satisfies the required validator. +- [Numbers](api.html#schema-number-js) have [`min` and `max`](schematypes.html#number-validators) validators. +- [Strings](api.html#schema-string-js) have [`enum`, `match`, `minLength`, and `maxLength`](schematypes.html#string-validators) validators. Each of the validator links above provide more information about how to enable them and customize their error messages. @@ -75,7 +75,7 @@ to suit your needs. Custom validation is declared by passing a validation function. You can find detailed instructions on how to do this in the -[`SchemaType#validate()` API docs](./api.html#schematype_SchemaType-validate). +[`SchemaType#validate()` API docs](api.html#schematype_SchemaType-validate). ```javascript [require:Custom Validators] @@ -96,7 +96,7 @@ the value `false`, Mongoose will consider that a validation error. Errors returned after failed validation contain an `errors` object whose values are `ValidatorError` objects. Each -[ValidatorError](./api.html#error-validation-js) has `kind`, `path`, +[ValidatorError](api.html#error-validation-js) has `kind`, `path`, `value`, and `message` properties. A ValidatorError also may have a `reason` property. If an error was thrown in the validator, this property will contain the error that was From 7a0a0eca77d18267831ae154ff8c2aacc0ce6f60 Mon Sep 17 00:00:00 2001 From: hasezoey Date: Mon, 14 Nov 2022 14:09:20 +0100 Subject: [PATCH 083/112] docs: fix remaining static links fixes #12645 re #12623 --- docs/jest.md | 4 ++-- docs/promises.md | 4 ++-- docs/tutorials/custom-casting.md | 4 ++-- docs/tutorials/getters-setters.md | 4 ++-- docs/tutorials/query_casting.md | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/jest.md b/docs/jest.md index 36e07845d45..108ca6efcd0 100644 --- a/docs/jest.md +++ b/docs/jest.md @@ -8,7 +8,7 @@ If you choose to delve into dangerous waters and test Mongoose apps with Jest, h -If you are using Jest `<=26`, do **not** use Jest's default [`jsdom` test environment](https://jestjs.io/docs/en/configuration.html#testenvironment-string) when testing Mongoose apps, _unless_ you are explicitly testing an application that only uses [Mongoose's browser library](https://mongoosejs.com/docs/browser.html). In Jest `>=27`, ["node" is Jest's default `testEnvironment`](https://jestjs.io/ro/blog/2021/05/25/jest-27#flipping-defaults), so this is no longer an issue. +If you are using Jest `<=26`, do **not** use Jest's default [`jsdom` test environment](https://jestjs.io/docs/en/configuration.html#testenvironment-string) when testing Mongoose apps, _unless_ you are explicitly testing an application that only uses [Mongoose's browser library](browser.html). In Jest `>=27`, ["node" is Jest's default `testEnvironment`](https://jestjs.io/ro/blog/2021/05/25/jest-27#flipping-defaults), so this is no longer an issue. The `jsdom` test environment attempts to create a browser-like test environment in Node.js, and it comes with numerous nasty surprises like a @@ -81,4 +81,4 @@ course on Pluralsight has a great section on testing Mongoose apps with [Mocha]( - \ No newline at end of file + diff --git a/docs/promises.md b/docs/promises.md index 562626890a3..cc86b1e602f 100644 --- a/docs/promises.md +++ b/docs/promises.md @@ -7,7 +7,7 @@ This means that you can do things like `MyModel.findOne({}).then()` and `await MyModel.findOne({}).exec()` if you're using [async/await](http://thecodebarbarian.com/80-20-guide-to-async-await-in-node.js.html). -You can find the return type of specific operations [in the api docs](https://mongoosejs.com/docs/api.html) +You can find the return type of specific operations [in the api docs](api.html) You can also read more about [promises in Mongoose](https://masteringjs.io/tutorials/mongoose/promise). ```javascript @@ -72,4 +72,4 @@ ES6-style promise constructor and mongoose will use it.

          - \ No newline at end of file + diff --git a/docs/tutorials/custom-casting.md b/docs/tutorials/custom-casting.md index 58fa9f64031..97ee4af97e4 100644 --- a/docs/tutorials/custom-casting.md +++ b/docs/tutorials/custom-casting.md @@ -1,6 +1,6 @@ # Custom Casting -[Mongoose 5.4.0](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md#540--2018-12-14) introduced [several ways to configure SchemaTypes globally](http://thecodebarbarian.com/whats-new-in-mongoose-54-global-schematype-configuration). One of these new features is the [`SchemaType.cast()` function](https://mongoosejs.com/docs/api.html#schematype_SchemaType-cast), which enables you to override Mongoose's built-in casting. +[Mongoose 5.4.0](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md#540--2018-12-14) introduced [several ways to configure SchemaTypes globally](http://thecodebarbarian.com/whats-new-in-mongoose-54-global-schematype-configuration). One of these new features is the [`SchemaType.cast()` function](../api.html#schematype_SchemaType-cast), which enables you to override Mongoose's built-in casting. For example, by default Mongoose will throw an error if you attempt to cast a string that contains a Japanese numeral to a number. @@ -14,4 +14,4 @@ the string that contains the Japanese numeral "2" to a number as shown below. ```javascript [require:custom casting.*casting override] -``` \ No newline at end of file +``` diff --git a/docs/tutorials/getters-setters.md b/docs/tutorials/getters-setters.md index 4b237622960..dc94fb6a41b 100644 --- a/docs/tutorials/getters-setters.md +++ b/docs/tutorials/getters-setters.md @@ -26,7 +26,7 @@ app.get(function(req, res) { }); ``` -To disable running getters when converting a document to JSON, set the [`toJSON.getters` option to `false` in your schema](https://mongoosejs.com/docs/guide.html#toJSON) as shown below. +To disable running getters when converting a document to JSON, set the [`toJSON.getters` option to `false` in your schema](../guide.html#toJSON) as shown below. ```javascript const userSchema = new Schema({ @@ -80,4 +80,4 @@ corresponding getter for `email`. ```javascript [require:getters/setters.*setters.*vs ES6] -``` \ No newline at end of file +``` diff --git a/docs/tutorials/query_casting.md b/docs/tutorials/query_casting.md index 9e740f2c906..1824850a1f7 100644 --- a/docs/tutorials/query_casting.md +++ b/docs/tutorials/query_casting.md @@ -1,12 +1,12 @@ # Query Casting -The first parameter to [`Model.find()`](https://mongoosejs.com/docs/api.html#model_Model-find), [`Query#find()`](https://mongoosejs.com/docs/api.html#query_Query-find), [`Model.findOne()`](https://mongoosejs.com/docs/api.html#model_Model-findOne), etc. is called `filter`. In older content this parameter is sometimes called `query` or `conditions`. For example: +The first parameter to [`Model.find()`](../api.html#model_Model-find), [`Query#find()`](../api.html#query_Query-find), [`Model.findOne()`](../api.html#model_Model-findOne), etc. is called `filter`. In older content this parameter is sometimes called `query` or `conditions`. For example: ```javascript [require:Cast Tutorial.*get and set] ``` -When you execute the query using [`Query#exec()`](https://mongoosejs.com/docs/api.html#query_Query-exec) or [`Query#then()`](https://mongoosejs.com/docs/api.html#query_Query-then), Mongoose _casts_ the filter to match your schema. +When you execute the query using [`Query#exec()`](../api.html#query_Query-exec) or [`Query#then()`](../api.html#query_Query-then), Mongoose _casts_ the filter to match your schema. ```javascript [require:Cast Tutorial.*cast values] @@ -27,7 +27,7 @@ By default, Mongoose does **not** cast filter properties that aren't in your sch [require:Cast Tutorial.*not in schema] ``` -You can configure this behavior using the [`strictQuery` option for schemas](https://mongoosejs.com/docs/guide.html#strictQuery). This option is analogous to the [`strict` option](https://mongoosejs.com/docs/guide.html#strict). Setting `strictQuery` to `true` removes non-schema properties from the filter: +You can configure this behavior using the [`strictQuery` option for schemas](../guide.html#strictQuery). This option is analogous to the [`strict` option](../guide.html#strict). Setting `strictQuery` to `true` removes non-schema properties from the filter: ```javascript [require:Cast Tutorial.*strictQuery true] From 4f3c5656b53036c62737ec58f5e760733b92fac2 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 19 Nov 2022 10:50:05 +0100 Subject: [PATCH 084/112] docs(mongoose): removed duplicated line --- lib/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index f395aded5a6..bf2777f8cad 100644 --- a/lib/index.js +++ b/lib/index.js @@ -205,7 +205,6 @@ Mongoose.prototype.setDriver = function setDriver(driver) { * - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information. * - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models * - 'cloneSchemas': `false` by default. Set to `true` to `clone()` all schemas before compiling into a model. - * - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arugments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`. * - 'timestamps.createdAt.immutable': `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-immutable) which means you can update the `createdAt` * - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query * - 'objectIdGetter': `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter. From b8f24f3d0987f4b773d4d04a93915c16c10e1143 Mon Sep 17 00:00:00 2001 From: sgpinkus Date: Sun, 20 Nov 2022 08:22:39 +1100 Subject: [PATCH 085/112] Replace used before defined User with this. Changed line gave "'User' was used before it was defined" linting error. Will compile if you ignore the lint error but I think it's more informative to show that `this` can be used - as it is an instance of `UserModel` here. --- docs/typescript/statics-and-methods.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/typescript/statics-and-methods.md b/docs/typescript/statics-and-methods.md index e49a8a520c5..9fc69e74b7a 100644 --- a/docs/typescript/statics-and-methods.md +++ b/docs/typescript/statics-and-methods.md @@ -112,7 +112,7 @@ const schema = new Schema({ }); schema.static('createWithFullName', function createWithFullName(name: string) { const [firstName, lastName] = name.split(' '); - return User.create({ firstName, lastName }); + return this.create({ firstName, lastName }); }); schema.method('fullName', function fullName(): string { return this.firstName + ' ' + this.lastName; @@ -124,4 +124,4 @@ User.createWithFullName('Jean-Luc Picard').then(doc => { console.log(doc.firstName); // 'Jean-Luc' doc.fullName(); // 'Jean-Luc Picard' }); -``` \ No newline at end of file +``` From afbd8d1c29ad585b83a13b428696ecdaa057f5bc Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sun, 20 Nov 2022 11:24:08 +0100 Subject: [PATCH 086/112] docs(query): updated examples for updateOne and replaceOne fix #12706 --- lib/query.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/query.js b/lib/query.js index 30e85f7985b..7dc1f8bbc20 100644 --- a/lib/query.js +++ b/lib/query.js @@ -4574,8 +4574,11 @@ Query.prototype.updateMany = function(conditions, doc, options, callback) { * #### Example: * * const res = await Person.updateOne({ name: 'Jean-Luc Picard' }, { ship: 'USS Enterprise' }); - * res.n; // Number of documents matched - * res.nModified; // Number of documents modified + * res.acknowledged; // Indicates if this write result was acknowledged. If not, then all other members of this result will be undefined. + * res.matchedCount; // Number of documents that matched the filter + * res.modifiedCount; // Number of documents that were modified + * res.upsertedCount; // Number of documents that were upserted + * res.upsertedId; // Identifier of the inserted document (if an upsert took place) * * This function triggers the following middleware. * @@ -4638,8 +4641,11 @@ Query.prototype.updateOne = function(conditions, doc, options, callback) { * #### Example: * * const res = await Person.replaceOne({ _id: 24601 }, { name: 'Jean Valjean' }); - * res.n; // Number of documents matched - * res.nModified; // Number of documents modified + * res.acknowledged; // Indicates if this write result was acknowledged. If not, then all other members of this result will be undefined. + * res.matchedCount; // Number of documents that matched the filter + * res.modifiedCount; // Number of documents that were modified + * res.upsertedCount; // Number of documents that were upserted + * res.upsertedId; // Identifier of the inserted document (if an upsert took place) * * This function triggers the following middleware. * From 994387e941d3774ee6465e344243d8476d4677cb Mon Sep 17 00:00:00 2001 From: Noah Passalacqua Date: Sun, 20 Nov 2022 18:10:59 +0000 Subject: [PATCH 087/112] add `rewind` function to `QueryCursor` Wraps the `mongodb.FindCursor.rewind` function to reset the cursor to its uninitialized state, effectively resetting the cursor to the beginning. --- lib/cursor/QueryCursor.js | 15 +++++++++++++++ types/cursor.d.ts | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/lib/cursor/QueryCursor.js b/lib/cursor/QueryCursor.js index 3a2e683890e..a73224d2240 100644 --- a/lib/cursor/QueryCursor.js +++ b/lib/cursor/QueryCursor.js @@ -194,6 +194,21 @@ QueryCursor.prototype.close = function(callback) { }, this.model.events); }; +/** + * Rewind this cursor to its uninitialized state. Any options that are present on the cursor will + * remain in effect. Iterating this cursor will cause new queries to be sent to the server, even + * if the resultant data has already been retrieved by this cursor. + * + * @return {AggregationCursor} this + * @api public + * @method rewind + */ + + QueryCursor.prototype.rewind = function() { + this.cursor.rewind(); + return this; +}; + /** * Get the next document from this cursor. Will return `null` when there are * no documents left. diff --git a/types/cursor.d.ts b/types/cursor.d.ts index 80e43530dff..bd514542676 100644 --- a/types/cursor.d.ts +++ b/types/cursor.d.ts @@ -26,6 +26,13 @@ declare module 'mongoose' { close(callback: CallbackWithoutResult): void; close(): Promise; + /** + * Rewind this cursor to its uninitialized state. Any options that are present on the cursor will + * remain in effect. Iterating this cursor will cause new queries to be sent to the server, even + * if the resultant data has already been retrieved by this cursor. + */ + rewind(): this; + /** * Execute `fn` for every document(s) in the cursor. If batchSize is provided * `fn` will be executed for each batch of documents. If `fn` returns a promise, From 934bb87c4dfec857c3997591ba2ca75fe3b765ae Mon Sep 17 00:00:00 2001 From: Noah Passalacqua Date: Mon, 21 Nov 2022 00:14:30 -0600 Subject: [PATCH 088/112] wrap function --- lib/cursor/QueryCursor.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/cursor/QueryCursor.js b/lib/cursor/QueryCursor.js index a73224d2240..f862d0f4fde 100644 --- a/lib/cursor/QueryCursor.js +++ b/lib/cursor/QueryCursor.js @@ -204,8 +204,11 @@ QueryCursor.prototype.close = function(callback) { * @method rewind */ - QueryCursor.prototype.rewind = function() { - this.cursor.rewind(); +QueryCursor.prototype.rewind = function() { + const _this = this; + _waitForCursor(this, function() { + _this.cursor.rewind(); + }); return this; }; From cfb2785a975bc24eb88f01883605380e365eafc3 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 21 Nov 2022 10:03:02 -0800 Subject: [PATCH 089/112] fix(types): avoid typeof Query with generics for TypeScript 4.6 support Fix #12688 --- types/query.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/query.d.ts b/types/query.d.ts index 3a3a7a6b36f..5dec26efd7a 100644 --- a/types/query.d.ts +++ b/types/query.d.ts @@ -616,7 +616,7 @@ declare module 'mongoose' { then: Promise['then']; /** Converts this query to a customized, reusable query constructor with all arguments and options retained. */ - toConstructor(): typeof Query; + toConstructor(): RetType; /** Declare and/or execute this query as an update() operation. */ update(filter?: FilterQuery, update?: UpdateQuery | UpdateWithAggregationPipeline, options?: QueryOptions | null, callback?: Callback): QueryWithHelpers; From 5839c5e17915b9a3e14f92d91c3c29ac9e0bdd7c Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 19 Nov 2022 10:09:01 +0100 Subject: [PATCH 090/112] feat(debug): allow setting debug on a per-connection basis fix #12700 --- lib/connection.js | 1 + lib/drivers/node-mongodb-native/collection.js | 7 +++++- test/docs/debug.test.js | 22 ++++++++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/connection.js b/lib/connection.js index 98fb871c115..ab18b0f0103 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -155,6 +155,7 @@ Connection.prototype.get = function(key) { * Supported options include: * * - `maxTimeMS`: Set [`maxTimeMS`](/docs/api.html#query_Query-maxTimeMS) for all queries on this connection. + * - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arugments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`. * * #### Example: * diff --git a/lib/drivers/node-mongodb-native/collection.js b/lib/drivers/node-mongodb-native/collection.js index 1207264d2db..c36274a6a61 100644 --- a/lib/drivers/node-mongodb-native/collection.js +++ b/lib/drivers/node-mongodb-native/collection.js @@ -77,11 +77,16 @@ function iter(i) { const collection = this.collection; const args = Array.from(arguments); const _this = this; - const debug = _this && + const hasGlobalDebug = _this && _this.conn && _this.conn.base && _this.conn.base.options && _this.conn.base.options.debug; + const hasConnectionDebug = _this && + _this.conn && + _this.conn.options && + _this.conn.options.debug; + const debug = hasGlobalDebug || hasConnectionDebug; const lastArg = arguments[arguments.length - 1]; const opId = new ObjectId(); diff --git a/test/docs/debug.test.js b/test/docs/debug.test.js index 7e12c3fe008..a7e798d1294 100644 --- a/test/docs/debug.test.js +++ b/test/docs/debug.test.js @@ -15,7 +15,11 @@ const Schema = mongoose.Schema; */ const testSchema = new Schema({ - dob: Date + dob: Date, + title: { + type: String, + required: false, + } }, { timestamps: { createdAt: 'created_at' @@ -67,4 +71,20 @@ describe('debug: shell', function() { assert.equal(true, lastLog.includes('ISODate')); }); + it('should allow to set the `debug` option on a per-connection basis (gh-12700)', async function() { + // Disable global debug + mongoose.set('debug', false); + // `conn1` with active debug + const conn1 = mongoose.createConnection('mongodb://localhost:27017'); + conn1.set('debug', true); + const testModel1 = conn1.model('Test', testSchema); + await testModel1.create({ dob: new Date(), title: 'Connection 1' }); + const storedLog = lastLog; + // `conn2` without debug + const conn2 = mongoose.createConnection('mongodb://localhost:27017'); + const testModel2 = conn2.model('Test', testSchema); + await testModel2.create({ dob: new Date(), title: 'Connection 2' }); + // Last log should not have been overwritten + assert.equal(storedLog, lastLog); + }); }); From 955f6a9239ac7648d1845248a97e2adbbf0f57a6 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 19 Nov 2022 10:14:56 +0100 Subject: [PATCH 091/112] fix connection uri --- test/docs/debug.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/docs/debug.test.js b/test/docs/debug.test.js index a7e798d1294..4aa18db99d1 100644 --- a/test/docs/debug.test.js +++ b/test/docs/debug.test.js @@ -75,13 +75,13 @@ describe('debug: shell', function() { // Disable global debug mongoose.set('debug', false); // `conn1` with active debug - const conn1 = mongoose.createConnection('mongodb://localhost:27017'); + const conn1 = mongoose.createConnection(start.uri); conn1.set('debug', true); const testModel1 = conn1.model('Test', testSchema); await testModel1.create({ dob: new Date(), title: 'Connection 1' }); const storedLog = lastLog; // `conn2` without debug - const conn2 = mongoose.createConnection('mongodb://localhost:27017'); + const conn2 = mongoose.createConnection(start.uri); const testModel2 = conn2.model('Test', testSchema); await testModel2.create({ dob: new Date(), title: 'Connection 2' }); // Last log should not have been overwritten From e8691c2162c7497b3b1b6070216e5add6cf83c60 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Tue, 22 Nov 2022 09:17:42 +0100 Subject: [PATCH 092/112] applied requested changes --- lib/drivers/node-mongodb-native/collection.js | 6 +++--- test/docs/debug.test.js | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/drivers/node-mongodb-native/collection.js b/lib/drivers/node-mongodb-native/collection.js index c36274a6a61..ae74dd1a880 100644 --- a/lib/drivers/node-mongodb-native/collection.js +++ b/lib/drivers/node-mongodb-native/collection.js @@ -77,16 +77,16 @@ function iter(i) { const collection = this.collection; const args = Array.from(arguments); const _this = this; - const hasGlobalDebug = _this && + const globalDebug = _this && _this.conn && _this.conn.base && _this.conn.base.options && _this.conn.base.options.debug; - const hasConnectionDebug = _this && + const connectionDebug = _this && _this.conn && _this.conn.options && _this.conn.options.debug; - const debug = hasGlobalDebug || hasConnectionDebug; + const debug = connectionDebug == null ? globalDebug : connectionDebug; const lastArg = arguments[arguments.length - 1]; const opId = new ObjectId(); diff --git a/test/docs/debug.test.js b/test/docs/debug.test.js index 4aa18db99d1..39df6e93369 100644 --- a/test/docs/debug.test.js +++ b/test/docs/debug.test.js @@ -72,16 +72,15 @@ describe('debug: shell', function() { }); it('should allow to set the `debug` option on a per-connection basis (gh-12700)', async function() { - // Disable global debug - mongoose.set('debug', false); + const m = new mongoose.Mongoose(); // `conn1` with active debug - const conn1 = mongoose.createConnection(start.uri); + const conn1 = m.createConnection(start.uri); conn1.set('debug', true); const testModel1 = conn1.model('Test', testSchema); await testModel1.create({ dob: new Date(), title: 'Connection 1' }); const storedLog = lastLog; // `conn2` without debug - const conn2 = mongoose.createConnection(start.uri); + const conn2 = m.createConnection(start.uri); const testModel2 = conn2.model('Test', testSchema); await testModel2.create({ dob: new Date(), title: 'Connection 2' }); // Last log should not have been overwritten From aa06f1d25673cbf2bd6bf683ae24f944cece0239 Mon Sep 17 00:00:00 2001 From: Eliott C Date: Tue, 22 Nov 2022 16:45:50 +0100 Subject: [PATCH 093/112] fix(types): Update replaceWith pipeline stage --- types/pipelinestage.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/pipelinestage.d.ts b/types/pipelinestage.d.ts index f58e4b61f27..c3ee2f0a168 100644 --- a/types/pipelinestage.d.ts +++ b/types/pipelinestage.d.ts @@ -213,7 +213,7 @@ declare module 'mongoose' { export interface ReplaceWith { /** [`$replaceWith` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/replaceWith/) */ - $replaceWith: ObjectExpressionOperator | { [field: string]: Expression }; + $replaceWith: ObjectExpressionOperator | { [field: string]: Expression } | `${string}`; } export interface Sample { From 616ce5dedf47a1ece96161a3b714e4c3ebbbad15 Mon Sep 17 00:00:00 2001 From: Eliott C Date: Tue, 22 Nov 2022 16:48:07 +0100 Subject: [PATCH 094/112] Correctly prefix with $ --- types/pipelinestage.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/pipelinestage.d.ts b/types/pipelinestage.d.ts index c3ee2f0a168..37d228ff1b7 100644 --- a/types/pipelinestage.d.ts +++ b/types/pipelinestage.d.ts @@ -213,7 +213,7 @@ declare module 'mongoose' { export interface ReplaceWith { /** [`$replaceWith` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/replaceWith/) */ - $replaceWith: ObjectExpressionOperator | { [field: string]: Expression } | `${string}`; + $replaceWith: ObjectExpressionOperator | { [field: string]: Expression } | `$${string}`; } export interface Sample { From fde5e0f4b973713e52253eebaa273822f8d13ba0 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 22 Nov 2022 15:34:10 -0500 Subject: [PATCH 095/112] fix(cursor): make `eachAsync()` avoid modifying batch when mixing `parallel` and `batchSize` Fix #12652 --- lib/helpers/cursor/eachAsync.js | 144 ++++++++++++++------------ test/helpers/cursor.eachAsync.test.js | 24 +++++ 2 files changed, 103 insertions(+), 65 deletions(-) diff --git a/lib/helpers/cursor/eachAsync.js b/lib/helpers/cursor/eachAsync.js index 735fd2d8156..e3f6f8a24f4 100644 --- a/lib/helpers/cursor/eachAsync.js +++ b/lib/helpers/cursor/eachAsync.js @@ -33,7 +33,7 @@ module.exports = function eachAsync(next, fn, options, callback) { const aggregatedErrors = []; const enqueue = asyncQueue(); - let drained = false; + let aborted = false; return promiseOrCallback(callback, cb => { if (signal != null) { @@ -42,7 +42,7 @@ module.exports = function eachAsync(next, fn, options, callback) { } signal.addEventListener('abort', () => { - drained = true; + aborted = true; return cb(null); }, { once: true }); } @@ -63,90 +63,104 @@ module.exports = function eachAsync(next, fn, options, callback) { function iterate(finalCallback) { let handleResultsInProgress = 0; let currentDocumentIndex = 0; - let documentsBatch = []; let error = null; for (let i = 0; i < parallel; ++i) { - enqueue(fetch); + enqueue(createFetch()); } - function fetch(done) { - if (drained || error) { - return done(); - } + function createFetch() { + let documentsBatch = []; + let drained = false; + + return fetch; - next(function(err, doc) { - if (drained || error != null) { + function fetch(done) { + if (drained || aborted) { + return done(); + } else if (error) { return done(); } - if (err != null) { - if (continueOnError) { - aggregatedErrors.push(err); - } else { - error = err; - finalCallback(err); + + next(function(err, doc) { + if (error != null) { return done(); } - } - if (doc == null) { - drained = true; - if (handleResultsInProgress <= 0) { - const finalErr = continueOnError ? - createEachAsyncMultiError(aggregatedErrors) : - error; - - finalCallback(finalErr); - } else if (batchSize && documentsBatch.length) { - handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack); + if (err != null) { + if (err.name === 'MongoCursorExhaustedError') { + // We may end up calling `next()` multiple times on an exhausted + // cursor, which leads to an error. In case cursor is exhausted, + // just treat it as if the cursor returned no document, which is + // how a cursor indicates it is exhausted. + doc = null; + } else if (continueOnError) { + aggregatedErrors.push(err); + } else { + error = err; + finalCallback(err); + return done(); + } + } + if (doc == null) { + drained = true; + if (handleResultsInProgress <= 0) { + const finalErr = continueOnError ? + createEachAsyncMultiError(aggregatedErrors) : + error; + + finalCallback(finalErr); + } else if (batchSize && documentsBatch.length) { + handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack); + } + return done(); } - return done(); - } - ++handleResultsInProgress; + ++handleResultsInProgress; - // Kick off the subsequent `next()` before handling the result, but - // make sure we know that we still have a result to handle re: #8422 - immediate(() => done()); + // Kick off the subsequent `next()` before handling the result, but + // make sure we know that we still have a result to handle re: #8422 + immediate(() => done()); - if (batchSize) { - documentsBatch.push(doc); - } + if (batchSize) { + documentsBatch.push(doc); + } - // If the current documents size is less than the provided patch size don't process the documents yet - if (batchSize && documentsBatch.length !== batchSize) { - immediate(() => enqueue(fetch)); - return; - } + // If the current documents size is less than the provided batch size don't process the documents yet + if (batchSize && documentsBatch.length !== batchSize) { + immediate(() => enqueue(fetch)); + return; + } - const docsToProcess = batchSize ? documentsBatch : doc; + const docsToProcess = batchSize ? documentsBatch : doc; - function handleNextResultCallBack(err) { - if (batchSize) { - handleResultsInProgress -= documentsBatch.length; - documentsBatch = []; - } else { - --handleResultsInProgress; - } - if (err != null) { - if (continueOnError) { - aggregatedErrors.push(err); + function handleNextResultCallBack(err) { + if (batchSize) { + handleResultsInProgress -= documentsBatch.length; + documentsBatch = []; } else { - error = err; - return finalCallback(err); + --handleResultsInProgress; + } + if (err != null) { + if (continueOnError) { + aggregatedErrors.push(err); + } else { + error = err; + return finalCallback(err); + } + } + if ((drained || aborted) && handleResultsInProgress <= 0) { + const finalErr = continueOnError ? + createEachAsyncMultiError(aggregatedErrors) : + error; + return finalCallback(finalErr); } - } - if (drained && handleResultsInProgress <= 0) { - const finalErr = continueOnError ? - createEachAsyncMultiError(aggregatedErrors) : - error; - return finalCallback(finalErr); - } - immediate(() => enqueue(fetch)); - } + immediate(() => enqueue(fetch)); + } - handleNextResult(docsToProcess, currentDocumentIndex++, handleNextResultCallBack); - }); + handleNextResult(docsToProcess, currentDocumentIndex++, handleNextResultCallBack); + }); + } } } diff --git a/test/helpers/cursor.eachAsync.test.js b/test/helpers/cursor.eachAsync.test.js index b42cab85da0..57411ccfd5d 100644 --- a/test/helpers/cursor.eachAsync.test.js +++ b/test/helpers/cursor.eachAsync.test.js @@ -189,6 +189,30 @@ describe('eachAsync()', function() { assert.equal(numCalled, 1); }); + it('avoids mutating document batch with parallel (gh-12652)', async() => { + const max = 100; + let numCalled = 0; + function next(cb) { + setImmediate(() => { + if (++numCalled > max) { + return cb(null, null); + } + cb(null, { num: numCalled }); + }); + } + + let numDocsProcessed = 0; + async function fn(batch) { + numDocsProcessed += batch.length; + const length = batch.length; + await new Promise(resolve => setTimeout(resolve, 50)); + assert.equal(batch.length, length); + } + + await eachAsync(next, fn, { parallel: 7, batchSize: 10 }); + assert.equal(numDocsProcessed, max); + }); + it('using AbortSignal (gh-12173)', async function() { if (typeof AbortController === 'undefined') { return this.skip(); From e50de5c0f7f2e3d9386638f7b5aac027cdd153e1 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 22 Nov 2022 16:48:37 -0500 Subject: [PATCH 096/112] chore: release 6.7.3 --- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d54e3a7223e..17432a1ed80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +6.7.3 / 2022-11-22 +================== + * fix(document): handle setting array to itself after saving and pushing a new value #12672 #12656 + * fix(types): update replaceWith pipeline stage #12715 [coyotte508](https://github.com/coyotte508) + * fix(types): remove incorrect modelName type definition #12682 #12669 [lpizzinidev](https://github.com/lpizzinidev) + * fix(schema): fix setupTimestamps for browser.umd #12683 [raphael-papazikas](https://github.com/raphael-papazikas) + * docs: correct justOne description #12686 #12599 [tianguangcn](https://github.com/tianguangcn) + * docs: make links more consistent #12690 #12645 [hasezoey](https://github.com/hasezoey) + * docs(document): explain that $isNew is false in post('save') hooks #12685 #11990 + * docs: fixed line causing a "used before defined" linting error #12707 [sgpinkus](https://github.com/sgpinkus) + 6.7.2 / 2022-11-07 ================== * fix(discriminator): skip copying base schema plugins if `applyPlugins == false` #12613 #12604 [lpizzinidev](https://github.com/lpizzinidev) diff --git a/package.json b/package.json index 48899d57b59..ea400a3989e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mongoose", "description": "Mongoose MongoDB ODM", - "version": "6.7.2", + "version": "6.7.3", "author": "Guillermo Rauch ", "keywords": [ "mongodb", From 0a0630b71bbe1c3eda1b802ef0aa902adf754aed Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Wed, 23 Nov 2022 09:18:15 +0100 Subject: [PATCH 097/112] fix: setting global strictQuery after Schema creation wasn't working fix #12703 --- lib/cast.js | 16 ++++++++++++++-- test/query.test.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/lib/cast.js b/lib/cast.js index 1cb88406de4..dc04500f1a3 100644 --- a/lib/cast.js +++ b/lib/cast.js @@ -264,7 +264,7 @@ module.exports = function cast(schema, obj, options, context) { } const strict = 'strict' in options ? options.strict : schema.options.strict; - const strictQuery = getStrictQuery(options, schema._userProvidedOptions, schema.options); + const strictQuery = getStrictQuery(options, schema._userProvidedOptions, schema.options, context); if (options.upsert && strict) { if (strict === 'throw') { throw new StrictModeError(path); @@ -374,7 +374,7 @@ function _cast(val, numbertype, context) { } } -function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions) { +function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions, context) { if ('strictQuery' in queryOptions) { return queryOptions.strictQuery; } @@ -387,5 +387,17 @@ function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions) if ('strict' in schemaUserProvidedOptions) { return schemaUserProvidedOptions.strict; } + if ( + context.mongooseCollection && + context.mongooseCollection.conn && + context.mongooseCollection.conn.base) { + const mongooseOptions = context.mongooseCollection.conn.base.options; + if ('strictQuery' in mongooseOptions) { + return mongooseOptions.strictQuery; + } + if ('strict' in mongooseOptions) { + return mongooseOptions.strict; + } + } return schemaOptions.strictQuery; } diff --git a/test/query.test.js b/test/query.test.js index b56a5e6c3de..a5309ebba40 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -4263,4 +4263,47 @@ describe('Query', function() { ); }, { message: 'Can\'t modify discriminator key "animals.kind" on discriminator model' }); }); + + it('global strictQuery should work if applied after schema creation (gh-12703)', async() => { + const m = new mongoose.Mongoose(); + + await m.connect(start.uri); + + const schema = new mongoose.Schema({ title: String }); + + const Test = m.model('test', schema); + + m.set('strictQuery', false); + + await Test.create({ + title: 'chimichanga' + }); + await Test.create({ + title: 'burrito bowl' + }); + await Test.create({ + title: 'taco supreme' + }); + + const cond = { + $or: [ + { + title: { + $regex: 'urri', + $options: 'i' + } + }, + { + name: { + $regex: 'urri', + $options: 'i' + } + } + ] + }; + + const found = await Test.find(cond); + assert.strictEqual(found.length, 1); + assert.strictEqual(found[0].title, 'burrito bowl'); + }); }); From f75cf27826a6e96f2a9c4f1fb6e8642c968a4d92 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Wed, 23 Nov 2022 09:33:36 +0100 Subject: [PATCH 098/112] added options object check --- lib/cast.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cast.js b/lib/cast.js index dc04500f1a3..019556a7e5d 100644 --- a/lib/cast.js +++ b/lib/cast.js @@ -390,7 +390,8 @@ function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions, if ( context.mongooseCollection && context.mongooseCollection.conn && - context.mongooseCollection.conn.base) { + context.mongooseCollection.conn.base && + context.mongooseCollection.conn.base.options) { const mongooseOptions = context.mongooseCollection.conn.base.options; if ('strictQuery' in mongooseOptions) { return mongooseOptions.strictQuery; From 22074a3f509aa5623e5c5bdde87085265d2d9915 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Wed, 23 Nov 2022 09:36:01 +0100 Subject: [PATCH 099/112] fix lint --- lib/cast.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cast.js b/lib/cast.js index 019556a7e5d..b65c1e3737b 100644 --- a/lib/cast.js +++ b/lib/cast.js @@ -390,7 +390,7 @@ function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions, if ( context.mongooseCollection && context.mongooseCollection.conn && - context.mongooseCollection.conn.base && + context.mongooseCollection.conn.base && context.mongooseCollection.conn.base.options) { const mongooseOptions = context.mongooseCollection.conn.base.options; if ('strictQuery' in mongooseOptions) { From 0ee889391bb82fe117d1209c75c38e444e068ddf Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 23 Nov 2022 16:08:21 -0500 Subject: [PATCH 100/112] fix(types): correctly infer ReadonlyArray types in schema definitions Fix #12611 --- test/types/schema.test.ts | 19 ++++++++++++++ types/inferschematype.d.ts | 53 +++++++++++++++++++------------------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 7bd00a8d4b8..2a9f66b4d63 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -938,3 +938,22 @@ function gh12590() { }); } + +function gh12611() { + const reusableFields = { + description: { type: String, required: true }, + skills: { type: [Schema.Types.ObjectId], ref: "Skill", default: [] } + } as const; + + const firstSchema = new Schema({ + ...reusableFields, + anotherField: String + }); + + type Props = InferSchemaType; + expectType<{ + description: string; + skills: Types.ObjectId[]; + anotherField?: string; + }>({} as Props); +} diff --git a/types/inferschematype.d.ts b/types/inferschematype.d.ts index e8c345fc707..c4dc62f7502 100644 --- a/types/inferschematype.d.ts +++ b/types/inferschematype.d.ts @@ -161,29 +161,30 @@ type PathEnumOrString['enum']> = T extends ( type ResolvePathType = {}, TypeKey extends TypeKeyBaseType = DefaultTypeKey> = PathValueType extends Schema ? InferSchemaType : PathValueType extends (infer Item)[] ? IfEquals> : ObtainDocumentPathType[]> : - PathValueType extends StringSchemaDefinition ? PathEnumOrString : - IfEquals extends true ? PathEnumOrString : - IfEquals extends true ? PathEnumOrString : - PathValueType extends NumberSchemaDefinition ? Options['enum'] extends ReadonlyArray ? Options['enum'][number] : number : - IfEquals extends true ? number : - PathValueType extends DateSchemaDefinition ? Date : - IfEquals extends true ? Date : - PathValueType extends typeof Buffer | 'buffer' | 'Buffer' | typeof Schema.Types.Buffer ? Buffer : - PathValueType extends BooleanSchemaDefinition ? boolean : - IfEquals extends true ? boolean : - PathValueType extends ObjectIdSchemaDefinition ? Types.ObjectId : - IfEquals extends true ? Types.ObjectId : - IfEquals extends true ? Types.ObjectId : - PathValueType extends 'decimal128' | 'Decimal128' | typeof Schema.Types.Decimal128 ? Types.Decimal128 : - IfEquals extends true ? Types.Decimal128 : - IfEquals extends true ? Types.Decimal128 : - PathValueType extends 'uuid' | 'UUID' | typeof Schema.Types.UUID ? Buffer : - IfEquals extends true ? Buffer : - PathValueType extends MapConstructor ? Map> : - PathValueType extends ArrayConstructor ? any[] : - PathValueType extends typeof Schema.Types.Mixed ? any: - IfEquals extends true ? any: - IfEquals extends true ? any: - PathValueType extends typeof SchemaType ? PathValueType['prototype'] : - PathValueType extends Record ? ObtainDocumentType : - unknown; + PathValueType extends ReadonlyArray ? IfEquals> : ObtainDocumentPathType[]> : + PathValueType extends StringSchemaDefinition ? PathEnumOrString : + IfEquals extends true ? PathEnumOrString : + IfEquals extends true ? PathEnumOrString : + PathValueType extends NumberSchemaDefinition ? Options['enum'] extends ReadonlyArray ? Options['enum'][number] : number : + IfEquals extends true ? number : + PathValueType extends DateSchemaDefinition ? Date : + IfEquals extends true ? Date : + PathValueType extends typeof Buffer | 'buffer' | 'Buffer' | typeof Schema.Types.Buffer ? Buffer : + PathValueType extends BooleanSchemaDefinition ? boolean : + IfEquals extends true ? boolean : + PathValueType extends ObjectIdSchemaDefinition ? Types.ObjectId : + IfEquals extends true ? Types.ObjectId : + IfEquals extends true ? Types.ObjectId : + PathValueType extends 'decimal128' | 'Decimal128' | typeof Schema.Types.Decimal128 ? Types.Decimal128 : + IfEquals extends true ? Types.Decimal128 : + IfEquals extends true ? Types.Decimal128 : + PathValueType extends 'uuid' | 'UUID' | typeof Schema.Types.UUID ? Buffer : + IfEquals extends true ? Buffer : + PathValueType extends MapConstructor ? Map> : + PathValueType extends ArrayConstructor ? any[] : + PathValueType extends typeof Schema.Types.Mixed ? any: + IfEquals extends true ? any: + IfEquals extends true ? any: + PathValueType extends typeof SchemaType ? PathValueType['prototype'] : + PathValueType extends Record ? ObtainDocumentType : + unknown; From 12706ebdd0ea039103636ef9ea4d25f7a0282f00 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 23 Nov 2022 16:14:05 -0500 Subject: [PATCH 101/112] style: fix lint --- test/types/schema.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 2a9f66b4d63..a531247e183 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -942,14 +942,14 @@ function gh12590() { function gh12611() { const reusableFields = { description: { type: String, required: true }, - skills: { type: [Schema.Types.ObjectId], ref: "Skill", default: [] } + skills: { type: [Schema.Types.ObjectId], ref: 'Skill', default: [] } } as const; - + const firstSchema = new Schema({ ...reusableFields, anotherField: String }); - + type Props = InferSchemaType; expectType<{ description: string; From c51a40e10a0bd7772dc5ebd8509e5be1a65e7ca1 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Thu, 10 Nov 2022 19:27:08 +0100 Subject: [PATCH 102/112] added deprecation warning for default strictQuery fix #12666 --- docs/guide.md | 9 +++++++++ lib/index.js | 8 +++++++- lib/query.js | 10 ++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/guide.md b/docs/guide.md index f10b44dc5c9..f07a17bfe28 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -892,6 +892,15 @@ However, you can override this behavior globally: mongoose.set('strictQuery', false); ``` +In Mongoose 7, `strictQuery` default value will be switched back to `false`. +You can prepare for the change by specifying: + +```javascript +// Set `strictQuery` to `false` +mongoose.set('strictQuery', false); +``` + +

          option: toJSON

          Exactly the same as the [toObject](#toObject) option but only applies when diff --git a/lib/index.js b/lib/index.js index bf2777f8cad..edd303a42d0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -214,7 +214,7 @@ Mongoose.prototype.setDriver = function setDriver(driver) { * - 'sanitizeFilter': `false` by default. Set to true to enable the [sanitization of the query filters](/docs/api.html#mongoose_Mongoose-sanitizeFilter) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`. * - 'selectPopulatedPaths': `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one. * - 'strict': `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas. - * - 'strictQuery': same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas. + * - 'strictQuery': same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas. The default value will be switched back to `false` in Mongoose 7, use `mongoose.set('strictQuery', false);` if you want to prepare for the change. * - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()` * - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject) * @@ -408,6 +408,12 @@ Mongoose.prototype.connect = function(uri, options, callback) { const _mongoose = this instanceof Mongoose ? this : mongoose; const conn = _mongoose.connection; + if (_mongoose.options.strictQuery === undefined) { + utils.warn('Mongoose: the `strictQuery` option will be switched back to `false` by default ' + + 'in Mongoose 7. Use `mongoose.set(\'strictQuery\', false);` if you want to prepare ' + + 'for this change.'); + } + return _mongoose._promiseOrCallback(callback, cb => { conn.openUri(uri, options, err => { if (err != null) { diff --git a/lib/query.js b/lib/query.js index 7dc1f8bbc20..c887c00bed0 100644 --- a/lib/query.js +++ b/lib/query.js @@ -4895,6 +4895,16 @@ Query.prototype.exec = function exec(op, callback) { // Ensure that `exec()` is the first thing that shows up in // the stack when cast errors happen. const castError = new CastError(); + const collection = this.mongooseCollection; + + if ( + collection.conn.base.options.strictQuery === undefined && + _this.options.strictQuery === true + ) { + utils.warn('Mongoose: the `strictQuery` option will be switched back to `false` by default ' + + 'in Mongoose 7. Use `mongoose.set(\'strictQuery\', false);` if you want to prepare ' + + 'for this change.'); + } if (typeof op === 'function') { callback = op; From 8cdcfeba10df4afdb2c148de28466f0815b7d412 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Thu, 10 Nov 2022 19:38:48 +0100 Subject: [PATCH 103/112] added connection check --- lib/query.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/query.js b/lib/query.js index c887c00bed0..4f4258ebbda 100644 --- a/lib/query.js +++ b/lib/query.js @@ -4898,6 +4898,7 @@ Query.prototype.exec = function exec(op, callback) { const collection = this.mongooseCollection; if ( + collection.conn && collection.conn.base.options.strictQuery === undefined && _this.options.strictQuery === true ) { From befef84a9219baa43153f306184aa42f2d28598e Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sun, 13 Nov 2022 10:22:22 +0100 Subject: [PATCH 104/112] extended warning message --- docs/guide.md | 5 ++++- lib/index.js | 2 +- lib/query.js | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/guide.md b/docs/guide.md index f07a17bfe28..994135f6381 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -896,8 +896,11 @@ In Mongoose 7, `strictQuery` default value will be switched back to `false`. You can prepare for the change by specifying: ```javascript -// Set `strictQuery` to `false` +// Set `strictQuery` to `false` to prepare for the change mongoose.set('strictQuery', false); + +// Set `strictQuery` to `true` to suppress the warning message +mongoose.set('strictQuery', true); ``` diff --git a/lib/index.js b/lib/index.js index edd303a42d0..aa21ecd3156 100644 --- a/lib/index.js +++ b/lib/index.js @@ -411,7 +411,7 @@ Mongoose.prototype.connect = function(uri, options, callback) { if (_mongoose.options.strictQuery === undefined) { utils.warn('Mongoose: the `strictQuery` option will be switched back to `false` by default ' + 'in Mongoose 7. Use `mongoose.set(\'strictQuery\', false);` if you want to prepare ' + - 'for this change.'); + 'for this change. Or use `mongoose.set(\'strictQuery\', true);` to suppress this warning.'); } return _mongoose._promiseOrCallback(callback, cb => { diff --git a/lib/query.js b/lib/query.js index 4f4258ebbda..6660d7d274b 100644 --- a/lib/query.js +++ b/lib/query.js @@ -4904,7 +4904,7 @@ Query.prototype.exec = function exec(op, callback) { ) { utils.warn('Mongoose: the `strictQuery` option will be switched back to `false` by default ' + 'in Mongoose 7. Use `mongoose.set(\'strictQuery\', false);` if you want to prepare ' + - 'for this change.'); + 'for this change. Or use `mongoose.set(\'strictQuery\', true);` to suppress this warning.'); } if (typeof op === 'function') { From 82f62e4d0627d0dcb1c5562197dfc7e9e7fc9233 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Mon, 14 Nov 2022 09:19:56 +0100 Subject: [PATCH 105/112] added printStrictQueryWarning dedicated function --- lib/helpers/printStrictQueryWarning.js | 11 +++++++++++ lib/index.js | 5 ++--- lib/query.js | 5 ++--- 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 lib/helpers/printStrictQueryWarning.js diff --git a/lib/helpers/printStrictQueryWarning.js b/lib/helpers/printStrictQueryWarning.js new file mode 100644 index 00000000000..b25bc2137fa --- /dev/null +++ b/lib/helpers/printStrictQueryWarning.js @@ -0,0 +1,11 @@ +'use strict'; + +const util = require('node:util'); + +module.exports = util.deprecate( + function() { }, + 'Mongoose: the `strictQuery` option will be switched back to `false` by default ' + + 'in Mongoose 7. Use `mongoose.set(\'strictQuery\', false);` if you want to prepare ' + + 'for this change. Or use `mongoose.set(\'strictQuery\', true);` to suppress this warning.', + 'MONGOOSE' +); diff --git a/lib/index.js b/lib/index.js index aa21ecd3156..ec25265fc57 100644 --- a/lib/index.js +++ b/lib/index.js @@ -32,6 +32,7 @@ const validateBeforeSave = require('./plugins/validateBeforeSave'); const Aggregate = require('./aggregate'); const PromiseProvider = require('./promise_provider'); +const printStrictQueryWarning = require('./helpers/printStrictQueryWarning'); const shardingPlugin = require('./plugins/sharding'); const trusted = require('./helpers/query/trusted').trusted; const sanitizeFilter = require('./helpers/query/sanitizeFilter'); @@ -409,9 +410,7 @@ Mongoose.prototype.connect = function(uri, options, callback) { const conn = _mongoose.connection; if (_mongoose.options.strictQuery === undefined) { - utils.warn('Mongoose: the `strictQuery` option will be switched back to `false` by default ' + - 'in Mongoose 7. Use `mongoose.set(\'strictQuery\', false);` if you want to prepare ' + - 'for this change. Or use `mongoose.set(\'strictQuery\', true);` to suppress this warning.'); + printStrictQueryWarning(); } return _mongoose._promiseOrCallback(callback, cb => { diff --git a/lib/query.js b/lib/query.js index 6660d7d274b..bd92b78ff32 100644 --- a/lib/query.js +++ b/lib/query.js @@ -30,6 +30,7 @@ const isSubpath = require('./helpers/projection/isSubpath'); const mpath = require('mpath'); const mquery = require('mquery'); const parseProjection = require('./helpers/projection/parseProjection'); +const printStrictQueryWarning = require('./helpers/printStrictQueryWarning'); const removeUnusedArrayFilters = require('./helpers/update/removeUnusedArrayFilters'); const sanitizeFilter = require('./helpers/query/sanitizeFilter'); const sanitizeProjection = require('./helpers/query/sanitizeProjection'); @@ -4902,9 +4903,7 @@ Query.prototype.exec = function exec(op, callback) { collection.conn.base.options.strictQuery === undefined && _this.options.strictQuery === true ) { - utils.warn('Mongoose: the `strictQuery` option will be switched back to `false` by default ' + - 'in Mongoose 7. Use `mongoose.set(\'strictQuery\', false);` if you want to prepare ' + - 'for this change. Or use `mongoose.set(\'strictQuery\', true);` to suppress this warning.'); + printStrictQueryWarning(); } if (typeof op === 'function') { From c9b8a6ea0acde58332aa42061c7a390969a4283b Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Mon, 14 Nov 2022 09:23:16 +0100 Subject: [PATCH 106/112] fix require util --- lib/helpers/printStrictQueryWarning.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/printStrictQueryWarning.js b/lib/helpers/printStrictQueryWarning.js index b25bc2137fa..3cf4fdf4341 100644 --- a/lib/helpers/printStrictQueryWarning.js +++ b/lib/helpers/printStrictQueryWarning.js @@ -1,6 +1,6 @@ 'use strict'; -const util = require('node:util'); +const util = require('util'); module.exports = util.deprecate( function() { }, From 35707d8d0b6c5562328a33f8f05c1b1350d80484 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 19 Nov 2022 10:58:01 +0100 Subject: [PATCH 107/112] test trigger --- docs/guide.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/guide.md b/docs/guide.md index 994135f6381..82346fead82 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -898,7 +898,6 @@ You can prepare for the change by specifying: ```javascript // Set `strictQuery` to `false` to prepare for the change mongoose.set('strictQuery', false); - // Set `strictQuery` to `true` to suppress the warning message mongoose.set('strictQuery', true); ``` From 8f3fa256ba6a5c9b09f0a9d8d8255e51d8739700 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Thu, 24 Nov 2022 09:13:28 +0100 Subject: [PATCH 108/112] removed deprecation warning message from query execution --- docs/guide.md | 1 + lib/query.js | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/docs/guide.md b/docs/guide.md index 82346fead82..994135f6381 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -898,6 +898,7 @@ You can prepare for the change by specifying: ```javascript // Set `strictQuery` to `false` to prepare for the change mongoose.set('strictQuery', false); + // Set `strictQuery` to `true` to suppress the warning message mongoose.set('strictQuery', true); ``` diff --git a/lib/query.js b/lib/query.js index bd92b78ff32..7dc1f8bbc20 100644 --- a/lib/query.js +++ b/lib/query.js @@ -30,7 +30,6 @@ const isSubpath = require('./helpers/projection/isSubpath'); const mpath = require('mpath'); const mquery = require('mquery'); const parseProjection = require('./helpers/projection/parseProjection'); -const printStrictQueryWarning = require('./helpers/printStrictQueryWarning'); const removeUnusedArrayFilters = require('./helpers/update/removeUnusedArrayFilters'); const sanitizeFilter = require('./helpers/query/sanitizeFilter'); const sanitizeProjection = require('./helpers/query/sanitizeProjection'); @@ -4896,15 +4895,6 @@ Query.prototype.exec = function exec(op, callback) { // Ensure that `exec()` is the first thing that shows up in // the stack when cast errors happen. const castError = new CastError(); - const collection = this.mongooseCollection; - - if ( - collection.conn && - collection.conn.base.options.strictQuery === undefined && - _this.options.strictQuery === true - ) { - printStrictQueryWarning(); - } if (typeof op === 'function') { callback = op; From 7379c3d0e47e5570ac5bd1710fa9de72a2c003ce Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 27 Nov 2022 11:32:56 -0500 Subject: [PATCH 109/112] fix: address code review comments --- lib/cursor/QueryCursor.js | 2 +- .../populate/getModelsMapForPopulate.js | 4 +- lib/model.js | 8 --- test/model.populate.test.js | 25 ++++++-- types/index.d.ts | 2 +- types/populate.d.ts | 62 ++++++++++--------- 6 files changed, 57 insertions(+), 46 deletions(-) diff --git a/lib/cursor/QueryCursor.js b/lib/cursor/QueryCursor.js index f862d0f4fde..63281bdb988 100644 --- a/lib/cursor/QueryCursor.js +++ b/lib/cursor/QueryCursor.js @@ -210,7 +210,7 @@ QueryCursor.prototype.rewind = function() { _this.cursor.rewind(); }); return this; -}; +}; /** * Get the next document from this cursor. Will return `null` when there are diff --git a/lib/helpers/populate/getModelsMapForPopulate.js b/lib/helpers/populate/getModelsMapForPopulate.js index be2394cce68..8ae89fcbbd3 100644 --- a/lib/helpers/populate/getModelsMapForPopulate.js +++ b/lib/helpers/populate/getModelsMapForPopulate.js @@ -365,7 +365,9 @@ function _virtualPopulate(model, docs, options, _virtualRes) { let localField; const virtualPrefix = _virtualRes.nestedSchemaPath ? _virtualRes.nestedSchemaPath + '.' : ''; - if (typeof virtual.options.localField === 'function') { + if (typeof options.localField === 'string') { + localField = options.localField; + } else if (typeof virtual.options.localField === 'function') { localField = virtualPrefix + virtual.options.localField.call(doc, doc); } else if (Array.isArray(virtual.options.localField)) { localField = virtual.options.localField.map(field => virtualPrefix + field); diff --git a/lib/model.js b/lib/model.js index d60b73d81dd..e94992ed637 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4666,13 +4666,6 @@ function populate(model, docs, options, callback) { populateOptions.strictPopulate = model.base.options.strictPopulate; } } - let originalLocalField = ''; - if (model.schema.virtuals[populateOptions.path]) { - originalLocalField = model.schema.virtuals[populateOptions.path].options.localField; - } - if (populateOptions.localField) { - model.schema.virtuals[populateOptions.path].options.localField = populateOptions.localField; - } // normalize single / multiple docs passed if (!Array.isArray(docs)) { @@ -4689,7 +4682,6 @@ function populate(model, docs, options, callback) { callback(modelsMap); }); } - if (originalLocalField) model.schema.virtuals[populateOptions.path].options.localField = originalLocalField; const len = modelsMap.length; let vals = []; diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 3b4726c15d0..0de1ef29b38 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10828,6 +10828,7 @@ describe('model: populate:', function() { assert.ok(err); assert.ok(err.message.includes('strictPopulate'), err.message); }); + it('allows overwriting localField and foreignField when populating a virtual gh-6963', async function() { const testSchema = Schema({ name: String, uuid: 'ObjectId' }, { toJSON: { virtuals: true }, toObject: { virtuals: true } }); const userSchema = Schema({ name: String, field: { type: mongoose.Schema.Types.ObjectId, ref: 'gh6963' }, change: { type: mongoose.Schema.Types.ObjectId, ref: 'gh6963' } }); @@ -10876,12 +10877,18 @@ describe('model: populate:', function() { change: otherLocalEntry.uuid }); - const localTest = await Test.findOne({ _id: localEntry._id }).populate({ path: 'test', localField: 'uuid' }); + const localTest = await Test. + findOne({ _id: localEntry._id }). + populate({ path: 'test', localField: 'uuid' }); assert.equal(localTest.test.length, 1); - const otherLocalTest = await Test.findOne({ _id: otherLocalEntry._id }).populate({ path: 'test', localField: 'uuid' }); + const otherLocalTest = await Test. + findOne({ _id: otherLocalEntry._id }). + populate({ path: 'test', localField: 'uuid' }); assert.equal(otherLocalTest.test.length, 0); // should be empty because the original local field was _id and we created a doc with uuids - const check = await Test.findOne({ _id: localEntry._id }).populate({ path: 'test' }); + const check = await Test. + findOne({ _id: localEntry._id }). + populate({ path: 'test' }); assert.equal(check.test.length, 0); // ============localFieldAndForeignField============ const bothEntry = await Test.create({ name: 'Both', uuid: mongoose.Types.ObjectId() }); @@ -10891,11 +10898,17 @@ describe('model: populate:', function() { field: bothEntry.uuid, change: otherBothEntry.uuid }); - const bothTest = await Test.findOne({ _id: otherBothEntry._id }).populate({ path: 'test', localField: 'uuid', foreignField: 'change' }); + const bothTest = await Test. + findOne({ _id: otherBothEntry._id }). + populate({ path: 'test', localField: 'uuid', foreignField: 'change' }); assert.equal(bothTest.test.length, 1); - const otherBothTest = await Test.findOne({ _id: bothEntry._id }).populate({ path: 'test', localField: 'uuid', foreignField: 'change' }); + const otherBothTest = await Test. + findOne({ _id: bothEntry._id }). + populate({ path: 'test', localField: 'uuid', foreignField: 'change' }); assert.equal(otherBothTest.test.length, 0); - const normal = await Test.findOne({ _id: otherBothEntry._id }).populate({ path: 'test' }); + const normal = await Test. + findOne({ _id: otherBothEntry._id }). + populate({ path: 'test' }); // should be empty because the original local field was _id and we created a doc with uuids assert.equal(normal.test.length, 0); }); diff --git a/types/index.d.ts b/types/index.d.ts index b1ce3eabffb..f0e3aee7833 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -401,7 +401,7 @@ declare module 'mongoose' { /** If `ref` is not nullish, this becomes a populated virtual. */ ref?: string | Function; - /** The local field to populate on if this is a populated virtual. */ + /** The local field to populate on if this is a populated virtual. */ localField?: string | ((this: HydratedDocType, doc: HydratedDocType) => string); /** The foreign field to populate on if this is a populated virtual. */ diff --git a/types/populate.d.ts b/types/populate.d.ts index 77575c6da0e..0db038014f9 100644 --- a/types/populate.d.ts +++ b/types/populate.d.ts @@ -3,39 +3,43 @@ declare module 'mongoose' { /** * Reference another Model */ - type PopulatedDoc< - PopulatedType, - RawId extends RefType = (PopulatedType extends { _id?: RefType; } ? NonNullable : Types.ObjectId) | undefined - > = PopulatedType | RawId; + type PopulatedDoc< + PopulatedType, + RawId extends RefType = (PopulatedType extends { _id?: RefType; } ? NonNullable : Types.ObjectId) | undefined + > = PopulatedType | RawId; - interface PopulateOptions { - /** space delimited path(s) to populate */ - path: string; - /** fields to select */ - select?: any; - /** query conditions to match */ - match?: any; - /** optional model to use for population */ - model?: string | Model; - /** optional query options like sort, limit, etc */ - options?: QueryOptions; - /** correct limit on populated array */ - perDocumentLimit?: number; - /** optional boolean, set to `false` to allow populating paths that aren't in the schema */ - strictPopulate?: boolean; - /** deep populate */ - populate?: string | PopulateOptions | (string | PopulateOptions)[]; - /** + interface PopulateOptions { + /** space delimited path(s) to populate */ + path: string; + /** fields to select */ + select?: any; + /** query conditions to match */ + match?: any; + /** optional model to use for population */ + model?: string | Model; + /** optional query options like sort, limit, etc */ + options?: QueryOptions; + /** correct limit on populated array */ + perDocumentLimit?: number; + /** optional boolean, set to `false` to allow populating paths that aren't in the schema */ + strictPopulate?: boolean; + /** deep populate */ + populate?: string | PopulateOptions | (string | PopulateOptions)[]; + /** * If true Mongoose will always set `path` to a document, or `null` if no document was found. * If false Mongoose will always set `path` to an array, which will be empty if no documents are found. * Inferred from schema by default. */ - justOne?: boolean; - /** transform function to call on every populated doc */ - transform?: (doc: any, id: any) => any; - } + justOne?: boolean; + /** transform function to call on every populated doc */ + transform?: (doc: any, id: any) => any; + /** Overwrite the schema-level local field to populate on if this is a populated virtual. */ + localField?: string; + /** Overwrite the schema-level foreign field to populate on if this is a populated virtual. */ + foreignField?: string; + } - interface PopulateOption { - populate?: string | string[] | PopulateOptions | PopulateOptions[]; - } + interface PopulateOption { + populate?: string | string[] | PopulateOptions | PopulateOptions[]; + } } From eab0d41e19b49fae2f132e76d7c0b9d626ff9e27 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 27 Nov 2022 11:45:14 -0500 Subject: [PATCH 110/112] fix: extra type check for foreignField --- lib/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/model.js b/lib/model.js index e94992ed637..bf027119582 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4727,7 +4727,7 @@ function populate(model, docs, options, callback) { } hasOne = true; - if (populateOptions.foreignField) { + if (typeof populateOptions.foreignField === 'string') { mod.foreignField.clear(); mod.foreignField.add(populateOptions.foreignField); } From 1751dad24c506a17e66aac1933e5c02089a35235 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 27 Nov 2022 13:02:37 -0500 Subject: [PATCH 111/112] test: improve tests --- test/schema.validation.test.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/schema.validation.test.js b/test/schema.validation.test.js index 8fc34312119..70f598fe3cc 100644 --- a/test/schema.validation.test.js +++ b/test/schema.validation.test.js @@ -1330,8 +1330,8 @@ describe('schema', function() { }); }); - it('Allows for doc to be passed as another parameter gh-12564', function(done) { - let document = ''; + it('Allows for doc to be passed as another parameter (gh-12564)', function(done) { + let document = null; const s = mongoose.Schema({ n: { type: String, @@ -1340,8 +1340,8 @@ describe('schema', function() { return v != null; }, message: function(properties, doc) { - document = doc.toString(); - return 'fail ' + properties.path + ' on doc ' + doc; + document = doc; + return 'fail ' + properties.path + ' on doc ' + doc._id; } } }, @@ -1351,8 +1351,9 @@ describe('schema', function() { const m = new M({ n: null, field: 'Yo' }); m.validate(function(error) { - assert.equal(error.errors['n'].message.includes(document), true); - assert.equal('fail n on doc ' + document, error.errors['n'].message); + assert.strictEqual(document, m); + assert.ok(error.errors['n'].message.includes(m._id)); + assert.equal('fail n on doc ' + m._id, error.errors['n'].message); done(); }); }); From 6f4fbeee672d79d2726cb161b67f3f22a5b76dd1 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 27 Nov 2022 13:03:25 -0500 Subject: [PATCH 112/112] feat: upgrade to mongodb node driver 4.12.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ea400a3989e..ce001cdc64a 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dependencies": { "bson": "^4.7.0", "kareem": "2.4.1", - "mongodb": "4.11.0", + "mongodb": "4.12.1", "mpath": "0.9.0", "mquery": "4.0.3", "ms": "2.1.3",