From 7af3dbda79f302bbceb22da244ce6421efa56934 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 15 Aug 2024 19:08:45 -0400 Subject: [PATCH] docs: upgrade marked -> 14.x, use new {#id-here} syntax for declaring custom header ids Fix #13211 --- docs/async-await.md | 2 +- docs/browser.md | 2 +- docs/connections.md | 32 +++++------ docs/deprecations.md | 4 +- docs/documents.md | 12 ++-- docs/geojson.md | 8 +-- docs/guide.md | 114 +++++++++++++++---------------------- docs/jest.md | 8 +-- docs/middleware.md | 26 ++++----- docs/migrating_to_5.md | 126 +++++++++++------------------------------ docs/migrating_to_8.md | 32 +++++------ package.json | 2 +- scripts/website.js | 66 ++++++++++++++------- 13 files changed, 190 insertions(+), 244 deletions(-) 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..75aa21a9ddd 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..19d94665e7f 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -19,7 +19,7 @@ If you are migrating from 7.x to 8.x please take a moment to read the [migration
  • Further Reading
  • -

    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 {#_id} 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: @@ -561,7 +561,7 @@ Valid options: * [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 +580,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 +605,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 +623,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 +633,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 +652,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 +663,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 +682,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 +706,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 +727,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 +757,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 +802,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 +838,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 +853,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 +867,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 +918,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,7 +970,7 @@ 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. @@ -991,7 +991,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 +1015,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 +1038,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 +1059,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 @@ -1137,7 +1137,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 +1201,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 +1223,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 +1242,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 +1255,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 +1325,7 @@ const schema = Schema({ }); ``` -

    option: pluginTags

    +## option: pluginTags {#pluginTags} Mongoose supports defining global plugins, plugins that apply to all schemas. @@ -1358,11 +1358,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 +1392,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 +1423,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,11 +1443,7 @@ 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. @@ -1474,11 +1458,7 @@ 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. @@ -1492,7 +1472,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 +1498,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 +1520,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). +Now that we've covered `Schemas`, let's take a look at [SchemaTypes](schematypes.html). \ No newline at end of file diff --git a/docs/jest.md b/docs/jest.md index 9b492f5b76c..5c1e4e47b10 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 @@ -87,4 +87,4 @@ course on Pluralsight has a great section on testing Mongoose apps with [Mocha]( RESTful Web Services with Node.js and Express - + \ No newline at end of file diff --git a/docs/middleware.md b/docs/middleware.md index 03a40983a7a..e8d67a8a2a6 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`. @@ -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. +to faking JOINs with its query [population](populate.html) helper. \ No newline at end of file diff --git a/docs/migrating_to_5.md b/docs/migrating_to_5.md index 2f892993ff8..44ff6f56014 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). @@ -547,4 +487,4 @@ If this is blocking you from upgrading, you can set the `tlsInsecure` option to ```javascript mongoose.connect(uri, { tlsInsecure: false }); // Opt out of additional SSL validation -``` +``` \ No newline at end of file diff --git a/docs/migrating_to_8.md b/docs/migrating_to_8.md index 55b9d12a4ee..e57eacdbc55 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/package.json b/package.json index 013c7325c21..f684e3a0e1f 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "lodash.isequal": "4.5.0", "lodash.isequalwith": "4.4.0", "markdownlint-cli2": "^0.13.0", - "marked": "4.3.0", + "marked": "14.0.0", "mkdirp": "^3.0.1", "mocha": "10.7.0", "moment": "2.30.1", diff --git a/scripts/website.js b/scripts/website.js index 63779a7e7be..53ac80d2673 100644 --- a/scripts/website.js +++ b/scripts/website.js @@ -10,11 +10,16 @@ const pug = require('pug'); const pkg = require('../package.json'); const transform = require('acquit-require'); const childProcess = require("child_process"); -require('./generateSearch'); + // using "__dirname" and ".." to have a consistent CWD, this script should not be runnable, even when not being in the root of the project // also a consistent root path so that it is easy to change later when the script should be moved const cwd = path.resolve(__dirname, '..'); +// support github-like custom header ids +// Example: +// # Some Header {#custom-id} +const CustomIdRefex = /{#([a-z][\w-]*)}(?: *)$/; + const isMain = require.main === module; let jobs = []; @@ -29,28 +34,39 @@ try { require('acquit-ignore')(); -const { marked: markdown } = require('marked'); +const markdown = require('marked'); const highlight = require('highlight.js'); -const { promisify } = require("util"); +const { promisify } = require('util'); + markdown.use({ - heading: function(text, level, raw, slugger) { - const slug = slugger.slug(raw); - return ` - - ${text} - - \n`; - } -}); -markdown.setOptions({ - highlight: function(code, language) { - if (!language) { - language = 'javascript'; - } - if (language === 'no-highlight') { - return code; + renderer: { + heading: function({ tokens, depth }) { + let raw = this.parser.parseInline(tokens); + let slug; + const idMatch = CustomIdRefex.exec(raw); + + // use github-like custom header if available, otherwise fallback to default slugger + if (idMatch) { + slug = idMatch[1]; + raw = raw.replace(CustomIdRefex, ''); + } else { + slug = createSlug(raw.trim()); + } + return ` + + ${raw} + + \n`; + }, + code: function({ text, lang }) { + if (!lang || lang === 'acquit') { + lang = 'javascript'; + } + if (lang === 'no-highlight') { + return text; + } + return `
    ${highlight.highlight(text, { language: lang }).value}
    `; } - return highlight.highlight(code, { language }).value; } }); @@ -590,6 +606,7 @@ if (isMain) { (async function main() { console.log(`Processing ~${files.length} files`); + require('./generateSearch'); await deleteAllHtmlFiles(); await pugifyAllFiles(); await copyAllRequiredFiles(); @@ -600,3 +617,12 @@ if (isMain) { console.log('Done Processing'); })(); } + +// Modified from github-slugger +function createSlug(value) { + if (typeof value !== 'string') { + return ''; + } + value = value.toLowerCase(); + return value.replace(/[^a-z0-9-_\s]/, '').replace(/ /g, '-'); +} \ No newline at end of file