diff --git a/CHANGELOG.md b/CHANGELOG.md index 66b823f2ec7..07464045681 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +8.5.5 / 2024-08-28 +================== + * fix(populate): fix a couple of other places where Mongoose gets the document's _id with getters #14833 #14827 #14759 + * fix(discriminator): shallow clone Schema.prototype.obj before merging schemas to avoid modifying original obj #14821 + * types: fix schema type based on timestamps schema options value #14829 #14825 [ark23CIS](https://github.com/ark23CIS) + +8.5.4 / 2024-08-23 +================== + * fix: add empty string check for collection name passed #14806 [Shubham2552](https://github.com/Shubham2552) + * docs(model): add 'throw' as valid strict value for bulkWrite() and add some more clarification on throwOnValidationError #14809 + +7.8.1 / 2024-08-19 +================== + * fix(query): handle casting $switch in $expr #14761 + * docs(mongoose): remove out-of-date callback-based example for mongoose.connect() #14811 #14810 + 8.5.3 / 2024-08-13 ================== * fix(document): call required functions on subdocuments underneath nested paths with correct context #14801 #14788 @@ -20,6 +36,11 @@ * types: allow calling SchemaType.cast() without parent and init parameters #14756 #14748 #9076 * docs: fix a wrong example in v6 migration guide #14758 [abdelrahman-elkady](https://github.com/abdelrahman-elkady) +7.8.0 / 2024-07-23 +================== + * feat: add transactionAsyncLocalStorage option to opt in to automatically setting session on all transactions #14744 #14742 #14583 #13889 + * types(query): fix usage of "RawDocType" where "DocType" should be passed #14737 [hasezoey](https://github.com/hasezoey) + 8.5.1 / 2024-07-12 ================== * perf(model): performance improvements for insertMany() #14724 @@ -59,6 +80,10 @@ * types: add $documents pipeline stage and fix $unionWith type #14666 [nick-statsig](https://github.com/nick-statsig) * docs(findoneandupdate): improve example that shows findOneAndUpdate() returning doc before updates were applied #14671 #14670 +7.7.0 / 2024-06-18 +================== + * feat(model): add throwOnValidationError option for opting into getting MongooseBulkWriteError if all valid operations succeed in bulkWrite() and insertMany() #14599 #14587 #14572 #13410 + 8.4.3 / 2024-06-17 ================== * fix: remove 0x flamegraph files from release @@ -72,6 +97,16 @@ * types: avoid inferring Boolean, Buffer, ObjectId as Date in schema definitions under certain circumstances #14667 #14630 * docs: add note about parallelism in transations #14647 [fiws](https://github.com/fiws) +6.13.0 / 2024-06-06 +=================== + * feat(model): add throwOnValidationError option for opting into getting MongooseBulkWriteError if all valid operations succeed in bulkWrite() and insertMany() #14599 #14587 #14572 #13410 + +7.6.13 / 2024-06-05 +=================== + * fix(query): shallow clone $or and $and array elements to avoid mutating query filter arguments #14614 #14610 + * types: pass DocType down to subdocuments so HydratedSingleSubdocument and HydratedArraySubdocument toObject() returns correct type #14612 #14601 + * docs(migrating_to_7): add id setter to Mongoose 7 migration guide #14645 #13672 + 8.4.1 / 2024-05-31 ================== * fix: pass options to clone instead of get in applyVirtuals #14606 #14543 [andrews05](https://github.com/andrews05) @@ -79,6 +114,11 @@ * fix: ensure buildBulkWriteOperations target shard if shardKey is set #14622 #14621 [matlpriceshape](https://github.com/matlpriceshape) * types: pass DocType down to subdocuments so HydratedSingleSubdocument and HydratedArraySubdocument toObject() returns correct type #14612 #14601 +6.12.9 / 2024-05-24 +=================== + * fix(cast): cast $comment to string in query filters #14590 #14576 + * types(model): allow passing strict type checking override to create() #14571 #14548 + 7.6.12 / 2024-05-21 =================== * fix(array): avoid converting to $set when calling pull() on an element in the middle of the array #14531 #14502 @@ -559,6 +599,7 @@ ================== * perf: speed up mapOfSubdocs benchmark by 4x by avoiding unnecessary O(n^2) loop in getPathsToValidate() #13614 * feat: upgrade to MongoDB Node.js driver 5.7.0 #13591 + * feat: add `id` setter which allows modifying `_id` by setting `id` (Note this change was reverted in Mongoose 8) #13517 * feat: support generating custom cast error message with a function #13608 #3162 * feat(query): support MongoDB driver's includeResultMetadata option for findOneAndUpdate #13584 #13539 * feat(connection): add Connection.prototype.removeDb() for removing a related connection #13580 #11821 diff --git a/benchmarks/typescript/simple/package.json b/benchmarks/typescript/simple/package.json index ee74cdf4d70..6571d866d06 100644 --- a/benchmarks/typescript/simple/package.json +++ b/benchmarks/typescript/simple/package.json @@ -1,7 +1,7 @@ { "dependencies": { "mongoose": "file:../../../mongoose.tgz", - "typescript": "4.9.x" + "typescript": "5.5.x" }, "scripts": { "benchmark": "tsc --extendedDiagnostics" diff --git a/docs/async-await.md b/docs/async-await.md index 241d938a783..eb2d98ea405 100644 --- a/docs/async-await.md +++ b/docs/async-await.md @@ -82,7 +82,7 @@ async function doStuffWithUser() { } ``` -

Async/Await with Mongoose Queries

+## Async/Await with Mongoose Queries {#queries} Under the hood, [async/await is syntactic sugar](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await) over the Promise API. 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. diff --git a/docs/browser.md b/docs/browser.md index a32172bbdb2..43bc487384a 100644 --- a/docs/browser.md +++ b/docs/browser.md @@ -19,7 +19,7 @@ const mongoose = require('mongoose/browser'); import mongoose from 'mongoose/browser'; ``` -

Using the Browser Library

+## Using the Browser Library {#usage} Mongoose's browser library is very limited. The only use case it supports is validating documents as shown below. diff --git a/docs/connections.md b/docs/connections.md index e823e3e3f40..24164c01b8b 100644 --- a/docs/connections.md +++ b/docs/connections.md @@ -35,7 +35,7 @@ See the [mongodb connection string spec](http://www.mongodb.com/docs/manual/refe
  • Multi Tenant Connections
  • -

    Operation Buffering

    +## Operation Buffering {#buffering} Mongoose lets you start using your models immediately, without waiting for mongoose to establish a connection to MongoDB. @@ -95,7 +95,7 @@ const Model = mongoose.model('Test', schema); await Model.createCollection(); ``` -

    Error Handling

    +## Error Handling {#error-handling} There are two classes of errors that can occur with a Mongoose connection. @@ -129,7 +129,7 @@ mongoose.connection.on('error', err => { Note that Mongoose does not necessarily emit an 'error' event if it loses connectivity to MongoDB. You should listen to the `disconnected` event to report when Mongoose is disconnected from MongoDB. -

    Options

    +## Options {#options} The `connect` method also accepts an `options` object which will be passed on to the underlying MongoDB driver. @@ -158,7 +158,7 @@ Below are some of the options that are important for tuning Mongoose. * `serverSelectionTimeoutMS` - The MongoDB driver will try to find a server to send any given operation to, and keep retrying for `serverSelectionTimeoutMS` milliseconds. If not set, the MongoDB driver defaults to using `30000` (30 seconds). * `heartbeatFrequencyMS` - The MongoDB driver sends a heartbeat every `heartbeatFrequencyMS` to check on the status of the connection. A heartbeat is subject to `serverSelectionTimeoutMS`, so the MongoDB driver will retry failed heartbeats for up to 30 seconds by default. Mongoose only emits a `'disconnected'` event after a heartbeat has failed, so you may want to decrease this setting to reduce the time between when your server goes down and when Mongoose emits `'disconnected'`. We recommend you do **not** set this setting below 1000, too many heartbeats can lead to performance degradation. -

    serverSelectionTimeoutMS

    +## serverSelectionTimeoutMS {#serverselectiontimeoutms} The `serverSelectionTimeoutMS` option is extremely important: it controls how long the MongoDB Node.js driver will attempt to retry any operation before erroring out. This includes initial connection, like `await mongoose.connect()`, as well as any operations that make requests to MongoDB, like `save()` or `find()`. @@ -208,7 +208,7 @@ for (let i = 0; i < 3; ++i) { } ``` -

    Callback

    +## Callback {#callback} The `connect()` function also accepts a callback parameter and returns a [promise](promises.html). @@ -225,7 +225,7 @@ mongoose.connect(uri, options).then( ); ``` -

    Connection String Options

    +## Connection String Options {#connection-string-options} You can also specify driver options in your connection string as [parameters in the query string](https://en.wikipedia.org/wiki/Query_string) @@ -258,7 +258,7 @@ are closely associated with the hostname and authentication information. * `authSource` - The database to use when authenticating with `user` and `pass`. In MongoDB, [users are scoped to a database](https://www.mongodb.com/docs/manual/tutorial/manage-users-and-roles/). If you are getting an unexpected login failure, you may need to set this option. * `family` - Whether to connect using IPv4 or IPv6. This option passed to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. If you don't specify this option, the MongoDB driver will try IPv6 first and then IPv4 if IPv6 fails. If your `mongoose.connect(uri)` call takes a long time, try `mongoose.connect(uri, { family: 4 })` -

    Connection Events

    +## Connection Events {#connection-events} Connections inherit from [Node.js' `EventEmitter` class](https://nodejs.org/api/events.html#events_class_eventemitter), and emit events when something happens to the connection, like losing @@ -304,13 +304,13 @@ conn.on('disconnecting', () => console.log('disconnecting')); conn.on('close', () => console.log('close')); ``` -

    A note about keepAlive

    +## A note about keepAlive {#keepAlive} Before Mongoose 5.2.0, you needed to enable the `keepAlive` option to initiate [TCP keepalive](https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html) to prevent `"connection closed"` errors. However, `keepAlive` has been `true` by default since Mongoose 5.2.0, and the `keepAlive` is deprecated as of Mongoose 7.2.0. Please remove `keepAlive` and `keepAliveInitialDelay` options from your Mongoose connections. -

    Replica Set Connections

    +## Replica Set Connections {#replicaset_connections} To connect to a replica set you pass a comma delimited list of hosts to connect to rather than a single host. @@ -331,7 +331,7 @@ To connect to a single node replica set, specify the `replicaSet` option. mongoose.connect('mongodb://host1:port1/?replicaSet=rsName'); ``` -

    Server Selection

    +## Server Selection {#server-selection} The underlying MongoDB driver uses a process known as [server selection](https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst) to connect to MongoDB and send operations to MongoDB. If the MongoDB driver can't find a server to send an operation to after `serverSelectionTimeoutMS`, @@ -366,7 +366,7 @@ mongoose.connect(uri, { }).catch(err => console.log(err.reason)); ``` -

    Replica Set Host Names

    +## Replica Set Host Names {#replicaset-hostnames} MongoDB replica sets rely on being able to reliably figure out the domain name for each member. On Linux and OSX, the MongoDB server uses the output of the [`hostname` command](https://linux.die.net/man/1/hostname) to figure out the domain name to report to the replica set. @@ -399,7 +399,7 @@ if (err.name === 'MongooseServerSelectionError') { } ``` -

    Multi-mongos support

    +## Multi-mongos support {#mongos_connections} You can also connect to multiple [mongos](https://www.mongodb.com/docs/manual/reference/program/mongos/) instances for high availability in a sharded cluster. You do @@ -410,7 +410,7 @@ for high availability in a sharded cluster. You do mongoose.connect('mongodb://mongosA:27501,mongosB:27501', cb); ``` -

    Multiple connections

    +## Multiple connections {#multiple_connections} So far we've seen how to connect to MongoDB using Mongoose's default connection. Mongoose creates a *default connection* when you call `mongoose.connect()`. @@ -493,7 +493,7 @@ module.exports = conn; You can create separate files for each connection, like `connections/web.js` and `connections/mobile.js` if you want to create separate connections for your web API backend and your mobile API backend. Your business logic can then `require()` or `import` the connection it needs. -

    Connection Pools

    +## Connection Pools {#connection_pools} Each `connection`, whether created with `mongoose.connect` or `mongoose.createConnection` are all backed by an internal configurable @@ -512,7 +512,7 @@ mongoose.createConnection(uri); The connection pool size is important because [MongoDB currently can only process one operation per socket](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs). So `maxPoolSize` functions as a cap on the number of concurrent operations. -

    Multi Tenant Connections

    +## Multi Tenant Connections {#multi-tenant-connections} In the context of Mongoose, a multi-tenant architecture typically means a case where multiple different clients talk to MongoDB through a single Mongoose application. This typically means each client makes queries and executes updates through a single Mongoose application, but has a distinct MongoDB database within the same MongoDB cluster. @@ -592,6 +592,6 @@ app.get('/users/:tenantId', function(req, res) { app.listen(3000); ``` -

    Next Up

    +## Next Up {#next} 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 bb194674e19..d7a7936e1fe 100644 --- a/docs/deprecations.md +++ b/docs/deprecations.md @@ -5,7 +5,7 @@ that Mongoose users should be aware of. Mongoose provides options to work around these deprecation warnings, but you need to test whether these options cause any problems for your application. Please [report any issues on GitHub](https://github.com/Automattic/mongoose/issues/new). -

    Summary

    +## Summary {#summary} To fix all deprecation warnings, follow the below steps: @@ -13,7 +13,7 @@ To fix all deprecation warnings, follow the below steps: Read below for more a more detailed description of each deprecation warning. -

    rawResult

    +## `rawResult` {#rawresult} As of Mongoose 7.4.0, the `rawResult` option to `findOneAndUpdate()` is deprecated. You should instead use the `includeResultMetadata` option, which the MongoDB Node.js driver's new option that replaces `rawResult`. diff --git a/docs/documents.md b/docs/documents.md index 93cb1b9e9fe..20764c6dbef 100644 --- a/docs/documents.md +++ b/docs/documents.md @@ -13,7 +13,7 @@ to documents as stored in MongoDB. Each document is an instance of its
  • Overwriting
  • -

    Documents vs Models

    +## Documents vs Models {#documents-vs-models} [Document](api/document.html#Document) and [Model](api/model.html#Model) are distinct classes in Mongoose. The Model class is a subclass of the Document class. @@ -33,7 +33,7 @@ In Mongoose, a "document" generally means an instance of a model. You should not have to create an instance of the Document class without going through a model. -

    Retrieving

    +## Retrieving {#retrieving} When you load documents from MongoDB using model functions like [`findOne()`](api/model.html#model_Model-findOne), you get a Mongoose document back. @@ -46,7 +46,7 @@ doc instanceof mongoose.Model; // true doc instanceof mongoose.Document; // true ``` -

    Updating Using save()

    +## Updating Using `save()` {#updating-using-save} Mongoose documents track changes. You can modify a document using vanilla JavaScript assignments and Mongoose will convert it into [MongoDB update operators](https://www.mongodb.com/docs/manual/reference/operator/update/). @@ -81,7 +81,7 @@ doc.name = 'foo'; await doc.save(); // Throws DocumentNotFoundError ``` -

    Updating Using Queries

    +## Updating Using Queries {#updating-using-queries} The [`save()`](api/model.html#model_Model-save) function is generally the right way to update a document with Mongoose. With `save()`, you get full @@ -100,7 +100,7 @@ await MyModel.updateMany({}, { $set: { name: 'foo' } }); execute `save()` middleware. If you need save middleware and full validation, first query for the document and then `save()` it.* -

    Validating

    +## Validating {#validating} Documents are casted and validated before they are saved. Mongoose first casts values to the specified type and then validates them. Internally, Mongoose @@ -136,7 +136,7 @@ await Person.updateOne({}, { age: -1 }, { runValidators: true }); Read the [validation](validation.html) guide for more details. -

    Overwriting

    +## Overwriting {#overwriting} There are 2 different ways to overwrite a document (replacing all keys in the document). One way is to use the diff --git a/docs/geojson.md b/docs/geojson.md index c094894b249..b42461056f3 100644 --- a/docs/geojson.md +++ b/docs/geojson.md @@ -5,7 +5,7 @@ polygons. [MongoDB has excellent support for geospatial queries](http://thecodeb on GeoJSON objects. Let's take a look at how you can use Mongoose to store and query GeoJSON objects. -

    Point Schema

    +## Point Schema {#points} The most simple structure in GeoJSON is a point. Below is an example point representing the approximate location of [San Francisco](https://www.google.com/maps/@37.7,-122.5,9z). @@ -64,7 +64,7 @@ const citySchema = new mongoose.Schema({ }); ``` -

    Polygon Schema

    +## Polygon Schema {#polygons} GeoJSON polygons let you define an arbitrary shape on a map. For example, the below polygon is a GeoJSON rectangle that approximates the border @@ -106,7 +106,7 @@ const citySchema = new mongoose.Schema({ }); ``` -

    Geospatial Queries with Mongoose

    +## Geospatial Queries with Mongoose {#querying} Mongoose queries support the same [geospatial query operators](http://thecodebarbarian.com/80-20-guide-to-mongodb-geospatial-queries) that the MongoDB driver does. For example, the below script saves a @@ -128,7 +128,7 @@ that's a shorthand for `$geoWithin`. [require:geojson.*within helper] ``` -

    Geospatial Indexes

    +## Geospatial Indexes {#geospatial-indexes} MongoDB supports [2dsphere indexes](https://www.mongodb.com/docs/manual/core/2dsphere/) for speeding up geospatial queries. Here's how you can define diff --git a/docs/guide.md b/docs/guide.md index 9c2766c311b..fa653acc4dd 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -6,7 +6,7 @@ If you are migrating from 7.x to 8.x please take a moment to read the [migration -

    Defining your schema

    +## Defining your schema {#definition} Everything in Mongoose starts with a Schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection. @@ -88,7 +88,7 @@ properties, they also define document [instance methods](#methods), [static Model methods](#statics), [compound indexes](#indexes), and document lifecycle hooks called [middleware](middleware.html). -

    Creating a model

    +## Creating a model {#models} To use our schema definition, we need to convert our `blogSchema` into a [Model](models.html) we can work with. @@ -99,7 +99,7 @@ const Blog = mongoose.model('Blog', blogSchema); // ready to go! ``` -

    Ids

    +## Ids By default, Mongoose adds an `_id` property to your schemas. @@ -165,7 +165,7 @@ const nestedSchema = new Schema({ }); ``` -

    Instance methods

    +## Instance methods {#methods} Instances of `Models` are [documents](documents.html). Documents have many of their own [built-in instance methods](api/document.html). @@ -206,7 +206,7 @@ dog.findSimilarTypes((err, dogs) => { * 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/schema.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

    +## Statics {#statics} You can also add static functions to your model. There are three equivalent ways to add a static: @@ -243,7 +243,7 @@ animals = animals.concat(await Animal.findByBreed('Poodle')); Do **not** declare statics 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 the above examples will not work because of the value of `this`. -

    Query Helpers

    +## Query Helpers {#query-helpers} You can also add query helper functions, which are like instance methods but for mongoose queries. Query helper methods let you extend mongoose's @@ -279,7 +279,7 @@ Animal.findOne().byName('fido').exec((err, animal) => { }); ``` -

    Indexes

    +## Indexes {#indexes} MongoDB supports [secondary indexes](http://www.mongodb.com/docs/manual/indexes/). With mongoose, we define these indexes within our `Schema` [at](api/schematype.html#schematype_SchemaType-index) [the](api/schematype.html#schematype_SchemaType-unique) [path](api/schematype.html#schematype_SchemaType-sparse) [level](api/schemadateoptions.html#schemadateoptions_SchemaDateOptions-expires) or the `schema` level. @@ -332,7 +332,7 @@ Animal.on('index', error => { See also the [Model#ensureIndexes](api/model.html#model_Model-ensureIndexes) method. -

    Virtuals

    +## Virtuals {#virtuals} [Virtuals](api/schema.html#schema_Schema-virtual) are document properties that you can get and set but that do not get persisted to MongoDB. The getters @@ -475,7 +475,7 @@ Since virtuals are not stored in MongoDB, you can't query with them. You can [learn more about virtuals here](https://masteringjs.io/tutorials/mongoose/virtuals). -

    Aliases

    +## Aliases {#aliases} Aliases are a particular type of virtual where the getter and setter seamlessly get and set another property. This is handy for saving network @@ -510,7 +510,7 @@ nested path aliases inline as long as you use the full nested path [require:gh-6671] ``` -

    Options

    +## Options {#options} Schemas have a few configurable options which can be passed to the constructor or to the `set` method: @@ -526,6 +526,7 @@ schema.set(option, value); Valid options: + * [autoIndex](#autoIndex) * [autoCreate](#autoCreate) * [bufferCommands](#bufferCommands) @@ -560,8 +561,9 @@ Valid options: * [query](#query-helpers) * [autoSearchIndex](#autoSearchIndex) * [readConcern](#readConcern) + -

    option: autoIndex

    +## option: autoIndex {#autoIndex} By default, Mongoose's [`init()` function](api/model.html#model_Model-init) creates all the indexes defined in your model's schema by calling @@ -580,7 +582,7 @@ Clock.ensureIndexes(callback); The `autoIndex` option is set to `true` by default. You can change this default by setting [`mongoose.set('autoIndex', false);`](api/mongoose.html#mongoose_Mongoose-set) -

    option: autoCreate

    +## option: autoCreate {#autoCreate} Before Mongoose builds indexes, it calls `Model.createCollection()` to create the underlying collection in MongoDB by default. 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 @@ -605,7 +607,7 @@ const Test = mongoose.model('Test', schema); await Test.createCollection(); ``` -

    option: bufferCommands

    +## option: bufferCommands {#bufferCommands} By default, mongoose buffers commands when the connection goes down until the driver manages to reconnect. To disable buffering, set `bufferCommands` @@ -623,7 +625,7 @@ mongoose.set('bufferCommands', true); const schema = new Schema({ /* ... */ }, { bufferCommands: false }); ``` -

    option: bufferTimeoutMS

    +## option: bufferTimeoutMS {#bufferTimeoutMS} If `bufferCommands` is on, this option sets the maximum amount of time Mongoose buffering will wait before throwing an error. If not specified, Mongoose will use 10000 (10 seconds). @@ -633,7 +635,7 @@ throwing an error. If not specified, Mongoose will use 10000 (10 seconds). const schema = new Schema({ /* ... */ }, { bufferTimeoutMS: 1000 }); ``` -

    option: capped

    +## option: capped {#capped} Mongoose supports MongoDBs [capped](https://www.mongodb.com/docs/manual/core/capped-collections/) collections. To specify the underlying MongoDB collection be `capped`, set @@ -652,7 +654,7 @@ In this case you must explicitly pass the `size` option, which is required. new Schema({ /* ... */ }, { capped: { size: 1024, max: 1000, autoIndexId: true } }); ``` -

    option: collection

    +## option: collection {#collection} Mongoose by default produces a collection name by passing the model name to the `utils.toCollectionName` method. @@ -663,7 +665,7 @@ for your collection. const dataSchema = new Schema({ /* ... */ }, { collection: 'data' }); ``` -

    option: discriminatorKey

    +## option: discriminatorKey {#discriminatorKey} 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 @@ -682,7 +684,7 @@ const doc = new PersonModel({ name: 'James T. Kirk' }); doc.type; // 'Person' ``` -

    option: excludeIndexes

    +## option: excludeIndexes {#excludeIndexes} When `excludeIndexes` is `true`, Mongoose will not create indexes from the given subdocument schema. This option only works when the schema is used in a subdocument path or document array path, Mongoose ignores this option if set on the top-level schema for a model. @@ -706,7 +708,7 @@ const User = new Schema({ }); ``` -

    option: id

    +## option: id {#id} Mongoose assigns each of your schemas an `id` virtual getter by default which returns the document's `_id` field cast to a string, or in the case of @@ -727,7 +729,7 @@ const p = new Page({ name: 'mongodb.org' }); console.log(p.id); // undefined ``` -

    option: _id

    +## option: _id {#_id} Mongoose assigns each of your schemas an `_id` field by default if one is not passed into the [Schema](api/schema.html#schema_Schema) constructor. @@ -757,7 +759,7 @@ Model.create({ children: [{ name: 'Luke' }] }, (error, doc) => { }); ``` -

    option: minimize

    +## option: minimize {#minimize} Mongoose will, by default, "minimize" schemas by removing empty objects. @@ -802,7 +804,7 @@ sam.inventory.barrowBlade = 1; sam.$isEmpty('inventory'); // false ``` -

    option: read

    +## option: read {#read} Allows setting [query#read](api/query.html#query_Query-read) options at the schema level, providing us a way to apply default @@ -838,7 +840,7 @@ const schema = new Schema({ /* ... */ }, { read: ['nearest', { disk: 'ssd' }] }) mongoose.model('JellyBean', schema); ``` -

    option: writeConcern

    +## option: writeConcern {#writeConcern} Allows setting [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) at the schema level. @@ -853,7 +855,7 @@ const schema = new Schema({ name: String }, { }); ``` -

    option: shardKey

    +## option: shardKey {#shardKey} The `shardKey` option is used when we have a [sharded MongoDB architecture](https://www.mongodb.com/docs/manual/sharding/). Each sharded collection is given a shard key which must be present in all @@ -867,7 +869,7 @@ new Schema({ /* ... */ }, { shardKey: { tag: 1, name: 1 } }); *Note that Mongoose does not send the `shardcollection` command for you. You must configure your shards yourself.* -

    option: strict

    +## option: strict {#strict} The strict option, (enabled by default), ensures that values passed to our model constructor that were not specified in our schema do not get saved to @@ -918,7 +920,7 @@ thing.iAmNotInTheSchema = true; thing.save(); // iAmNotInTheSchema is never saved to the db ``` -

    option: strictQuery

    +## option: strictQuery {#strictQuery} Mongoose supports a separate `strictQuery` option to avoid strict mode for query filters. This is because empty query filters cause Mongoose to return all documents in the model, which can cause issues. @@ -970,10 +972,12 @@ However, you can override this behavior globally: mongoose.set('strictQuery', true); ``` -

    option: toJSON

    +## option: toJSON {#toJSON} + Exactly the same as the [toObject](#toObject) option but only applies when the document's [`toJSON` method](https://thecodebarbarian.com/what-is-the-tojson-function-in-javascript.html) is called. + ```javascript const schema = new Schema({ name: String }); @@ -991,7 +995,7 @@ console.log(JSON.stringify(m)); // { "_id": "504e0cd7dd992d9be2f20b6f", "name": To see all available `toJSON/toObject` options, read [this](api/document.html#document_Document-toObject). -

    option: toObject

    +## option: toObject {#toObject} Documents have a [toObject](api/document.html#document_Document-toObject) method which converts the mongoose document into a plain JavaScript object. This @@ -1015,7 +1019,7 @@ console.log(m); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my na To see all available `toObject` options, read [this](api/document.html#document_Document-toObject). -

    option: typeKey

    +## option: typeKey {#typeKey} By default, if you have an object with key 'type' in your schema, mongoose will interpret it as a type declaration. @@ -1038,7 +1042,7 @@ const schema = new Schema({ }, { typeKey: '$type' }); // A '$type' key means this object is a type declaration ``` -

    option: validateBeforeSave

    +## option: validateBeforeSave {#validateBeforeSave} By default, documents are automatically validated before they are saved to the database. This is to prevent saving an invalid document. If you want to @@ -1059,7 +1063,7 @@ m.validate(function(err) { m.save(); // Succeeds despite being invalid ``` -

    option: versionKey

    +## option: versionKey {#versionKey} The `versionKey` is a property set on each document when first created by Mongoose. This keys value contains the internal @@ -1100,7 +1104,9 @@ doc2.set('comments.1.body', 'new comment'); await doc2.save(); ``` -If you need optimistic concurrency support for `save()`, you can set the [`optimisticConcurrency` option](#optimisticConcurrency) + +If you need optimistic concurrency support for `save()`, you can set the [`optimisticConcurrency` option](#optimisticConcurrency). + Document versioning can also be disabled by setting the `versionKey` to `false`. @@ -1137,7 +1143,7 @@ schema.pre('findOneAndUpdate', function() { }); ``` -

    option: optimisticConcurrency

    +## option: optimisticConcurrency {#optimisticConcurrency} [Optimistic concurrency](https://en.wikipedia.org/wiki/Optimistic_concurrency_control) is a strategy to ensure the document you're updating didn't change between when you loaded it using `find()` or `findOne()`, and when @@ -1201,7 +1207,7 @@ house.status = 'APPROVED'; await house.save(); ``` -

    option: collation

    +## option: collation {#collation} Sets a default [collation](https://www.mongodb.com/docs/manual/reference/collation/) for every query and aggregation. [Here's a beginner-friendly overview of collations](http://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations). @@ -1223,7 +1229,7 @@ MyModel.create([{ name: 'val' }, { name: 'Val' }]). }); ``` -

    option: timeseries

    +## option: timeseries {#timeseries} If you set the `timeseries` option on a schema, Mongoose will create a [timeseries collection](https://www.mongodb.com/docs/manual/core/timeseries-collections/) for any model that you create from that schema. @@ -1242,7 +1248,7 @@ const schema = Schema({ name: String, timestamp: Date, metadata: Object }, { const Test = db.model('Test', schema); ``` -

    option: skipVersioning

    +## option: skipVersioning {#skipVersioning} `skipVersioning` allows excluding paths from versioning (i.e., the internal revision will not be incremented even if these paths are updated). DO NOT @@ -1255,7 +1261,7 @@ thing.dontVersionMe.push('hey'); thing.save(); // version is not incremented ``` -

    option: timestamps

    +## option: timestamps {#timestamps} The `timestamps` option tells Mongoose to assign `createdAt` and `updatedAt` fields to your schema. The type assigned is [Date](schematypes.html#dates). @@ -1325,7 +1331,7 @@ const schema = Schema({ }); ``` -

    option: pluginTags

    +## option: pluginTags {#pluginTags} Mongoose supports defining global plugins, plugins that apply to all schemas. @@ -1358,11 +1364,7 @@ mongoose.plugin(function myPlugin(schema) { }, { tags: ['useMetaPlugin'] }); ``` -

    - - option: selectPopulatedPaths - -

    +## option: selectPopulatedPaths {#selectPopulatedPaths} By default, Mongoose will automatically `select()` any populated paths for you, unless you explicitly exclude them. @@ -1396,11 +1398,7 @@ const Book = mongoose.model('Book', bookSchema); const doc = await Book.findOne().select('title').populate('author'); ``` -

    - - option: storeSubdocValidationError - -

    +## option: storeSubdocValidationError {#storeSubdocValidationError} For legacy reasons, when there is a validation error in subpath of a single nested schema, Mongoose will record that there was a validation error @@ -1431,11 +1429,7 @@ const Parent = mongoose.model('Parent', parentSchema); new Parent({ child: {} }).validateSync().errors; ``` -

    - - option: collectionOptions - -

    +## option: collectionOptions {#collectionOptions} Options like [`collation`](#collation) and [`capped`](#capped) affect the options Mongoose passes to MongoDB when creating a new collection. Mongoose schemas support most [MongoDB `createCollection()` options](https://www.mongodb.com/docs/manual/reference/method/db.createCollection/), but not all. @@ -1455,14 +1449,12 @@ const Test = mongoose.model('Test', schema); await Test.createCollection(); ``` -

    - - option: autoSearchIndex - -

    +## option: autoSearchIndex {#autoSearchIndex} + Similar to [`autoIndex`](#autoIndex), except for automatically creates any [Atlas search indexes](https://www.mongodb.com/docs/atlas/atlas-search/create-index/) defined in your schema. Unlike `autoIndex`, this option defaults to false. + ```javascript const schema = new Schema({ name: String }, { autoSearchIndex: true }); @@ -1474,14 +1466,12 @@ schema.searchIndex({ const Test = mongoose.model('Test', schema); ``` -

    - - option: readConcern - -

    +## option: readConcern {#readConcern} + [Read concerns](https://www.mongodb.com/docs/manual/reference/read-concern/) are similar to [`writeConcern`](#writeConcern), but for read operations like `find()` and `findOne()`. To set a default `readConcern`, pass the `readConcern` option to the schema constructor as follows. + ```javascript const eventSchema = new mongoose.Schema( @@ -1492,7 +1482,7 @@ const eventSchema = new mongoose.Schema( ); ``` -

    With ES6 Classes

    +## With ES6 Classes {#es6-classes} 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): @@ -1518,12 +1508,12 @@ console.log(schema.statics); // { myStatic: [Function: myStatic] } console.log(schema.virtuals); // { myVirtual: VirtualType { ... } } ``` -

    Pluggable

    +## Pluggable {#plugins} 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 {#further-reading} Here's an [alternative introduction to Mongoose schemas](https://masteringjs.io/tutorials/mongoose/schema). @@ -1540,6 +1530,6 @@ by Christian Kvalheim, the original author of the [MongoDB Node.js driver](http: This book shows you how to implement performant schemas for a laundry list of use cases, including e-commerce, wikis, and appointment bookings. -

    Next Up

    +## Next Up {#next} Now that we've covered `Schemas`, let's take a look at [SchemaTypes](schematypes.html). diff --git a/docs/jest.md b/docs/jest.md index 9b492f5b76c..aa1669ef329 100644 --- a/docs/jest.md +++ b/docs/jest.md @@ -12,7 +12,7 @@ env SUPPRESS_JEST_WARNINGS=1 npm test If you choose to delve into dangerous waters and test Mongoose apps with Jest, here's what you need to know: - +## Recommended `testEnvironment` {#recommended-testenvironment} 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. @@ -32,7 +32,7 @@ module.exports = { }; ``` -

    Timer Mocks

    +## Timer Mocks {#timer-mocks} Absolutely do **not** use [timer mocks](https://jestjs.io/docs/en/timer-mocks.html) when testing Mongoose apps. This is especially important if you're using Jest `>=25`, which stubs out `process.nextTick()`. @@ -71,7 +71,7 @@ const sinon = require('sinon'); sinon.stub(time, 'setTimeout'); ``` -

    globalSetup and globalTeardown

    +## `globalSetup` and `globalTeardown` {#globalsetup-and-globalteardown} Do **not** use `globalSetup` to call `mongoose.connect()` or `mongoose.createConnection()`. Jest runs `globalSetup` in diff --git a/docs/middleware.md b/docs/middleware.md index 03a40983a7a..b74452affbd 100644 --- a/docs/middleware.md +++ b/docs/middleware.md @@ -129,7 +129,7 @@ childSchema.pre('findOneAndUpdate', function() { }); ``` -

    Pre

    +## Pre {#pre} Pre middleware functions are executed one after another, when each middleware calls `next`. @@ -175,7 +175,7 @@ schema.pre('save', function(next) { }); ``` -

    Use Cases

    +### Use Cases Middleware are useful for atomizing model logic. Here are some other ideas: @@ -184,7 +184,7 @@ Middleware are useful for atomizing model logic. Here are some other ideas: * asynchronous defaults * asynchronous tasks that a certain action triggers -

    Errors in Pre Hooks

    +### Errors in Pre Hooks {#error-handling} If any pre hook errors out, mongoose will not execute subsequent middleware or the hooked function. Mongoose will instead pass an error to the callback @@ -228,7 +228,7 @@ myDoc.save(function(err) { Calling `next()` multiple times is a no-op. If you call `next()` with an error `err1` and then throw an error `err2`, mongoose will report `err1`. -

    Post middleware

    +## Post middleware {#post} [post](api.html#schema_Schema-post) middleware are executed *after* the hooked method and all of its `pre` middleware have completed. @@ -248,7 +248,7 @@ schema.post('deleteOne', function(doc) { }); ``` -

    Asynchronous Post Hooks

    +## Asynchronous Post Hooks {#post-async} If your post hook function takes at least 2 parameters, mongoose will assume the second parameter is a `next()` function that you will call to trigger the next middleware in the sequence. @@ -288,7 +288,7 @@ schema.post('save', async function(doc, next) { }); ``` -

    Define Middleware Before Compiling Models

    +## Define Middleware Before Compiling Models {#defining} Calling `pre()` or `post()` after [compiling a model](models.html#compiling) does **not** work in Mongoose in general. For example, the below `pre('save')` @@ -338,7 +338,7 @@ const schema = new mongoose.Schema({ name: String }); module.exports = mongoose.model('User', schema); ``` -

    Save/Validate Hooks

    +## Save/Validate Hooks {#order} The `save()` function triggers `validate()` hooks, because mongoose has a built-in `pre('save')` hook that calls `validate()`. This means @@ -360,7 +360,7 @@ schema.post('save', function() { }); ``` -

    Accessing Parameters in Middleware

    +## Accessing Parameters in Middleware {#accessing-parameters-in-middleware} Mongoose provides 2 ways to get information about the function call that triggered the middleware. For query middleware, we recommend using `this`, which will be a [Mongoose Query instance](api/query.html). @@ -393,7 +393,7 @@ const doc = new User({ name: 'John', age: 30 }); await doc.save({ validateModifiedOnly: true }); ``` -

    Naming Conflicts

    +## Naming Conflicts {#naming} Mongoose has both query and document hooks for `deleteOne()`. @@ -447,7 +447,7 @@ await doc.validate(); await Test.find().validate(); ``` -

    Notes on findAndUpdate() and Query Middleware

    +## Notes on `findAndUpdate()` and Query Middleware {#notes} Pre and post `save()` hooks are **not** executed on `update()`, `findOneAndUpdate()`, etc. You can see a more detailed discussion why in @@ -514,7 +514,7 @@ await doc.updateOne({ $set: { name: 'test' } }); // Prints "Updating" await Model.updateOne({}, { $set: { name: 'test' } }); ``` -

    Error Handling Middleware

    +## Error Handling Middleware {#error-handling-middleware} Middleware execution normally stops the first time a piece of middleware calls `next()` with an error. However, there is a special kind of post @@ -577,7 +577,7 @@ Error handling middleware can transform an error, but it can't remove the error. Even if you call `next()` with no error as shown above, the function call will still error out. -

    Aggregation Hooks

    +## Aggregation Hooks {#aggregate} You can also define hooks for the [`Model.aggregate()` function](api/model.html#model_Model-aggregate). In aggregation middleware functions, `this` refers to the [Mongoose `Aggregate` object](api/aggregate.html#Aggregate). @@ -599,7 +599,7 @@ lets you access the MongoDB aggregation pipeline that Mongoose will send to the MongoDB server. It is useful for adding stages to the beginning of the pipeline from middleware. -

    Synchronous Hooks

    +## Synchronous Hooks {#synchronous} Certain Mongoose hooks are synchronous, which means they do **not** support functions that return promises or receive a `next()` callback. Currently, @@ -618,7 +618,7 @@ rejections. [require:post init hooks.*error] ``` -

    Next Up

    +## Next Up {#next} Now that we've covered middleware, let's take a look at Mongoose's approach 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 2f892993ff8..06d60e81fb3 100644 --- a/docs/migrating_to_5.md +++ b/docs/migrating_to_5.md @@ -41,13 +41,13 @@ If you're still on Mongoose 3.x, please read the [Mongoose 3.x to 4.x migration * [`bulkWrite()` results](#bulkwrite-results) * [Strict SSL validation](#strict-ssl-validation) -

    Version Requirements

    +## Version Requirements {#version-requirements} Mongoose now requires Node.js >= 4.0.0 and MongoDB >= 3.0.0. [MongoDB 2.6](https://www.mongodb.com/blog/post/mongodb-2-6-end-of-life) and [Node.js < 4](https://github.com/nodejs/Release) where both EOL-ed in 2016. -

    Query Middleware

    +## Query Middleware {#query-middleware} Query middleware is now compiled when you call `mongoose.model()` or `db.model()`. If you add query middleware after calling `mongoose.model()`, that middleware will **not** get called. @@ -63,9 +63,7 @@ MyModel.find().exec(function() { }); ``` -

    - Promises and Callbacks for mongoose.connect() -

    +## Promises and Callbacks for `mongoose.connect()` {#promises-and-callbacks} `mongoose.connect()` and `mongoose.disconnect()` now return a promise if no callback specified, or `null` otherwise. It does **not** return the mongoose singleton. @@ -80,9 +78,7 @@ mongoose.connect('mongodb://127.0.0.1:27017/test'); mongoose.model('Test', new Schema({})); ``` -

    - Connection Logic and useMongoClient -

    +## Connection Logic and `useMongoClient` {#connection-logic} The [`useMongoClient` option](/docs/4.x/docs/connections.html#use-mongo-client) was removed in Mongoose 5, it is now always `true`. As a consequence, Mongoose 5 @@ -97,9 +93,7 @@ examples of `mongoose.connect()` calls that do **not** work in Mongoose 5.x. In Mongoose 5.x, the first parameter to `mongoose.connect()` and `mongoose.createConnection()`, if specified, **must** be a [MongoDB connection string](https://www.mongodb.com/docs/manual/reference/connection-string/). The connection string and options are then passed down to [the MongoDB Node.js driver's `MongoClient.connect()` function](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html#.connect). Mongoose does not modify the connection string, although `mongoose.connect()` and `mongoose.createConnection()` support a [few additional options in addition to the ones the MongoDB driver supports](http://mongoosejs.com/docs/connections.html#options). -

    - Setter Order -

    +## Setter Order {#setter-order} Setters run in reverse order in 4.x: @@ -119,9 +113,7 @@ schema.path('name'). set(() => console.log('This will print 2nd')); ``` -

    - Checking if a path is populated -

    +## Checking if a path is populated {#id-getter} Mongoose 5.1.0 introduced an `_id` getter to ObjectIds that lets you get an ObjectId regardless of whether a path is populated. @@ -151,9 +143,7 @@ As a consequence, checking whether `blogPost.author._id` is [no longer viable as Note that you can call `mongoose.set('objectIdGetter', false)` to change this behavior. -

    - Return Values for remove() and deleteX() -

    +## Return Values for `remove()` and `deleteX()` {#return-value-for-delete} `deleteOne()`, `deleteMany()`, and `remove()` now resolve to the result object rather than the full [driver `WriteOpResult` object](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~writeOpCallback). @@ -165,9 +155,7 @@ MyModel.deleteMany().then(res => console.log(res.result.n)); MyModel.deleteMany().then(res => res.n); ``` -

    - Aggregation Cursors -

    +## Aggregation Cursors {#aggregation-cursors} The `useMongooseAggCursor` option from 4.x is now always on. This is the new syntax for aggregation cursors in mongoose 5: @@ -185,23 +173,17 @@ const cursorWithOptions = MyModel. exec(); ``` -

    - geoNear -

    +## `geoNear` {#geonear} `Model.geoNear()` has been removed because the [MongoDB driver no longer supports it](https://github.com/mongodb/node-mongodb-native/blob/4bac63ce7b9e9fff87c31c5a27d78bcdaca12669/etc/notes/CHANGES_3.0.0.md#geonear-command-helper) -

    - Required URI encoding of connection strings -

    +## Required URI encoding of connection strings {#uri-encoding} Due to changes in the MongoDB driver, connection strings must be URI encoded. If they are not, connections may fail with an illegal character message. -

    - Passwords which contain certain characters -

    +## Passwords which contain certain characters {#password-characters} See a [full list of affected characters](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding). @@ -230,9 +212,7 @@ mongoose.connect(encodeMongoURI(mongodbConnectString)); The function above is safe to use whether the existing string is already encoded or not. -

    - Domain sockets -

    +## Domain sockets {#domain-sockets} Domain sockets must be URI encoded. For example: @@ -247,9 +227,7 @@ const host = encodeURIComponent('/tmp/mongodb-27017.sock'); mongoose.createConnection(`mongodb://aaron:psw@${host}/fake`); ``` -

    - toObject() Options -

    +## `toObject()` Options {#toobject-options} The `options` parameter to `toObject()` and `toJSON()` merge defaults rather than overwriting them. @@ -267,9 +245,7 @@ const doc = new MyModel({ name: 'test' }); console.log(doc.toJSON({ minimize: false }).answer); ``` -

    - Aggregate Parameters -

    +## Aggregate Parameters {#aggregate-parameters} `aggregate()` no longer accepts a spread, you **must** pass your aggregation pipeline as an array. The below code worked in 4.x: @@ -283,9 +259,7 @@ The above code does **not** work in 5.x, you **must** wrap the `$match` and `$sk MyModel.aggregate([{ $match: { isDeleted: false } }, { $skip: 10 }]).exec(cb); ``` -

    - Boolean Casting -

    +## Boolean Casting {#boolean-casting} By default, mongoose 4 would coerce any value to a boolean without error. @@ -316,9 +290,7 @@ And the following values to `false`: All other values will cause a `CastError` -

    - Query Casting -

    +## Query Casting {#query-casting} Casting for `update()`, `updateOne()`, `updateMany()`, `replaceOne()`, `remove()`, `deleteOne()`, and `deleteMany()` doesn't happen until `exec()`. @@ -334,9 +306,7 @@ query helpers have ran. It also makes it possible to set the `overwrite` option User.where({ name: 'Bar' }).update({ name: 'Baz' }).setOptions({ overwrite: true }); ``` -

    - Post Save Hooks Get Flow Control -

    +## Post Save Hooks Get Flow Control {#post-save-flow-control} Post hooks now get flow control, which means async post save hooks and child document post save hooks execute **before** your `save()` callback. @@ -363,21 +333,15 @@ m.save(function() { }); ``` -

    - The $pushAll Operator -

    +## The `$pushAll` Operator {#pushall} `$pushAll` is no longer supported and no longer used internally for `save()`, since it has been [deprecated since MongoDB 2.4](https://www.mongodb.com/docs/manual/reference/operator/update/pushAll/). Use `$push` with `$each` instead. -

    - Always Use Forward Key Order -

    +## Always Use Forward Key Order {#retain-key-order} The `retainKeyOrder` option was removed, mongoose will now always retain the same key position when cloning objects. If you have queries or indexes that rely on reverse key order, you will have to change them. -

    - Run setters on queries -

    +## Run setters on queries {#run-setters-on-queries} Setters now run on queries by default, and the old `runSettersOnQuery` option has been removed. @@ -390,69 +354,49 @@ const Model = mongoose.model('Test', schema); Model.find({ email: 'FOO@BAR.BAZ' }); // Converted to `find({ email: 'foo@bar.baz' })` ``` -

    - Pre-compiled Browser Bundle -

    +## Pre-compiled Browser Bundle {#browser-bundle} We no longer have a pre-compiled version of mongoose for the browser. If you want to use mongoose schemas in the browser, you need to build your own bundle with browserify/webpack. -

    - Save Errors -

    +## Save Errors {#save-errors} The `saveErrorIfNotFound` option was removed, mongoose will now always error out from `save()` if the underlying document was not found -

    - Init hook signatures -

    +## Init hook signatures {#init-hooks} `init` hooks are now fully synchronous and do not receive `next()` as a parameter. `Document.prototype.init()` no longer takes a callback as a parameter. It was always synchronous, just had a callback for legacy reasons. -

    - numAffected and save() -

    +## `numAffected` and `save()` {#save-num-affected} `doc.save()` no longer passes `numAffected` as a 3rd param to its callback. -

    - remove() and debouncing -

    +## `remove()` and debouncing {#remove-debounce} `doc.remove()` no longer debounces -

    - getPromiseConstructor() -

    +## `getPromiseConstructor()` {#get-promise-constructor} `getPromiseConstructor()` is gone, just use `mongoose.Promise`. -

    - Passing Parameters from Pre Hooks -

    +## Passing Parameters from Pre Hooks {#pre-hook-params} You cannot pass parameters to the next pre middleware in the chain using `next()` in mongoose 5.x. In mongoose 4, `next('Test')` in pre middleware would call the next middleware with 'Test' as a parameter. Mongoose 5.x has removed support for this. -

    - required validator for arrays -

    +## `required` validator for arrays {#array-required} In mongoose 5 the `required` validator only verifies if the value is an array. That is, it will **not** fail for *empty* arrays as it would in mongoose 4. -

    - debug output defaults to stdout instead of stderr -

    +## debug output defaults to stdout instead of stderr {#debug-output} In mongoose 5 the default debug function uses `console.info()` to display messages instead of `console.error()`. -

    - Overwriting filter properties -

    +## Overwriting filter properties {#overwrite-filter} In Mongoose 4.x, overwriting a filter property that's a primitive with one that is an object would silently fail. For example, the below code would ignore the `where()` and be equivalent to `Sport.find({ name: 'baseball' })` @@ -462,9 +406,7 @@ Sport.find({ name: 'baseball' }).where({ name: { $ne: 'softball' } }); In Mongoose 5.x, the above code will correctly overwrite `'baseball'` with `{ $ne: 'softball' }` -

    - bulkWrite() results -

    +## `bulkWrite()` results {#bulkwrite-results} 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](api/model.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). @@ -536,9 +478,7 @@ BulkWriteResult { n: 1 } ``` -

    - Strict SSL Validation -

    +## Strict SSL Validation {#strict-ssl-validation} The most recent versions of the [MongoDB Node.js driver use strict SSL validation by default](http://mongodb.github.io/node-mongodb-native/3.5/tutorials/connect/tls/), which may lead to errors if you're using [self-signed certificates](https://github.com/Automattic/mongoose/issues/9147). diff --git a/docs/migrating_to_6.md b/docs/migrating_to_6.md index f0b91a5f9b8..9455c83577c 100644 --- a/docs/migrating_to_6.md +++ b/docs/migrating_to_6.md @@ -54,11 +54,11 @@ If you're still on Mongoose 4.x, please read the [Mongoose 4.x to 5.x migration * [Removed `reconnectTries` and `reconnectInterval` options](#removed-reconnecttries-and-reconnectinterval-options) * [MongoDB Driver's New URL Parser Incompatible with Some npm Packages](#mongodb-drivers-new-url-parser-incompatible-with-some-npm-packages) -

    Version Requirements

    +## Version Requirements {#version-requirements} Mongoose now requires Node.js >= 12.0.0. Mongoose still supports MongoDB server versions back to 3.0.0. -

    MongoDB Driver 4.0

    +## MongoDB Driver 4.0 {#mongodb-driver-40} Mongoose now uses v4.x of the [MongoDB Node driver](https://www.npmjs.com/package/mongodb). See [the MongoDB Node drivers' migration guide](https://github.com/mongodb/node-mongodb-native/blob/4.0/docs/CHANGES_4.0.0.md) for detailed info. @@ -87,7 +87,7 @@ res; res.deletedCount; // Number of documents that were deleted. Replaces `res.n` ``` -

    No More Deprecation Warning Options

    +## No More Deprecation Warning Options {#no-more-deprecation-warning-options} `useNewUrlParser`, `useUnifiedTopology`, `useFindAndModify`, and `useCreateIndex` are no longer supported options. Mongoose 6 always behaves as if `useNewUrlParser`, `useUnifiedTopology`, and `useCreateIndex` are `true`, and `useFindAndModify` is `false`. Please remove these options from your code. @@ -101,7 +101,7 @@ await mongoose.connect('mongodb://127.0.0.1:27017/test', { }); ``` -

    The asPromise() Method for Connections

    +## The `asPromise()` Method for Connections {#the-aspromise-method-for-connections} Mongoose connections are no longer [thenable](https://masteringjs.io/tutorials/fundamentals/thenable). This means that `await mongoose.createConnection(uri)` **no longer waits for Mongoose to connect**. Use `mongoose.createConnection(uri).asPromise()` instead. See [#8810](https://github.com/Automattic/mongoose/issues/8810). @@ -113,11 +113,11 @@ await mongoose.createConnection(uri); await mongoose.createConnection(uri).asPromise(); ``` -

    mongoose.connect() Returns a Promise

    +## `mongoose.connect()` Returns a Promise {#mongoose-connect-returns-a-promise} The `mongoose.connect()` function now always returns a promise, **not** a Mongoose instance. -

    Duplicate Query Execution

    +## Duplicate Query Execution {#duplicate-query-execution} Mongoose no longer allows executing the same query object twice. If you do, you'll get a `Query was already executed` error. Executing the same query instance twice is typically indicative of mixing callbacks and promises, but if you need to execute the same query twice, you can call `Query#clone()` to clone the query and re-execute it. See [gh-7398](https://github.com/Automattic/mongoose/issues/7398) @@ -130,7 +130,7 @@ await q; await q.clone(); // Can `clone()` the query to allow executing the query again ``` -

    Model.exists(...) now returns a lean document instead of boolean

    +## `Model.exists(...)` now returns a lean document instead of boolean {#model-exists-returns-a-lean-document-instead-of-boolean} ```js // in Mongoose 5.x, `existingUser` used to be a boolean @@ -141,7 +141,7 @@ if (existingUser) { } ``` -

    strictQuery is now equal to strict by default

    +## `strictQuery` is now equal to `strict` by default {#strictquery-is-removed-and-replaced-by-strict} ~Mongoose no longer supports a `strictQuery` option. You must now use `strict`.~ As of Mongoose 6.0.10, we brought back the `strictQuery` option. @@ -167,11 +167,11 @@ You can also disable `strictQuery` globally to override: mongoose.set('strictQuery', false); ``` -

    MongoError is now MongoServerError

    +## MongoError is now MongoServerError {#mongoerror-is-now-mongoservererror} In MongoDB Node.js Driver v4.x, 'MongoError' is now 'MongoServerError'. Please change any code that depends on the hardcoded string 'MongoError'. -

    Clone Discriminator Schemas By Default

    +## Clone Discriminator Schemas By Default {#clone-discriminator-schemas-by-default} Mongoose now clones discriminator schemas by default. This means you need to pass `{ clone: false }` to `discriminator()` if you're using recursive embedded discriminators. @@ -184,7 +184,7 @@ User.discriminator('author', authorSchema.clone()); User.discriminator('author', authorSchema, { clone: false }); ``` -

    Simplified isValidObjectId() and separate isObjectIdOrHexString()

    +## Simplified `isValidObjectId()` and separate `isObjectIdOrHexString()` {#simplified-isvalidobjectid-and-separate-isobjectidorhexstring} In Mongoose 5, `mongoose.isValidObjectId()` returned `false` for values like numbers, which was inconsistent with the MongoDB driver's `ObjectId.isValid()` function. Technically, any JavaScript number can be converted to a MongoDB ObjectId. @@ -209,7 +209,7 @@ mongoose.isObjectIdOrHexString('0123456789ab'); // false mongoose.isObjectIdOrHexString(6); // false ``` -

    Schema Defined Document Key Order

    +## Schema Defined Document Key Order {#schema-defined-document-key-order} Mongoose now saves objects with keys in the order the keys are specified in the schema, not in the user-defined object. So whether `Object.keys(new User({ name: String, email: String }).toObject()` is `['name', 'email']` or `['email', 'name']` depends on the order `name` and `email` are defined in your schema. @@ -233,7 +233,7 @@ const doc = new Test({ assert.deepEqual(Object.keys(doc.toObject().profile.name), ['first', 'last']); ``` -

    sanitizeFilter and trusted()

    +## `sanitizeFilter` and `trusted()` {#sanitizefilter-and-trusted} Mongoose 6 introduces a new `sanitizeFilter` option to globals and queries that defends against [query selector injection attacks](https://thecodebarbarian.com/2014/09/04/defending-against-query-selector-injection-attacks.html). If you enable `sanitizeFilter`, Mongoose will wrap any object in the query filter in a `$eq`: @@ -250,7 +250,7 @@ To explicitly allow a query selector, use `mongoose.trusted()`: await Test.find({ username: 'val', pwd: mongoose.trusted({ $ne: null }) }).setOptions({ sanitizeFilter: true }); ``` -

    Removed omitUndefined: Mongoose now removes undefined keys in updates instead of setting them to null

    +## Removed `omitUndefined`: Mongoose now removes `undefined` keys in updates instead of setting them to `null` {#removed-omitundefined} In Mongoose 5.x, setting a key to `undefined` in an update operation was equivalent to setting it to `null`. @@ -279,7 +279,7 @@ The only workaround is to explicitly set properties to `null` in your updates: const res = await Test.findOneAndUpdate({}, { $set: { name: null } }, { new: true }); ``` -

    Document Parameter to Default Functions

    +## Document Parameter to Default Functions {#document-parameter-to-default-functions} Mongoose now passes the document as the first parameter to `default` functions, which is helpful for using [arrow functions](https://masteringjs.io/tutorials/fundamentals/arrow) with defaults. @@ -297,7 +297,7 @@ const schema = new Schema({ }); ``` -

    Arrays are Proxies

    +## Arrays are Proxies {#arrays-are-proxies} Mongoose arrays are now ES6 proxies. You no longer need to `markModified()` after setting an array index directly. @@ -308,7 +308,7 @@ post.tags[0] = 'javascript'; await post.save(); // Works, no need for `markModified()`! ``` -

    typePojoToMixed

    +## `typePojoToMixed` {#typepojotomixed} Schema paths declared with `type: { name: String }` become single nested subdocs in Mongoose 6, as opposed to Mixed in Mongoose 5. This removes the need for the `typePojoToMixed` option. See [gh-7181](https://github.com/Automattic/mongoose/issues/7181). @@ -320,11 +320,11 @@ const schema = new Schema({ }); ``` -

    strictPopulate()

    +## `strictPopulate()` {#strictpopulate} Mongoose now throws an error if you `populate()` a path that isn't defined in your schema. This is only for cases when we can infer the local schema, like when you use `Query#populate()`, **not** when you call `Model.populate()` on a POJO. See [gh-5124](https://github.com/Automattic/mongoose/issues/5124). -

    Subdocument ref Function Context

    +## Subdocument `ref` Function Context {#subdocument-ref-function-context} When populating a subdocument with a function `ref` or `refPath`, `this` is now the subdocument being populated, not the top-level document. See [#8469](https://github.com/Automattic/mongoose/issues/8469). @@ -344,37 +344,37 @@ const schema = new Schema({ }); ``` -

    Schema Reserved Names Warning

    +## Schema Reserved Names Warning {#schema-reserved-names-warning} Using `save`, `isNew`, and other Mongoose reserved names as schema path names now triggers a warning, not an error. You can suppress the warning by setting the `suppressReservedKeysWarning` in your schema options: `new Schema({ save: String }, { suppressReservedKeysWarning: true })`. Keep in mind that this may break plugins that rely on these reserved names. -

    Subdocument Paths

    +## Subdocument Paths {#subdocument-paths} Single nested subdocs have been renamed to "subdocument paths". So `SchemaSingleNestedOptions` is now `SchemaSubdocumentOptions` and `mongoose.Schema.Types.Embedded` is now `mongoose.Schema.Types.Subdocument`. See [gh-10419](https://github.com/Automattic/mongoose/issues/10419) -

    Creating Aggregation Cursors

    +## Creating Aggregation Cursors {#creating-aggregation-cursors} `Aggregate#cursor()` now returns an AggregationCursor instance to be consistent with `Query#cursor()`. You no longer need to do `Model.aggregate(pipeline).cursor().exec()` to get an aggregation cursor, just `Model.aggregate(pipeline).cursor()`. -

    autoCreate Defaults to true

    +## `autoCreate` Defaults to `true` {#autocreate-defaults-to-true} `autoCreate` is `true` by default **unless** readPreference is secondary or secondaryPreferred, which means Mongoose will attempt to create every model's underlying collection before creating indexes. If readPreference is secondary or secondaryPreferred, Mongoose will default to `false` for both `autoCreate` and `autoIndex` because both `createCollection()` and `createIndex()` will fail when connected to a secondary. -

    No More context: 'query'

    +## No More `context: 'query'` {#no-more-context-query} The `context` option for queries has been removed. Now Mongoose always uses `context = 'query'`. -

    Custom Validators with Populated Paths

    +## Custom Validators with Populated Paths {#custom-validators-with-populated-paths} Mongoose 6 always calls validators with depopulated paths (that is, with the id rather than the document itself). In Mongoose 5, Mongoose would call validators with the populated doc if the path was populated. See [#8042](https://github.com/Automattic/mongoose/issues/8042) -

    Disconnected Event with Replica Sets

    +## Disconnected Event with Replica Sets {#disconnected-event-with-replica-sets} When connected to a replica set, connections now emit 'disconnected' when connection to the primary is lost. In Mongoose 5, connections only emitted 'disconnected' when losing connection to all members of the replica set. However, Mongoose 6 does **not** buffer commands while a connection is disconnected. So you can still successfully execute commands like queries with `readPreference = 'secondary'`, even if the Mongoose connection is in the disconnected state. -

    Removed execPopulate()

    +## Removed `execPopulate()` {#removed-execpopulate} `Document#populate()` now returns a promise and is now no longer chainable. @@ -385,15 +385,15 @@ However, Mongoose 6 does **not** buffer commands while a connection is disconnec await doc.populate([{path: 'path1', select: 'select1'}, {path: 'path2', select: 'select2'}]); ``` -

    create() with Empty Array

    +## `create()` with Empty Array {#create-with-empty-array} `await Model.create([])` in v6.0 returns an empty array when provided an empty array, in v5.0 it used to return `undefined`. If any of your code is checking whether the output is `undefined` or not, you need to modify it with the assumption that `await Model.create(...)` will always return an array if provided an array. -

    Removed Nested Path Merging

    +## Removed Nested Path Merging {#removed-nested-path-merging} `doc.set({ child: { age: 21 } })` now works the same whether `child` is a nested path or a subdocument: Mongoose will overwrite the value of `child`. In Mongoose 5, this operation would merge `child` if `child` was a nested path. -

    ObjectId valueOf()

    +## ObjectId `valueOf()` {#objectid-valueof} Mongoose now adds a `valueOf()` function to ObjectIds. This means you can now use `==` to compare an ObjectId against a string. @@ -403,19 +403,19 @@ const a = ObjectId('6143b55ac9a762738b15d4f0'); a == '6143b55ac9a762738b15d4f0'; // true ``` -

    Immutable createdAt

    +## Immutable `createdAt` {#immutable-createdat} If you set `timestamps: true`, Mongoose will now make the `createdAt` property `immutable`. See [gh-10139](https://github.com/Automattic/mongoose/issues/10139) -

    Removed Validator isAsync

    +## Removed Validator `isAsync` {#removed-validator-isasync} `isAsync` is no longer an option for `validate`. Use an `async function` instead. -

    Removed safe

    +## Removed `safe` {#removed-safe} `safe` is no longer an option for schemas, queries, or `save()`. Use `writeConcern` instead. -

    SchemaType set parameters

    +## SchemaType `set` parameters {#schematype-set-parameters} Mongoose now calls setter functions with `priorValue` as the 2nd parameter, rather than `schemaType` in Mongoose 5. @@ -442,7 +442,7 @@ const user = new User({ name: 'Robert Martin' }); console.log(user.name); // 'robert martin' ``` -

    toObject() and toJSON() Use Nested Schema minimize

    +## `toObject()` and `toJSON()` Use Nested Schema `minimize` {#toobject-and-tojson-use-nested-schema-minimize} This change was technically released with 5.10.5, but [caused issues for users migrating from 5.9.x to 6.x](https://github.com/Automattic/mongoose/issues/10827). In Mongoose `< 5.10.5`, `toObject()` and `toJSON()` would use the top-level schema's `minimize` option by default. @@ -473,7 +473,7 @@ const parent = new Schema({ }, { minimize: false }); ``` -

    No default model for Query.prototype.populate()

    +## No default model for `Query.prototype.populate()` {#no-default-model-for-query-prototype-populate} In Mongoose 5, calling `populate()` on a mixed type or other path with no `ref` would fall back to using the query's model. @@ -498,7 +498,7 @@ In Mongoose 6, populating a path with no `ref`, `refPath`, or `model` is a no-op await Test.findOne().populate('parents'); ``` -

    MongoDB Driver's New URL Parser Incompatible with Some npm Packages

    +## MongoDB Driver's New URL Parser Incompatible with Some npm Packages {#mongodb-drivers-new-url-parser-incompatible-with-some-npm-packages} The MongoDB Node driver version that Mongoose 6 uses relies on a [URL parser module](https://npmjs.com/package/whatwg-url) that has several known compatibility issues with other npm packages. This can lead to errors like `Invalid URL: mongodb+srv://username:password@development.xyz.mongodb.net/abc` if you use one of the incompatible packages. @@ -542,7 +542,7 @@ schema.virtual('myVirtual').get(function() { }); ``` -

    Removed reconnectTries and reconnectInterval options

    +## Removed `reconnectTries` and `reconnectInterval` options {#removed-reconnecttries-and-reconnectinterval-options} The `reconnectTries` and `reconnectInterval` options have been removed since they are no longer necessary. diff --git a/docs/migrating_to_7.md b/docs/migrating_to_7.md index c0500576c28..ffab6f46e9a 100644 --- a/docs/migrating_to_7.md +++ b/docs/migrating_to_7.md @@ -16,6 +16,7 @@ If you're still on Mongoose 5.x, please read the [Mongoose 5.x to 6.x migration * [Dropped callback support](#dropped-callback-support) * [Removed `update()`](#removed-update) * [ObjectId requires `new`](#objectid-requires-new) +* [`id` setter](#id-setter) * [Discriminator schemas use base schema options by default](#discriminator-schemas-use-base-schema-options-by-default) * [Removed `castForQueryWrapper()`, updated `castForQuery()` signature](#removed-castforquerywrapper) * [Copy schema options in `Schema.prototype.add()`](#copy-schema-options-in-schema-prototype-add) @@ -26,7 +27,7 @@ If you're still on Mongoose 5.x, please read the [Mongoose 5.x to 6.x migration * [Removed `LeanDocument` and support for `extends Document`](#removed-leandocument-and-support-for-extends-document) * [New parameters for `HydratedDocument`](#new-parameters-for-hydrateddocument) -

    strictQuery

    +## `strictQuery` {#strictquery} `strictQuery` is now false by default. @@ -40,7 +41,7 @@ const docs = await MyModel.find({ notInSchema: 1 }); docs; ``` -

    Removed remove()

    +## Removed `remove()` {#removed-remove} The `remove()` method on documents and models has been removed. Use `deleteOne()` or `deleteMany()` instead. @@ -79,7 +80,7 @@ schema.pre('deleteOne', { document: true, query: false }, function() { }); ``` -

    Dropped callback support

    +## Dropped callback support {#dropped-callback-support} The following functions no longer accept callbacks. They always return promises. @@ -167,7 +168,7 @@ const [err, session] = await conn.startSession().then( ); ``` -

    Removed update()

    +## Removed `update()` {#removed-update} `Model.update()`, `Query.prototype.update()`, and `Document.prototype.update()` have been removed. Use `updateOne()` instead. @@ -182,7 +183,7 @@ await Model.updateOne(filter, update); await doc.updateOne(update); ``` -

    ObjectId requires new

    +## ObjectId requires `new` {#objectid-requires-new} In Mongoose 6 and older, you could define a new ObjectId without using the `new` keyword: @@ -199,7 +200,32 @@ In Mongoose 7, `ObjectId` is now a [JavaScript class](https://masteringjs.io/tut const oid = new mongoose.Types.ObjectId('0'.repeat(24)); ``` -

    Discriminator schemas use base schema options by default

    +## `id` Setter + +Starting in Mongoose 7.4, Mongoose's built-in `id` virtual (which stores the document's `_id` as a string) has a setter which allows modifying the document's `_id` property via `id`. + +```javascript +const doc = await TestModel.findOne(); + +doc.id = '000000000000000000000000'; +doc._id; // ObjectId('000000000000000000000000') +``` + +This can cause surprising behavior if you create a `new TestModel(obj)` where `obj` contains both an `id` and an `_id`, or if you use `doc.set()` + +```javascript +// Because `id` is after `_id`, the `id` will overwrite the `_id` +const doc = new TestModel({ + _id: '000000000000000000000000', + id: '111111111111111111111111' +}); + +doc._id; // ObjectId('111111111111111111111111') +``` + +[The `id` setter was later removed in Mongoose 8](/docs/migrating_to_8.html#removed-id-setter) due to compatibility issues. + +## Discriminator schemas use base schema options by default {#discriminator-schemas-use-base-schema-options-by-default} When you use `Model.discriminator()`, Mongoose will now use the discriminator base schema's options by default. This means you don't need to explicitly set child schema options to match the base schema's. @@ -217,7 +243,7 @@ const Test = Base.discriminator('Child', childSchema); Test.schema.options.typeKey; // '$type' ``` -

    Removed castForQueryWrapper, updated castForQuery() signature

    +## Removed `castForQueryWrapper`, updated `castForQuery()` signature {#removed-castforquerywrapper} Mongoose now always calls SchemaType `castForQuery()` method with 3 arguments: `$conditional`, `value`, and `context`. If you've implemented a custom schema type that defines its own `castForQuery()` method, you need to update the method as follows. @@ -243,7 +269,7 @@ MySchemaType.prototype.castForQuery = function($conditional, value, context) { }; ``` -

    Copy Schema options in Schema.prototype.add()

    +## Copy Schema options in `Schema.prototype.add()` {#copy-schema-options-in-schema-prototype-add} Mongoose now copies user defined schema options when adding one schema to another. For example, `childSchema` below will get `baseSchema`'s `id` and `toJSON` options. @@ -263,7 +289,7 @@ childSchema.add(new Schema({}, { toObject: { virtuals: true } })); childSchema.options.toObject; // { virtuals: true } in Mongoose 7. undefined in Mongoose 6. ``` -

    ObjectId bsontype now has lowercase d

    +## ObjectId bsontype now has lowercase d {#objectid-bsontype-now-has-lowercase-d} The internal `_bsontype` property on ObjectIds is equal to `'ObjectId'` in Mongoose 7, as opposed to `'ObjectID'` in Mongoose 6. @@ -276,7 +302,7 @@ oid._bsontype; // 'ObjectId' in Mongoose 7, 'ObjectID' in older versions of Mong Please update any places where you use `_bsontype` to check if an object is an ObjectId. This may also affect libraries that use Mongoose. -

    Removed mapReduce

    +## Removed `mapReduce` {#removed-mapreduce} MongoDB no longer supports `mapReduce`, so Mongoose 7 no longer has a `Model.mapReduce()` function. Use the aggregation framework as a replacement for `mapReduce()`. @@ -295,7 +321,7 @@ const o = { await MR.mapReduce(o); ``` -

    Removed Support for custom promise libraries

    +## Removed Support for custom promise libraries {#removed-support-for-custom-promise-libraries} Mongoose 7 no longer supports plugging in custom promise libraries. So the following no longer makes Mongoose return Bluebird promises in Mongoose 7. @@ -312,9 +338,9 @@ If you want to use Bluebird for all promises globally, you can do the following: global.Promise = require('bluebird'); ``` -

    TypeScript-specific Changes

    +## TypeScript-specific Changes {#typescript-specific-changes} -

    Removed LeanDocument and support for extends Document

    +### Removed `LeanDocument` and support for `extends Document` {#removed-leandocument-and-support-for-extends-document} Mongoose 7 no longer exports a `LeanDocument` type, and no longer supports passing a document type that `extends Document` into `Model<>`. @@ -335,7 +361,7 @@ const Test = model('Test', schema); type TestDocument = ReturnType<(typeof Test)['hydrate']>; ``` -

    New Parameters for HydratedDocument

    +### New Parameters for `HydratedDocument` {#new-parameters-for-hydrateddocument} Mongoose's `HydratedDocument` type transforms a raw document interface into the type of the hydrated Mongoose document, including virtuals, methods, etc. In Mongoose 7, the generic parameters to `HydratedDocument` have changed. diff --git a/docs/migrating_to_8.md b/docs/migrating_to_8.md index 55b9d12a4ee..5914318003e 100644 --- a/docs/migrating_to_8.md +++ b/docs/migrating_to_8.md @@ -29,7 +29,7 @@ We also recommend reviewing the [MongoDB Node.js driver's release notes for v6.0 * [Model constructor properties are all optional in TypeScript](#model-constructor-properties-are-all-optional-in-typescript) * [Infer `distinct()` return types from schema](#infer-distinct-return-types-from-schema) -

    Removed rawResult option for findOneAndUpdate()

    +## Removed `rawResult` option for `findOneAndUpdate()` {#removed-rawresult-option-for-findoneandupdate} The `rawResult` option for `findOneAndUpdate()`, `findOneAndReplace()`, and `findOneAndDelete()` has been replaced by the `includeResultMetadata` option. @@ -47,7 +47,7 @@ const res = await Character.findOneAndUpdate(filter, update, { `includeResultMetadata` in Mongoose 8 behaves identically to `rawResult`. -

    Document.prototype.deleteOne now returns a query

    +## `Document.prototype.deleteOne` now returns a query {#document-prototype-deleteone-now-returns-a-query} In Mongoose 7, `doc.deleteOne()` returned a promise that resolved to `doc`. In Mongoose 8, `doc.deleteOne()` returns a query for easier chaining, as well as consistency with `doc.updateOne()`. @@ -64,7 +64,7 @@ const q = numberOne.deleteOne(); const res = await q; ``` -

    MongoDB Node Driver 6

    +## MongoDB Node Driver 6 {#mongodb-node-driver-6} Mongoose 8 uses [v6.x of the MongoDB Node driver](https://github.com/mongodb/node-mongodb-native/releases/tag/v6.0.0). There's a few noteable changes in MongoDB Node driver v6 that affect Mongoose: @@ -81,22 +81,22 @@ There's a few noteable changes in MongoDB Node driver v6 that affect Mongoose: * `sslValidate` -> `tlsAllowInvalidCertificates` * `tlsCertificateFile` -> `tlsCertificateKeyFile` -

    Removed findOneAndRemove()

    +## Removed `findOneAndRemove()` {#removed-findoneandremove} In Mongoose 7, `findOneAndRemove()` was an alias for `findOneAndDelete()` that Mongoose supported for backwards compatibility. Mongoose 8 no longer supports `findOneAndRemove()`. Use `findOneAndDelete()` instead. -

    Removed count()

    +## Removed `count()` {#removed-count} `Model.count()` and `Query.prototype.count()` were removed in Mongoose 8. Use `Model.countDocuments()` and `Query.prototype.countDocuments()` instead. -

    Removed id Setter

    +## Removed id Setter {#removed-id-setter} In Mongoose 7.4, Mongoose introduced an `id` setter that made `doc.id = '0'.repeat(24)` equivalent to `doc._id = '0'.repeat(24)`. In Mongoose 8, that setter is now removed. -

    null is valid for non-required string enums

    +## `null` is valid for non-required string enums {#null-is-valid-for-non-required-string-enums} Before Mongoose 8, setting a string path with an `enum` to `null` would lead to a validation error, even if that path wasn't `required`. In Mongoose 8, it is valid to set a string path to `null` if `required` is not set, even with `enum`. @@ -115,7 +115,7 @@ const Test = mongoose.model('Test', schema); await Test.create({ status: null }); ``` -

    Apply minimize when save() updates an existing document

    +## Apply minimize when `save()` updates an existing document {#apply-minimize-when-save-updates-an-existing-document} In Mongoose 7, Mongoose would only apply minimize when saving a new document, not when updating an existing document. @@ -144,7 +144,7 @@ let rawDoc = await Test.findById(_id).lean(); rawDoc.nested; // undefined in Mongoose 8, {} in Mongoose 7 ``` -

    Apply base schema paths before discriminator paths

    +## Apply base schema paths before discriminator paths {#apply-base-schema-paths-before-discriminator-paths} This means that, in Mongoose 8, getters and setters on discriminator paths run *after* getters and setters on base paths. In Mongoose 7, getters and setters on discriminator paths ran *before* getters and setters on base paths. @@ -178,7 +178,7 @@ const doc = new D({ name: 'test', otherProp: 'test' }); console.log(doc.toObject({ getters: true })); ``` -

    Removed overwrite option for findOneAndUpdate()

    +## Removed `overwrite` option for `findOneAndUpdate()` {#removed-overwrite-option-for-findoneandupdate} Mongoose 7 and earlier supported an `overwrite` option for `findOneAndUpdate()`, `updateOne()`, and `update()`. Before Mongoose 7, `overwrite` would skip wrapping the `update` parameter in `$set`, which meant that `findOneAndUpdate()` and `update()` would overwrite the matched document. @@ -187,7 +187,7 @@ In Mongoose 7, setting `overwrite` would convert `findOneAndUpdate()` to `findOn In Mongoose 8, the `overwrite` option is no longer supported. If you want to overwrite the entire document, use `findOneAndReplace()` or `replaceOne()`. -

    Changed behavior for findOneAndUpdate() with orFail() and upsert

    +## Changed behavior for `findOneAndUpdate()` with `orFail()` and upsert {#changed-behavior-for-findoneandupdate-with-orfail-and-upsert} In Mongoose 7, `findOneAndUpdate(filter, update, { upsert: true }).orFail()` would throw a `DocumentNotFoundError` if a new document was upserted. In other words, `findOneAndUpdate().orFail()` always threw an error if no document was found, even if a new document was upserted. @@ -195,7 +195,7 @@ In other words, `findOneAndUpdate().orFail()` always threw an error if no docume In Mongoose 8, `findOneAndUpdate(filter, update, { upsert: true }).orFail()` always succeeds. `findOneAndUpdate().orFail()` now throws a `DocumentNotFoundError` if there's no document returned, rather than if no document was found. -

    create() waits until all saves are done before throwing any error

    +## Create waits until all saves are done before throwing any error {#create-waits-until-all-saves-are-done-before-throwing-any-error} In Mongoose 7, `create()` would immediately throw if any `save()` threw an error by default. Mongoose 8 instead waits for all `save()` calls to finish before throwing the first error that occurred. @@ -227,7 +227,7 @@ err; // ValidationError await Test.countDocuments(); ``` -

    Model.validate() returns copy of object

    +## `Model.validate()` returns copy of object {#model-validate-returns-copy-of-object} In Mongoose 7, `Model.validate()` would potentially modify the passed in object. Mongoose 8 instead copies the passed in object first. @@ -243,7 +243,7 @@ typeof obj.answer; // 'string' in Mongoose 8, 'number' in Mongoose 7 typeof res.answer; // 'number' in both Mongoose 7 and Mongoose 8 ``` -

    Allow null For Optional Fields in TypeScript

    +## Allow `null` For Optional Fields in TypeScript {#allow-null-for-optional-fields-in-typescript} In Mongoose 8, automatically inferred schema types in TypeScript allow `null` for optional fields. In Mongoose 7, optional fields only allowed `undefined`, not `null`. @@ -259,7 +259,7 @@ const doc = new TestModel(); doc.name; ``` -

    Model constructor properties are all optional in TypeScript

    +## Model constructor properties are all optional in TypeScript {#model-constructor-properties-are-all-optional-in-typescript} In Mongoose 8, no properties are required on model constructors by default. @@ -292,7 +292,7 @@ const newDoc2 = new TestModel({ }); ``` -

    Infer distinct() return types from schema

    +## Infer `distinct()` return types from schema {#infer-distinct-return-types-from-schema} ```ts interface User { diff --git a/docs/migration.md b/docs/migration.md index 1e6b7aae5ad..dc9b112ca8b 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -2,7 +2,7 @@ There are several [backwards-breaking changes](https://github.com/Automattic/mongoose/wiki/4.0-Release-Notes) to be aware of when migrating from Mongoose 3 to Mongoose 4. -

    `findOneAndUpdate()` new field is now `false` by default

    +## `findOneAndUpdate()` new field is now `false` by default {#findandmodify-new} Mongoose's `findOneAndUpdate()`, `findOneAndRemove()`, `findByIdAndUpdate()`, and `findByIdAndRemove()` functions are just @@ -25,7 +25,7 @@ MyModel.findOneAndUpdate({}, { $set: { test: 1 } }, { new: true }, callback); In Mongoose 3, CastError and ValidationError had a `type` field. For instance, user defined validation errors would have a `type` property that contained the string 'user defined'. In Mongoose 4, this property has been renamed to `kind` due to [the V8 JavaScript engine using the Error.type property internally](https://code.google.com/p/v8/issues/detail?id=2397). -

    Query now has a `.then()` function

    +## Query now has a `.then()` function {#promises} In mongoose 3, you needed to call `.exec()` on a query chain to get a promise back, like `MyModel.find().exec().then();`. Mongoose 4 queries are @@ -34,7 +34,7 @@ you're using functions like [q's `Q.ninvoke()`](https://github.com/kriskowal/q#adapting-node) or otherwise returning a mongoose query from a promise. -

    More Info

    +## More Info {#moreinfo} Related blog posts: diff --git a/docs/models.md b/docs/models.md index 84c53cca0d1..a5c7b3a39dc 100644 --- a/docs/models.md +++ b/docs/models.md @@ -13,7 +13,7 @@ reading documents from the underlying MongoDB database. * [Change Streams](#change-streams) * [Views](#views) -

    Compiling your first model

    +## Compiling your first model {#compiling} When you call `mongoose.model()` on a schema, Mongoose *compiles* a model for you. diff --git a/docs/plugins.md b/docs/plugins.md index 978a11cfcad..1cbfedcd3ba 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -9,7 +9,7 @@ Schemas are pluggable, that is, they allow for applying pre-packaged capabilitie
  • Officially Supported Plugins
  • -

    Example

    +## Example {#example} Plugins are a tool for reusing logic in multiple schemas. Suppose you have several models in your database and want to add a `loadedAt` property @@ -46,7 +46,7 @@ playerSchema.plugin(loadedAtPlugin); We just added loaded-time behavior to both our `Game` and `Player` schemas and declared an index on the `loadedAt` path of our Games to boot. Not bad for a few lines of code. -

    Global Plugins

    +## Global Plugins {#global} Want to register a plugin for all schemas? The mongoose singleton has a `.plugin()` function that registers a plugin for every schema. For @@ -63,7 +63,7 @@ const Game = mongoose.model('Game', gameSchema); const Player = mongoose.model('Player', playerSchema); ``` -

    Apply Plugins Before Compiling Models

    +## Apply Plugins Before Compiling Models {#apply-plugins-before-compiling-models} 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). @@ -96,7 +96,7 @@ const Game = mongoose.model('Game', gameSchema); gameSchema.plugin(loadedAtPlugin); ``` -

    Officially Supported Plugins

    +## Officially Supported Plugins {#official} The Mongoose team maintains several plugins that add cool new features to Mongoose. Here's a couple: diff --git a/docs/populate.md b/docs/populate.md index 9bc16f65962..0a24878d68d 100644 --- a/docs/populate.md +++ b/docs/populate.md @@ -57,7 +57,7 @@ the `Story` model.
  • Transform populated documents
  • -

    Saving refs

    +## Saving refs {#saving-refs} Saving refs to other documents works the same way you normally save properties, just assign the `_id` value: @@ -85,7 +85,7 @@ You can set the `ref` option on `ObjectId`, `Number`, `String`, and `Buffer` pat However, we recommend using ObjectIds as `_id` properties (and thus ObjectIds for `ref` properties) unless you have a good reason not to. That is because MongoDB will set `_id` to an ObjectId if you create a new document without an `_id` property, so if you make your `_id` property a Number, you need to be extra careful not to insert a document without a numeric `_id`. -

    Population

    +## Population {#population} So far we haven't done anything much different. We've merely created a `Person` and a `Story`. Now let's take a look at populating our story's @@ -108,7 +108,7 @@ Arrays of refs work the same way. Just call the [populate](api/query.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

    +## Setting Populated Fields {#setting-populated-fields} You can manually populate a property by setting it to a document. The document must be an instance of the model your `ref` property refers to. @@ -119,7 +119,7 @@ story.author = author; console.log(story.author.name); // prints "Ian Fleming" ``` -

    Checking Whether a Field is Populated

    +## Checking Whether a Field is Populated {#checking-populated} You can call the `populated()` function to check whether a field is populated. If `populated()` returns a [truthy value](https://masteringjs.io/tutorials/fundamentals/truthy), @@ -147,7 +147,7 @@ story.author instanceof ObjectId; // true story.author._id; // ObjectId, because Mongoose adds a special getter ``` -

    What If There's No Foreign Document?

    +## What If There's No Foreign Document? {#doc-not-found} Mongoose populate doesn't behave like conventional [SQL joins](https://www.w3schools.com/sql/sql_join.asp). When there's no @@ -176,7 +176,7 @@ const story = await Story.findOne({ title: 'Casino Royale' }).populate('authors' story.authors; // `[]` ``` -

    Field Selection

    +## Field Selection {#field-selection} What if we only want a few specific fields returned for the populated documents? This can be accomplished by passing the usual @@ -194,7 +194,7 @@ console.log('The author is %s', story.author.name); console.log('The authors age is %s', story.author.age); ``` -

    Populating Multiple Paths

    +## Populating Multiple Paths {#populating-multiple-paths} What if we wanted to populate multiple paths at the same time? @@ -220,7 +220,7 @@ await Story. await Story.find().populate({ path: 'fans', select: 'email' }); ``` -

    Query conditions and other options

    +## Query conditions and other options {#query-conditions} What if we wanted to populate our fans array based on their age and select just their names? @@ -264,7 +264,7 @@ story; // null If you want to filter stories by their author's name, you should use [denormalization](https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-3). -

    limit vs. perDocumentLimit

    +## `limit` vs. `perDocumentLimit` {#limit-vs-perDocumentLimit} Populate does support a `limit` option, however, it currently does **not** limit on a per-document basis for backwards compatibility. For example, @@ -316,7 +316,7 @@ stories[1].name; // 'Live and Let Die' stories[1].fans.length; // 2 ``` -

    Refs to children

    +## Refs to children {#refs-to-children} We may find however, if we use the `author` object, we are unable to get a list of the stories. This is because no `story` objects were ever 'pushed' @@ -364,7 +364,7 @@ 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. -

    Populating an existing document

    +## Populating an existing document {#populate_an_existing_mongoose_document} If you have an existing mongoose document and want to populate some of its paths, you can use the @@ -390,7 +390,7 @@ await person.populate(['stories', 'fans']); person.populated('fans'); // Array of ObjectIds ``` -

    Populating multiple existing documents

    +## Populating multiple existing documents {#populate_multiple_documents} If we have one or many mongoose documents or even plain objects (*like [mapReduce](api/model.html#model_Model-mapReduce) output*), we may @@ -398,7 +398,7 @@ populate them using the [Model.populate()](api/model.html#model_Model-populate) method. This is what `Document#populate()` and `Query#populate()` use to populate documents. -

    Populating across multiple levels

    +## Populating across multiple levels {#deep-populate} Say you have a user schema which keeps track of the user's friends. @@ -423,7 +423,7 @@ await User. }); ``` -

    Cross Database Populate

    +## Cross Database Populate {#cross-db-populate} Let's say you have a schema representing events, and a schema representing conversations. Each event has a corresponding conversation thread. @@ -470,7 +470,7 @@ const events = await Event. populate({ path: 'conversation', model: Conversation }); ``` -

    Dynamic References via refPath

    +## Dynamic References via `refPath` {#dynamic-refpath} Mongoose can also populate from multiple collections based on the value of a property in the document. Let's say you're building a schema for @@ -591,7 +591,7 @@ const commentSchema = new Schema({ }); ``` -

    Dynamic References via ref

    +## Dynamic References via `ref` {#dynamic-ref} Just like `refPath`, `ref` can also be assigned a function. @@ -609,7 +609,7 @@ const commentSchema = new Schema({ }); ``` -

    Populate Virtuals

    +## Populate Virtuals {#populate-virtuals} So far you've only populated based on the `_id` field. However, that's sometimes not the right choice. @@ -706,7 +706,7 @@ authors = await Author. exec(); ``` -

    Populate Virtuals: The Count Option

    +## Populate Virtuals: The Count Option {#count} Populate virtuals also support counting the number of documents with matching `foreignField` as opposed to the documents themselves. Set the @@ -734,7 +734,7 @@ const doc = await Band.findOne({ name: 'Motley Crue' }). doc.numMembers; // 2 ``` -

    Populate Virtuals: The Match Option

    +## Populate Virtuals: The Match Option {#match} Another option for Populate virtuals is `match`. This option adds an extra filter condition to the query Mongoose uses to `populate()`: @@ -796,7 +796,7 @@ await Author.findOne().populate({ }); ``` -

    Populating Maps

    +## Populating Maps {#populating-maps} [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. @@ -866,7 +866,7 @@ You can `populate()` every book's author by populating `books.$*.author`: const libraries = await Library.find().populate('books.$*.author'); ``` -

    Populate in Middleware

    +## Populate in Middleware {#populate-middleware} You can populate in either pre or post [hooks](http://mongoosejs.com/docs/middleware.html). If you want to always populate a certain field, check out the [mongoose-autopopulate plugin](http://npmjs.com/package/mongoose-autopopulate). @@ -900,7 +900,7 @@ MySchema.post('save', function(doc, next) { }); ``` -

    Populating Multiple Paths in Middleware

    +## Populating Multiple Paths in Middleware {#populating-multiple-paths-middleware} Populating multiple paths in middleware can be helpful when you always want to populate some fields. But, the implementation is just a tiny bit trickier than what you may think. Here's how you may expect it to work: @@ -936,7 +936,7 @@ userSchema.pre('find', function(next) { Alternatively, you can check out the [mongoose-autopopulate plugin](http://npmjs.com/package/mongoose-autopopulate). -

    Transform populated documents

    +## Transform populated documents {#transform-populated-documents} You can manipulate populated documents using the `transform` option. If you specify a `transform` function, Mongoose will call this function on every populated document in the result with two arguments: the populated document, and the original id used to populate the document. diff --git a/docs/queries.md b/docs/queries.md index 0b00e752cf1..df552c5043f 100644 --- a/docs/queries.md +++ b/docs/queries.md @@ -97,11 +97,7 @@ await Person. A full list of [Query helper functions can be found in the API docs](api/query.html). -

    - - Queries are Not Promises - -

    +## Queries are Not Promises Mongoose queries are **not** promises. Queries are [thenables](https://masteringjs.io/tutorials/fundamentals/thenable), meaning they have a `.then()` method for [async/await](http://thecodebarbarian.com/common-async-await-design-patterns-in-node.js.html) as a convenience. @@ -115,14 +111,14 @@ await q.then(() => console.log('Update 2')); await q.then(() => console.log('Update 3')); ``` -

    References to other documents

    +## References to other documents {#refs} There are no joins in MongoDB but sometimes we still want references to 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/query.html#query_Query-populate). -

    Streaming

    +## Streaming {#streaming} You can [stream](http://nodejs.org/api/stream.html) query results from MongoDB. You need to call the @@ -159,7 +155,7 @@ However, cursors can still time out because of [session idle timeouts](https://w So even a cursor with `noCursorTimeout` set will still time out after 30 minutes of inactivity. You can read more about working around session idle timeouts in the [MongoDB documentation](https://www.mongodb.com/docs/manual/reference/method/cursor.noCursorTimeout/#session-idle-timeout-overrides-nocursortimeout). -

    Versus Aggregation

    +## Versus Aggregation {#versus-aggregation} [Aggregation](api/aggregate.html#aggregate_Aggregate) can do many of the same things that queries can. For example, below is @@ -201,7 +197,7 @@ const queryRes = await Person.findOne({ _id: idString }); const aggRes = await Person.aggregate([{ $match: { _id: idString } }]); ``` -

    Sorting

    +## Sorting {#sorting} [Sorting](/docs/api.html#query_Query-sort) is how you can ensure your query results come back in the desired order. @@ -284,6 +280,6 @@ As you can see, age is sorted from 0 to 2 but when age is equal, sorts by weight ]; ``` -

    Next Up

    +## Next Up {#next} 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 d4f90a6a014..904bb6a8726 100644 --- a/docs/schematypes.md +++ b/docs/schematypes.md @@ -18,7 +18,7 @@ and other general characteristics for Mongoose document properties. * [The `schema.path()` Function](#path) * [Further Reading](#further-reading) -

    What is a SchemaType?

    +## What is a SchemaType? {#what-is-a-schematype} You can think of a Mongoose schema as the configuration object for a Mongoose model. A SchemaType is then a configuration object for an individual @@ -56,7 +56,7 @@ Check out [Mongoose's plugins search](http://plugins.mongoosejs.io) to find plug * [UUID](#uuid) * [BigInt](#bigint) -

    Example

    +### Example ```javascript const schema = new Schema({ @@ -112,7 +112,7 @@ m.map = new Map([['key', 'value']]); m.save(callback); ``` -

    The type Key

    +## The `type` Key {#type-key} `type` is a special property in Mongoose schemas. When Mongoose finds a nested property named `type` in your schema, Mongoose assumes that @@ -163,7 +163,7 @@ const holdingSchema = new Schema({ }); ``` -

    SchemaType Options

    +## SchemaType Options {#schematype-options} You can declare a schema type using the type directly, or an object with a `type` property. @@ -201,7 +201,7 @@ The `lowercase` option only works for strings. There are certain options which apply for all schema types, and some that apply for specific schema types. -

    All Schema Types

    +### All Schema Types * `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. @@ -234,7 +234,7 @@ doc.integerOnly; // 3 doc.i; // 3 ``` -

    Indexes

    +### Indexes You can also define [MongoDB indexes](https://www.mongodb.com/docs/manual/indexes/) using schema type options. @@ -254,7 +254,7 @@ const schema2 = new Schema({ }); ``` -

    String

    +### String {#string-validators} * `lowercase`: boolean, whether to always call `.toLowerCase()` on the value * `uppercase`: boolean, whether to always call `.toUpperCase()` on the value @@ -265,26 +265,26 @@ const schema2 = new Schema({ * `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

    +### Number {#number-validators} * `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

    +### 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. * `expires`: Number or String, creates a TTL index with the value expressed in seconds. -

    ObjectId

    +### ObjectId * `populate`: Object, sets default [populate options](populate.html#query-conditions) -

    Usage Notes

    +## Usage Notes {#usage-notes} -

    String

    +### String {#strings} To declare a path as a string, you may use either the `String` global constructor or the string `'String'`. @@ -308,7 +308,7 @@ new Person({ name: { toString: () => 42 } }).name; // "42" as a string new Person({ name: { foo: 42 } }).name; ``` -

    Number

    +### Number {#numbers} To declare a path as a number, you may use either the `Number` global constructor or the string `'Number'`. @@ -337,7 +337,7 @@ 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](validation.html#cast-errors) once validated, meaning that it will not throw on initialization, only when validated. -

    Dates

    +### Dates {#dates} [Built-in `Date` methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) are [**not** hooked into](https://github.com/Automattic/mongoose/issues/1598) the mongoose change tracking logic which in English means that if you use a `Date` in your document and modify it with a method like `setMonth()`, mongoose will be unaware of this change and `doc.save()` will not persist this modification. If you must modify `Date` types using built-in methods, tell mongoose about the change with `doc.markModified('pathToYourDate')` before saving. @@ -351,7 +351,7 @@ doc.markModified('dueDate'); await doc.save(); // works ``` -

    Buffer

    +### Buffer {#buffers} To declare a path as a Buffer, you may use either the `Buffer` global constructor or the string `'Buffer'`. @@ -371,7 +371,7 @@ const file2 = new Data({ binData: 72987 }); // {"type":"Buffer","data":[27]} const file4 = new Data({ binData: { type: 'Buffer', data: [1, 2, 3]}}); // {"type":"Buffer","data":[1,2,3]} ``` -

    Mixed

    +### Mixed {#mixed} An "anything goes" SchemaType. Mongoose will not do any casting on mixed paths. You can define a mixed path using `Schema.Types.Mixed` or by passing an empty @@ -398,7 +398,7 @@ person.markModified('anything'); person.save(); // Mongoose will save changes to `anything`. ``` -

    ObjectIds

    +### ObjectIds {#objectids} An [ObjectId](https://www.mongodb.com/docs/manual/reference/method/ObjectId/) is a special type typically used for unique identifiers. Here's how @@ -425,7 +425,7 @@ car.driver instanceof mongoose.Types.ObjectId; // true car.driver.toString(); // Something like "5e1a0651741b255ddda996c4" ``` -

    Boolean

    +### Boolean {#booleans} Booleans in Mongoose are [plain JavaScript booleans](https://www.w3schools.com/js/js_booleans.asp). By default, Mongoose casts the below values to `true`: @@ -459,7 +459,7 @@ mongoose.Schema.Types.Boolean.convertToFalse.add('nay'); console.log(new M({ b: 'nay' }).b); // false ``` -

    Arrays

    +### Arrays {#arrays} Mongoose supports arrays of [SchemaTypes](api/schema.html#schema_Schema-Types) and arrays of [subdocuments](subdocs.html). Arrays of SchemaTypes are @@ -505,7 +505,7 @@ const Empty3 = new Schema({ any: [Schema.Types.Mixed] }); const Empty4 = new Schema({ any: [{}] }); ``` -

    Maps

    +### Maps {#maps} A `MongooseMap` is a subclass of [JavaScript's `Map` class](http://thecodebarbarian.com/the-80-20-guide-to-maps-in-javascript.html). In these docs, we'll use the terms 'map' and `MongooseMap` interchangeably. @@ -591,7 +591,7 @@ on `socialMediaHandles.$*.oauth`: const user = await User.findOne().populate('socialMediaHandles.$*.oauth'); ``` -

    UUID

    +### UUID {#uuid} Mongoose also supports a UUID type that stores UUID instances as [Node.js buffers](https://thecodebarbarian.com/an-overview-of-buffers-in-node-js.html). We recommend using [ObjectIds](#objectids) rather than UUIDs for unique document ids in Mongoose, but you may use UUIDs if you need to. @@ -632,7 +632,7 @@ const schema = new mongoose.Schema({ }); ``` -

    BigInt

    +### BigInt {#bigint} Mongoose supports [JavaScript BigInts](https://thecodebarbarian.com/an-overview-of-bigint-in-node-js.html) as a SchemaType. BigInts are stored as [64-bit integers in MongoDB (BSON type "long")](https://www.mongodb.com/docs/manual/reference/bson-types/). @@ -647,7 +647,7 @@ const question = new Question({ answer: 42n }); typeof question.answer; // 'bigint' ``` -

    Getters

    +## Getters {#getters} Getters are like virtuals for paths defined in your schema. For example, let's say you wanted to store user profile pictures as relative paths and @@ -709,7 +709,7 @@ const root = 'https://s3.amazonaws.com/mybucket'; schema.path('arr.0.url').get(v => `${root}${v}`); ``` -

    Schemas

    +## Schemas {#schemas} To declare a path as another [schema](guide.html#definition), set `type` to the sub-schema's instance. @@ -731,7 +731,7 @@ const schema = new mongoose.Schema({ }); ``` -

    Creating Custom Types

    +## Creating Custom Types {#customtypes} Mongoose can also be extended with [custom SchemaTypes](customschematypes.html). Search the [plugins](http://plugins.mongoosejs.io) @@ -743,7 +743,7 @@ and Read more about creating custom SchemaTypes [here](customschematypes.html). -

    The `schema.path()` Function

    +## The `schema.path()` Function {#path} The `schema.path()` function returns the instantiated schema type for a given path. @@ -765,7 +765,7 @@ console.log(sampleSchema.path('name')); You can use this function to inspect the schema type for a given path, including what validators it has and what the type is. -

    Further Reading

    +## Further Reading {#further-reading}