

Getting Started
================

 *First be sure you have [MongoDB](http://www.mongodb.org/downloads) and [Node.js](http://nodejs.org/) installed.*

 Next install Mongoose from the command line using `npm`:

 
```
npm install mongoose --save

```
 Now say we like fuzzy kittens and want to record every kitten we ever meet in MongoDB. The first thing we need to do is include mongoose in our project and open a connection to the `test` database on our locally running instance of MongoDB.

 
```
// getting-started.js
const mongoose = require('mongoose');

main().catch(err => console.log(err));

async function main() {
  await mongoose.connect('mongodb://127.0.0.1:27017/test');

  // use `await mongoose.connect('mongodb://user:password@127.0.0.1:27017/test');` if your database has auth enabled
}

```
 For brevity, let's assume that all following code is within the `main()` function.

 With Mongoose, everything is derived from a [Schema](guide). Let's get a reference to it and define our kittens.

 
```
const kittySchema = new mongoose.Schema({
  name: String
});

```
 So far so good. We've got a schema with one property, `name`, which will be a `String`. The next step is compiling our schema into a [Model](models).

 
```
const Kitten = mongoose.model('Kitten', kittySchema);

```
 A model is a class with which we construct documents. In this case, each document will be a kitten with properties and behaviors as declared in our schema. Let's create a kitten document representing the little guy we just met on the sidewalk outside:

 
```
const silence = new Kitten({ name: 'Silence' });
console.log(silence.name); // 'Silence'

```
 Kittens can meow, so let's take a look at how to add "speak" functionality to our documents:

 
```
// NOTE: methods must be added to the schema before compiling it with mongoose.model()
kittySchema.methods.speak = function speak() {
  const greeting = this.name
    ? 'Meow name is ' + this.name
    : 'I don\'t have a name';
  console.log(greeting);
};

const Kitten = mongoose.model('Kitten', kittySchema);

```
 Functions added to the `methods` property of a schema get compiled into the `Model` prototype and exposed on each document instance:

 
```
const fluffy = new Kitten({ name: 'fluffy' });
fluffy.speak(); // "Meow name is fluffy"

```
 We have talking kittens! But we still haven't saved anything to MongoDB. Each document can be saved to the database by calling its [save](api/model#model_Model-save) method. The first argument to the callback will be an error if any occurred.

 
```
await fluffy.save();
fluffy.speak();

```
 Say time goes by and we want to display all the kittens we've seen. We can access all of the kitten documents through our Kitten [model](models).

 
```
const kittens = await Kitten.find();
console.log(kittens);

```
 We just logged all of the kittens in our db to the console. If we want to filter our kittens by name, Mongoose supports MongoDBs rich [querying](queries) syntax.

 
```
await Kitten.find({ name: /^fluff/ });

```
 This performs a search for all documents with a name property that begins with "fluff" and returns the result as an array of kittens to the callback.

  Congratulations
----------------

 That's the end of our quick start. We created a schema, added a custom document method, saved and queried kittens in MongoDB using Mongoose. Head over to the <guide>, or [API docs](api/mongoose) for more.



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/index.html>

Models
=======

 [Models](api/model) are fancy constructors compiled from `Schema` definitions. An instance of a model is called a [document](documents). Models are responsible for creating and reading documents from the underlying MongoDB database.

 * [Compiling your first model](#compiling)
* [Constructing Documents](#constructing-documents)
* [Querying](#querying)
* [Deleting](#deleting)
* [Updating](#updating)
* [Change Streams](#change-streams)
* [Views](#views)

 Compiling your first model
--------------------------

 When you call `mongoose.model()` on a schema, Mongoose *compiles* a model for you.

 
```
const schema = new mongoose.Schema({ name: String, size: String });
const Tank = mongoose.model('Tank', schema);

```
 The first argument is the *singular* name of the collection your model is for. **Mongoose automatically looks for the plural, lowercased version of your model name.** Thus, for the example above, the model Tank is for the **tanks** collection in the database.

 **Note:** The `.model()` function makes a copy of `schema`. Make sure that you've added everything you want to `schema`, including hooks, before calling `.model()`!

  Constructing Documents
-----------------------

 An instance of a model is called a [document](documents). Creating them and saving to the database is easy.

 
```
const Tank = mongoose.model('Tank', yourSchema);

const small = new Tank({ size: 'small' });
await small.save();

// or

await Tank.create({ size: 'small' });

// or, for inserting large batches of documents
await Tank.insertMany([{ size: 'small' }]);

```
 Note that no tanks will be created/removed until the connection your model uses is open. Every model has an associated connection. When you use `mongoose.model()`, your model will use the default mongoose connection.

 
```
await mongoose.connect('mongodb://127.0.0.1/gettingstarted');

```
 If you create a custom connection, use that connection's `model()` function instead.

 
```
const connection = mongoose.createConnection('mongodb://127.0.0.1:27017/test');
const Tank = connection.model('Tank', yourSchema);

```
  Querying
---------

 Finding documents is easy with Mongoose, which supports the [rich](https://www.mongodb.com/docs/manual/reference/method/js-cursor/) query syntax of MongoDB. Documents can be retrieved using a `model`'s [find](api/model#model_Model-find), [findById](api/model#model_Model-findById), [findOne](api/model#model_Model-findOne), or [where](api/model#model_Model-where) static functions.

 
```
await Tank.find({ size: 'small' }).where('createdDate').gt(oneYearAgo).exec();

```
 See the chapter on <queries> for more details on how to use the [Query](api/query) api.

  Deleting
---------

 Models have static `deleteOne()` and `deleteMany()` functions for removing all documents matching the given `filter`.

 
```
await Tank.deleteOne({ size: 'large' });

```
  Updating
---------

 Each `model` has its own `update` method for modifying documents in the database without returning them to your application. See the [API](api/model#model_Model-updateOne) docs for more detail.

 
```
// Updated at most one doc, `res.nModified` contains the number
// of docs that MongoDB updated
await Tank.updateOne({ size: 'large' }, { name: 'T-90' });

```
 *If you want to update a single document in the db and return it to your application, use [findOneAndUpdate](api/model#model_Model-findOneAndUpdate) instead.*

  Change Streams
---------------

 [Change streams](https://www.mongodb.com/docs/manual/changeStreams/) provide a way for you to listen to all inserts and updates going through your MongoDB database. Note that change streams do **not** work unless you're connected to a [MongoDB replica set](https://www.mongodb.com/docs/manual/replication/).

 
```
async function run() {
  // Create a new mongoose model
  const personSchema = new mongoose.Schema({
    name: String
  });
  const Person = mongoose.model('Person', personSchema);

  // Create a change stream. The 'change' event gets emitted when there's a
  // change in the database
  Person.watch().
    on('change', data => console.log(new Date(), data));

  // Insert a doc, will trigger the change stream handler above
  console.log(new Date(), 'Inserting doc');
  await Person.create({ name: 'Axl Rose' });
}

```
 The output from the above [async function](http://thecodebarbarian.com/80-20-guide-to-async-await-in-node.js.html) will look like what you see below.

 
```
2018-05-11T15:05:35.467Z 'Inserting doc'
2018-05-11T15:05:35.487Z 'Inserted doc'
2018-05-11T15:05:35.491Z { _id: { _data: ... },
  operationType: 'insert',
  fullDocument: { _id: 5af5b13fe526027666c6bf83, name: 'Axl Rose', __v: 0 },
  ns: { db: 'test', coll: 'Person' },
  documentKey: { _id: 5af5b13fe526027666c6bf83 } }

```
 You can read more about [change streams in mongoose in this blog post](http://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-change-streams.html#change-streams-in-mongoose).

  Views
------

 [MongoDB Views](https://www.mongodb.com/docs/manual/core/views) are essentially read-only collections that contain data computed from other collections using [aggregations](api/aggregate). In Mongoose, you should define a separate Model for each of your Views. You can also create a View using [`createCollection()`](api/model#model_Model-createCollection).

 The following example shows how you can create a new `RedactedUser` View on a `User` Model that hides potentially sensitive information, like name and email.

 
```
// Make sure to disable `autoCreate` and `autoIndex` for Views,
// because you want to create the collection manually.
const userSchema = new Schema({
  name: String,
  email: String,
  roles: [String]
}, { autoCreate: false, autoIndex: false });
const User = mongoose.model('User', userSchema);

const RedactedUser = mongoose.model('RedactedUser', userSchema);

// First, create the User model's underlying collection...
await User.createCollection();
// Then create the `RedactedUser` model's underlying collection
// as a View.
await RedactedUser.createCollection({
  viewOn: 'users', // Set `viewOn` to the collection name, \*\*not\*\* model name.
  pipeline: [
    {
      $set: {
        name: { $concat: [{ $substr: ['$name', 0, 3] }, '...'] },
        email: { $concat: [{ $substr: ['$email', 0, 3] }, '...'] }
      }
    }
  ]
});

await User.create([
  { name: 'John Smith', email: 'john.smith@gmail.com', roles: ['user'] },
  { name: 'Bill James', email: 'bill@acme.co', roles: ['user', 'admin'] }
]);

// [{ \_id: ..., name: 'Bil...', email: 'bil...', roles: ['user', 'admin'] }]
console.log(await RedactedUser.find({ roles: 'admin' }));

```
 Note that Mongoose does **not** currently enforce that Views are read-only. If you attempt to `save()` a document from a View, you will get an error from the MongoDB server.

  Yet more
---------

 The [API docs](api/model#model_Model) cover many additional methods available like [count](api/model#model_Model-count), [mapReduce](api/model#model_Model-mapReduce), [aggregate](api/model#model_Model-aggregate), and [more](api/model#model_Model-findOneAndRemove).

  Next Up
--------

 Now that we've covered `Models`, let's take a look at [Documents](documents).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/models.html>

Queries
========

 Mongoose <models> provide several static helper functions for [CRUD operations](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete). Each of these functions returns a [mongoose `Query` object](api/query#Query).

 * [`Model.deleteMany()`](https://mongoosejs.com/docs/api.html#model_Model-deleteMany)
* [`Model.deleteOne()`](https://mongoosejs.com/docs/api.html#model_Model-deleteOne)
* [`Model.find()`](https://mongoosejs.com/docs/api.html#model_Model-find)
* [`Model.findById()`](https://mongoosejs.com/docs/api.html#model_Model-findById)
* [`Model.findByIdAndDelete()`](https://mongoosejs.com/docs/api.html#model_Model-findByIdAndDelete)
* [`Model.findByIdAndRemove()`](https://mongoosejs.com/docs/api.html#model_Model-findByIdAndRemove)
* [`Model.findByIdAndUpdate()`](https://mongoosejs.com/docs/api.html#model_Model-findByIdAndUpdate)
* [`Model.findOne()`](https://mongoosejs.com/docs/api.html#model_Model-findOne)
* [`Model.findOneAndDelete()`](https://mongoosejs.com/docs/api.html#model_Model-findOneAndDelete)
* [`Model.findOneAndRemove()`](https://mongoosejs.com/docs/api.html#model_Model-findOneAndRemove)
* [`Model.findOneAndReplace()`](https://mongoosejs.com/docs/api.html#model_Model-findOneAndReplace)
* [`Model.findOneAndUpdate()`](https://mongoosejs.com/docs/api.html#model_Model-findOneAndUpdate)
* [`Model.replaceOne()`](https://mongoosejs.com/docs/api.html#model_Model-replaceOne)
* [`Model.updateMany()`](https://mongoosejs.com/docs/api.html#model_Model-updateMany)
* [`Model.updateOne()`](https://mongoosejs.com/docs/api.html#model_Model-updateOne)

 A mongoose query can be executed in one of two ways. First, if you pass in a `callback` function, Mongoose will execute the query asynchronously and pass the results to the `callback`.

 A query also has a `.then()` function, and thus can be used as a promise.

  Executing
----------

 When executing a query, you specify your query as a JSON document. The JSON document's syntax is the same as the [MongoDB shell](http://www.mongodb.com/docs/manual/tutorial/query-documents/).

 
```
const Person = mongoose.model('Person', yourSchema);

// find each person with a last name matching 'Ghost', selecting the `name` and `occupation` fields
const person = await Person.findOne({ 'name.last': 'Ghost' }, 'name occupation');
// Prints "Space Ghost is a talk show host".
console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation);

```
 What `person` is depends on the operation: For `findOne()` it is a [potentially-null single document](api/model#model_Model-findOne), `find()` a [list of documents](api/model#model_Model-find), `count()` [the number of documents](api/model#model_Model-count), `update()` the [number of documents affected](api/model#model_Model-update), etc. The [API docs for Models](api/model) provide more details.

 Now let's look at what happens when no `await` is used:

 
```
// find each person with a last name matching 'Ghost'
const query = Person.findOne({ 'name.last': 'Ghost' });

// selecting the `name` and `occupation` fields
query.select('name occupation');

// execute the query at a later time
const person = await query.exec();
// Prints "Space Ghost is a talk show host."
console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation);

```
 In the above code, the `query` variable is of type [Query](api/query). A `Query` enables you to build up a query using chaining syntax, rather than specifying a JSON object. The below 2 examples are equivalent.

 
```
// With a JSON doc
await Person.
  find({
    occupation: /host/,
    'name.last': 'Ghost',
    age: { $gt: 17, $lt: 66 },
    likes: { $in: ['vaporizing', 'talking'] }
  }).
  limit(10).
  sort({ occupation: -1 }).
  select({ name: 1, occupation: 1 }).
  exec();

// Using query builder
await Person.
  find({ occupation: /host/ }).
  where('name.last').equals('Ghost').
  where('age').gt(17).lt(66).
  where('likes').in(['vaporizing', 'talking']).
  limit(10).
  sort('-occupation').
  select('name occupation').
  exec();

```
 A full list of [Query helper functions can be found in the API docs](api/query).

  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. However, unlike promises, calling a query's `.then()` executes the query, so calling `then()` multiple times will throw an error.

 
```
const q = MyModel.updateMany({}, { isDeleted: true });

await q.then(() => console.log('Update 2'));
// Throws "Query was already executed: Test.updateMany({}, { isDeleted: true })"
await q.then(() => console.log('Update 3'));

```
 References to other documents
-----------------------------

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

 Streaming
---------

 You can [stream](http://nodejs.org/api/stream.html) query results from MongoDB. You need to call the [Query#cursor()](api/query#query_Query-cursor) function to return an instance of [QueryCursor](api/query#query_Query-cursor).

 
```
const cursor = Person.find({ occupation: /host/ }).cursor();

for (let doc = await cursor.next(); doc != null; doc = await cursor.next()) {
  console.log(doc); // Prints documents one at a time
}

```
 Iterating through a Mongoose query using [async iterators](https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js.html) also creates a cursor.

 
```
for await (const doc of Person.find()) {
  console.log(doc); // Prints documents one at a time
}

```
 Cursors are subject to [cursor timeouts](https://stackoverflow.com/questions/21853178/when-a-mongodb-cursor-will-expire). By default, MongoDB will close your cursor after 10 minutes and subsequent `next()` calls will result in a `MongoServerError: cursor id 123 not found` error. To override this, set the `noCursorTimeout` option on your cursor.

 
```
// MongoDB won't automatically close this cursor after 10 minutes.
const cursor = Person.find().cursor().addCursorFlag('noCursorTimeout', true);

```
 However, cursors can still time out because of [session idle timeouts](https://www.mongodb.com/docs/manual/reference/method/cursor.noCursorTimeout/#session-idle-timeout-overrides-nocursortimeout). 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
------------------

 [Aggregation](api/aggregate#aggregate_Aggregate) can do many of the same things that queries can. For example, below is how you can use `aggregate()` to find docs where `name.last = 'Ghost'`:

 
```
const docs = await Person.aggregate([{ $match: { 'name.last': 'Ghost' } }]);

```
 However, just because you can use `aggregate()` doesn't mean you should. In general, you should use queries where possible, and only use `aggregate()` when you absolutely need to.

 Unlike query results, Mongoose does **not** [`hydrate()`](api/model#model_Model-hydrate) aggregation results. Aggregation results are always POJOs, not Mongoose documents.

 
```
const docs = await Person.aggregate([{ $match: { 'name.last': 'Ghost' } }]);

docs[0] instanceof mongoose.Document; // false

```
 Also, unlike query filters, Mongoose also doesn't [cast](tutorials/query_casting) aggregation pipelines. That means you're responsible for ensuring the values you pass in to an aggregation pipeline have the correct type.

 
```
const doc = await Person.findOne();

const idString = doc.\_id.toString();

// Finds the `Person`, because Mongoose casts `idString` to an ObjectId
const queryRes = await Person.findOne({ \_id: idString });

// Does \*\*not\*\* find the `Person`, because Mongoose doesn't cast aggregation
// pipelines.
const aggRes = await Person.aggregate([{ $match: { \_id: idString } }]);

```
 Sorting
-------

 [Sorting](https://mongoosejs.com/docs/api.html#query_Query-sort) is how you can ensure you query results come back in the desired order.

 
```
const personSchema = new mongoose.Schema({
  age: Number
});

const Person = mongoose.model('Person', personSchema);
for (let i = 0; i < 10; i++) {
  await Person.create({ age: i });
}

await Person.find().sort({ age: -1 }); // returns age starting from 10 as the first entry
await Person.find().sort({ age: 1 }); // returns age starting from 0 as the first entry

```
 When sorting with mutiple fields, the order of the sort keys determines what key MongoDB server sorts by first.

 
```
const personSchema = new mongoose.Schema({
  age: Number,
  name: String,
  weight: Number
});

const Person = mongoose.model('Person', personSchema);
const iterations = 5;
for (let i = 0; i < iterations; i++) {
  await Person.create({
    age: Math.abs(2 - i),
    name: 'Test' + i,
    weight: Math.floor(Math.random() * 100) + 1
  });
}

await Person.find().sort({ age: 1, weight: -1 }); // returns age starting from 0, but while keeping that order will then sort by weight.

```
 You can view the output of a single run of this block below. As you can see, age is sorted from 0 to 2 but when age is equal, sorts by weight.

 
```
[
  {
    \_id: new ObjectId('63a335a6b9b6a7bfc186cb37'),
    age: 0,
    name: 'Test2',
    weight: 67,
    \_\_v: 0
  },
  {
    \_id: new ObjectId('63a335a6b9b6a7bfc186cb35'),
    age: 1,
    name: 'Test1',
    weight: 99,
    \_\_v: 0
  },
  {
    \_id: new ObjectId('63a335a6b9b6a7bfc186cb39'),
    age: 1,
    name: 'Test3',
    weight: 73,
    \_\_v: 0
  },
  {
    \_id: new ObjectId('63a335a6b9b6a7bfc186cb33'),
    age: 2,
    name: 'Test0',
    weight: 65,
    \_\_v: 0
  },
  {
    \_id: new ObjectId('63a335a6b9b6a7bfc186cb3b'),
    age: 2,
    name: 'Test4',
    weight: 62,
    \_\_v: 0
  }
];

```
 Next Up
-------

 Now that we've covered `Queries`, let's take a look at [Validation](validation).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/queries.html>

Model
=====



### Model()


##### Parameters:


* `doc` «Object» values for initial set
* `[fields]` «Object» optional object containing the fields that were selected in the query which returned this document. You do **not** need to set this parameter to ensure Mongoose handles your [query projection](query#Query.prototype.select()).
* `[skipId=false]` «Boolean» optional boolean. If true, mongoose doesn't add an `_id` field to the document.


##### Inherits:


* [«Document»](document)



A Model is a class that's your primary tool for interacting with MongoDB. An instance of a Model is called a [Document](document#Document).

 In Mongoose, the term "Model" refers to subclasses of the `mongoose.Model` class. You should not use the `mongoose.Model` class directly. The [`mongoose.model()`](mongoose#Mongoose.prototype.model()) and [`connection.model()`](connection#Connection.prototype.model()) functions create subclasses of `mongoose.Model` as shown below.

 ####   [Example:](#example)

 
```
// `UserModel` is a "Model", a subclass of `mongoose.Model`.
const UserModel = mongoose.model('User', new Schema({ name: String }));

// You can use a Model to create new documents using `new`:
const userDoc = new UserModel({ name: 'Foo' });
await userDoc.save();

// You also use a model to create queries:
const userFromDb = await UserModel.findOne({ name: 'Foo' });

```
 
### Model.$where()


##### Parameters:


* `argument` «String|Function» is a javascript string or anonymous function


##### Returns:


* «Query»


##### See:


* [Query.$where](query#Query.prototype.$where)



Creates a `Query` and specifies a `$where` condition.

 Sometimes you need to query for things in mongodb using a JavaScript expression. You can do so via `find({ $where: javascript })`, or you can use the mongoose shortcut method $where via a Query chain or from your mongoose Model.

 
```
Blog.$where('this.username.indexOf("val") !== -1').exec(function (err, docs) {});

```
 
### Model.aggregate()


##### Parameters:


* `[pipeline]` «Array» aggregation pipeline as an array of objects
* `[options]` «Object» aggregation options


##### Returns:


* «Aggregate»


##### See:


* [Aggregate](aggregate#Aggregate())
* [MongoDB](https://www.mongodb.com/docs/manual/applications/aggregation/)



Performs [aggregations](https://www.mongodb.com/docs/manual/aggregation/) on the models collection.

 If a `callback` is passed, the `aggregate` is executed and a `Promise` is returned. If a callback is not passed, the `aggregate` itself is returned.

 This function triggers the following middleware.

 * `aggregate()`

 ####   [Example:](#example)

 
```
// Find the max balance of all accounts
const res = await Users.aggregate([
  { $group: { \_id: null, maxBalance: { $max: '$balance' }}},
  { $project: { \_id: 0, maxBalance: 1 }}
]);

console.log(res); // [ { maxBalance: 98000 } ]

// Or use the aggregation pipeline builder.
const res = await Users.aggregate().
  group({ \_id: null, maxBalance: { $max: '$balance' } }).
  project('-id maxBalance').
  exec();
console.log(res); // [ { maxBalance: 98 } ]

```
 ####   [Note:](#note)

 * Mongoose does **not** cast aggregation pipelines to the model's schema because `$project` and `$group` operators allow redefining the "shape" of the documents at any stage of the pipeline, which may leave documents in an incompatible format. You can use the [mongoose-cast-aggregation plugin](https://github.com/AbdelrahmanHafez/mongoose-cast-aggregation) to enable minimal casting for aggregation pipelines.
* The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned).

 ####   [More About Aggregations:](#more-about-aggregations)

 * [Mongoose `Aggregate`](aggregate)
* [An Introduction to Mongoose Aggregate](https://masteringjs.io/tutorials/mongoose/aggregate)
* [MongoDB Aggregation docs](https://www.mongodb.com/docs/manual/applications/aggregation/)

 
### Model.applyDefaults()


##### Parameters:


* `obj` «Object|Document» object or document to apply defaults on



Apply defaults to the given document or POJO.

 
### Model.bulkSave()


##### Parameters:


* `documents` «Array<Document>»
* `[options]` «Object» options passed to the underlying `bulkWrite()`
+ `[options.timestamps]` «Boolean» defaults to `null`, when set to false, mongoose will not add/update timestamps to the documents.
+ `[options.session=null]` «ClientSession» The session associated with this bulk write. See [transactions docs](../transactions).
+ `[options.w=1]` «String|number» The [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/). See [`Query#w()`](query#Query.prototype.w()) for more information.
+ `[options.wtimeout=null]` «number» The [write concern timeout](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout).
+ `[options.j=true]` «Boolean» If false, disable [journal acknowledgement](https://www.mongodb.com/docs/manual/reference/write-concern/#j-option)



takes an array of documents, gets the changes and inserts/updates documents in the database according to whether or not the document is new, or whether it has changes or not.

 `bulkSave` uses `bulkWrite` under the hood, so it's mostly useful when dealing with many documents (10K+)

 
### Model.bulkWrite()


##### Parameters:


* `ops` «Array»
+ `[ops.insertOne.document]` «Object» The document to insert
+ `[ops.updateOne.filter]` «Object» Update the first document that matches this filter
+ `[ops.updateOne.update]` «Object» An object containing [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/)
+ `[ops.updateOne.upsert=false]` «Boolean» If true, insert a doc if none match
+ `[ops.updateOne.timestamps=true]` «Boolean» If false, do not apply [timestamps](../guide#timestamps) to the operation
+ `[ops.updateOne.collation]` «Object» The [MongoDB collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) to use
+ `[ops.updateOne.arrayFilters]` «Array» The [array filters](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html) used in `update`
+ `[ops.updateMany.filter]` «Object» Update all the documents that match this filter
+ `[ops.updateMany.update]` «Object» An object containing [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/)
+ `[ops.updateMany.upsert=false]` «Boolean» If true, insert a doc if no documents match `filter`
+ `[ops.updateMany.timestamps=true]` «Boolean» If false, do not apply [timestamps](../guide#timestamps) to the operation
+ `[ops.updateMany.collation]` «Object» The [MongoDB collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) to use
+ `[ops.updateMany.arrayFilters]` «Array» The [array filters](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html) used in `update`
+ `[ops.deleteOne.filter]` «Object» Delete the first document that matches this filter
+ `[ops.deleteMany.filter]` «Object» Delete all documents that match this filter
+ `[ops.replaceOne.filter]` «Object» Replace the first document that matches this filter
+ `[ops.replaceOne.replacement]` «Object» The replacement document
+ `[ops.replaceOne.upsert=false]` «Boolean» If true, insert a doc if no documents match `filter`

* `[options]` «Object»
+ `[options.ordered=true]` «Boolean» If true, execute writes in order and stop at the first error. If false, execute writes in parallel and continue until all writes have either succeeded or errored.
+ `[options.session=null]` «ClientSession» The session associated with this bulk write. See [transactions docs](../transactions).
+ `[options.w=1]` «String|number» The [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/). See [`Query#w()`](query#Query.prototype.w()) for more information.
+ `[options.wtimeout=null]` «number» The [write concern timeout](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout).
+ `[options.j=true]` «Boolean» If false, disable [journal acknowledgement](https://www.mongodb.com/docs/manual/reference/write-concern/#j-option)
+ `[options.skipValidation=false]` «Boolean» Set to true to skip Mongoose schema validation on bulk write operations. Mongoose currently runs validation on `insertOne` and `replaceOne` operations by default.
+ `[options.bypassDocumentValidation=false]` «Boolean» If true, disable [MongoDB server-side schema validation](https://www.mongodb.com/docs/manual/core/schema-validation/) for all writes in this bulk.
+ `[options.throwOnValidationError=false]` «Boolean» If true and `ordered: false`, throw an error if one of the operations failed validation, but all valid operations completed successfully.
+ `[options.strict=null]` «Boolean» Overwrites the [`strict` option](../guide#strict) on schema. If false, allows filtering and writing fields not defined in the schema for all writes in this bulk.


##### Returns:


* «Promise» resolves to a [`BulkWriteOpResult`](https://mongodb.github.io/node-mongodb-native/4.9/classes/BulkWriteResult.html) if the operation succeeds



Sends multiple `insertOne`, `updateOne`, `updateMany`, `replaceOne`, `deleteOne`, and/or `deleteMany` operations to the MongoDB server in one command. This is faster than sending multiple independent operations (e.g. if you use `create()`) because with `bulkWrite()` there is only one round trip to MongoDB.

 Mongoose will perform casting on all operations you provide.

 This function does **not** trigger any middleware, neither `save()`, nor `update()`. If you need to trigger `save()` middleware for every document use [`create()`](#Model.create()) instead.

 ####   [Example:](#example)

 
```
Character.bulkWrite([
  {
    insertOne: {
      document: {
        name: 'Eddard Stark',
        title: 'Warden of the North'
      }
    }
  },
  {
    updateOne: {
      filter: { name: 'Eddard Stark' },
      // If you were using the MongoDB driver directly, you'd need to do
      // `update: { $set: { title: ... } }` but mongoose adds $set for
      // you.
      update: { title: 'Hand of the King' }
    }
  },
  {
    deleteOne: {
      filter: { name: 'Eddard Stark' }
    }
  }
]).then(res => {
 // Prints "1 1 1"
 console.log(res.insertedCount, res.modifiedCount, res.deletedCount);
});

```
 The [supported operations](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#db.collection.bulkWrite) are:

 * `insertOne`
* `updateOne`
* `updateMany`
* `deleteOne`
* `deleteMany`
* `replaceOne`

 
### Model.castObject()


##### Parameters:


* `obj` «Object» object or document to cast
* `options` «Object» options passed to castObject
* `options.ignoreCastErrors` «Boolean» If set to `true` will not throw a ValidationError and only return values that were successfully cast.



Cast the given POJO to the model's schema

 ####   [Example:](#example)

 
```
const Test = mongoose.model('Test', Schema({ num: Number }));

const obj = Test.castObject({ num: '42' });
obj.num; // 42 as a number

Test.castObject({ num: 'not a number' }); // Throws a ValidationError

```
 
### Model.cleanIndexes()


##### Parameters:


* `[callback]` «Function» optional callback


##### Returns:


* «Promise,undefined,void» Returns `undefined` if callback is specified, returns a promise if no callback.



Deletes all indexes that aren't defined in this model's schema. Used by `syncIndexes()`.

 The returned promise resolves to a list of the dropped indexes' names as an array

 
### Model.count()


~DEPRECATED~##### Parameters:


* `[filter]` «Object»


##### Returns:


* «Query»



Counts number of documents that match `filter` in a database collection.

 This method is deprecated. If you want to count the number of documents in a collection, e.g. `count({})`, use the [`estimatedDocumentCount()` function](#Model.estimatedDocumentCount()) instead. Otherwise, use the [`countDocuments()`](#Model.countDocuments()) function instead.

 ####   [Example:](#example)

 
```
const count = await Adventure.count({ type: 'jungle' });
console.log('there are %d jungle adventures', count);

```
 
### Model.countDocuments()


##### Parameters:


* `filter` «Object»


##### Returns:


* «Query»



Counts number of documents matching `filter` in a database collection.

 ####   [Example:](#example)

 
```
Adventure.countDocuments({ type: 'jungle' }, function (err, count) {
  console.log('there are %d jungle adventures', count);
});

```
 If you want to count all documents in a large collection, use the [`estimatedDocumentCount()` function](#Model.estimatedDocumentCount()) instead. If you call `countDocuments({})`, MongoDB will always execute a full collection scan and **not** use any indexes.

 The `countDocuments()` function is similar to `count()`, but there are a [few operators that `countDocuments()` does not support](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#countDocuments). Below are the operators that `count()` supports but `countDocuments()` does not, and the suggested replacement:

 * `$where`: [`$expr`](https://www.mongodb.com/docs/manual/reference/operator/query/expr/)
* `$near`: [`$geoWithin`](https://www.mongodb.com/docs/manual/reference/operator/query/geoWithin/) with [`$center`](https://www.mongodb.com/docs/manual/reference/operator/query/center/#op._S_center)
* `$nearSphere`: [`$geoWithin`](https://www.mongodb.com/docs/manual/reference/operator/query/geoWithin/) with [`$centerSphere`](https://www.mongodb.com/docs/manual/reference/operator/query/centerSphere/#op._S_centerSphere)

 
### Model.create()


##### Parameters:


* `docs` «Array|Object» Documents to insert, as a spread or array
* `[options]` «Object» Options passed down to `save()`. To specify `options`, `docs` **must** be an array, not a spread. See [Model.save](#Model.prototype.save()) for available options.
+ `[options.ordered]` «Boolean» saves the docs in series rather than parallel.
+ `[options.aggregateErrors]` «Boolean» Aggregate Errors instead of throwing the first one that occurs. Default: false


##### Returns:


* «Promise»



Shortcut for saving one or more documents to the database. `MyModel.create(docs)` does `new MyModel(doc).save()` for every doc in docs.

 This function triggers the following middleware.

 * `save()`

 ####   [Example:](#example)

 
```
// Insert one new `Character` document
await Character.create({ name: 'Jean-Luc Picard' });

// Insert multiple new `Character` documents
await Character.create([{ name: 'Will Riker' }, { name: 'Geordi LaForge' }]);

// Create a new character within a transaction. Note that you \*\*must\*\*
// pass an array as the first parameter to `create()` if you want to
// specify options.
await Character.create([{ name: 'Jean-Luc Picard' }], { session });

```
 
### Model.createCollection()


##### Parameters:


* `[options]` «Object» see [MongoDB driver docs](https://mongodb.github.io/node-mongodb-native/4.9/classes/Db.html#createCollection)



Create the collection for this model. By default, if no indexes are specified, mongoose will not create the collection for the model until any documents are created. Use this method to create the collection explicitly.

 Note 1: You may need to call this before starting a transaction See <https://www.mongodb.com/docs/manual/core/transactions/#transactions-and-operations>

 Note 2: You don't have to call this if your schema contains index or unique field. In that case, just use `Model.init()`

 ####   [Example:](#example)

 
```
const userSchema = new Schema({ name: String })
const User = mongoose.model('User', userSchema);

User.createCollection().then(function(collection) {
  console.log('Collection is created!');
});

```
 
### Model.createIndexes()


##### Parameters:


* `[options]` «Object» internal options


##### Returns:


* «Promise»



Similar to `ensureIndexes()`, except for it uses the [`createIndex`](https://mongodb.github.io/node-mongodb-native/4.9/classes/Db.html#createIndex) function.

 
### Model.db


##### Type:


* «property»



Connection instance the model uses.

 
### Model.deleteMany()


##### Parameters:


* `conditions` «Object»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»



Deletes all of the documents that match `conditions` from the collection. It returns an object with the property `deletedCount` containing the number of documents deleted. Behaves like `remove()`, but deletes all documents that match `conditions` regardless of the `single` option.

 ####   [Example:](#example)

 
```
await Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }); // returns {deletedCount: x} where x is the number of documents deleted.

```
 ####   [Note:](#note)

 This function triggers `deleteMany` query hooks. Read the [middleware docs](../middleware#naming) to learn more.

 
### Model.deleteOne()


##### Parameters:


* `conditions` «Object»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»



Deletes the first document that matches `conditions` from the collection. It returns an object with the property `deletedCount` indicating how many documents were deleted. Behaves like `remove()`, but deletes at most one document regardless of the `single` option.

 ####   [Example:](#example)

 
```
await Character.deleteOne({ name: 'Eddard Stark' }); // returns {deletedCount: 1}

```
 ####   [Note:](#note)

 This function triggers `deleteOne` query hooks. Read the [middleware docs](../middleware#naming) to learn more.

 
### Model.diffIndexes()


##### Parameters:


* `[options]` «Object»



Does a dry-run of Model.syncIndexes(), meaning that the result of this function would be the result of Model.syncIndexes().

 
### Model.discriminator()


##### Parameters:


* `name` «String» discriminator model name
* `schema` «Schema» discriminator model schema
* `[options]` «Object|String» If string, same as `options.value`.
+ `[options.value]` «String» the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
+ `[options.clone=true]` «Boolean» By default, `discriminator()` clones the given `schema`. Set to `false` to skip cloning.
+ `[options.overwriteModels=false]` «Boolean» by default, Mongoose does not allow you to define a discriminator with the same name as another discriminator. Set this to allow overwriting discriminators with the same name.
+ `[options.mergeHooks=true]` «Boolean» By default, Mongoose merges the base schema's hooks with the discriminator schema's hooks. Set this option to `false` to make Mongoose use the discriminator schema's hooks instead.
+ `[options.mergePlugins=true]` «Boolean» By default, Mongoose merges the base schema's plugins with the discriminator schema's plugins. Set this option to `false` to make Mongoose use the discriminator schema's plugins instead.


##### Returns:


* «Model» The newly created discriminator model



Adds a discriminator type.

 ####   [Example:](#example)

 
```
function BaseSchema() {
  Schema.apply(this, arguments);

  this.add({
    name: String,
    createdAt: Date
  });
}
util.inherits(BaseSchema, Schema);

const PersonSchema = new BaseSchema();
const BossSchema = new BaseSchema({ department: String });

const Person = mongoose.model('Person', PersonSchema);
const Boss = Person.discriminator('Boss', BossSchema);
new Boss().\_\_t; // "Boss". `\_\_t` is the default `discriminatorKey`

const employeeSchema = new Schema({ boss: ObjectId });
const Employee = Person.discriminator('Employee', employeeSchema, 'staff');
new Employee().\_\_t; // "staff" because of 3rd argument above

```
 
### Model.distinct()


##### Parameters:


* `field` «String»
* `[conditions]` «Object» optional


##### Returns:


* «Query»



Creates a Query for a `distinct` operation.

 ####   [Example:](#example)

 
```
const query = Link.distinct('url');
query.exec();

```
 
### Model.ensureIndexes()


##### Parameters:


* `[options]` «Object» internal options


##### Returns:


* «Promise»



Sends `createIndex` commands to mongo for each index declared in the schema. The `createIndex` commands are sent in series.

 ####   [Example:](#example)

 
```
Event.ensureIndexes(function (err) {
  if (err) return handleError(err);
});

```
 After completion, an `index` event is emitted on this `Model` passing an error if one occurred.

 ####   [Example:](#example-1)

 
```
const eventSchema = new Schema({ thing: { type: 'string', unique: true } })
const Event = mongoose.model('Event', eventSchema);

Event.on('index', function (err) {
  if (err) console.error(err); // error occurred during index creation
})

```
 *NOTE: It is not recommended that you run this in production. Index creation may impact database performance depending on your load. Use with caution.*

 
### Model.estimatedDocumentCount()


##### Parameters:


* `[options]` «Object»


##### Returns:


* «Query»



Estimates the number of documents in the MongoDB collection. Faster than using `countDocuments()` for large collections because `estimatedDocumentCount()` uses collection metadata rather than scanning the entire collection.

 ####   [Example:](#example)

 
```
const numAdventures = await Adventure.estimatedDocumentCount();

```
 
### Model.events


##### Type:


* «property»



Event emitter that reports any errors that occurred. Useful for global error handling.

 ####   [Example:](#example)

 
```
MyModel.events.on('error', err => console.log(err.message));

// Prints a 'CastError' because of the above handler
await MyModel.findOne({ \_id: 'Not a valid ObjectId' }).catch(noop);

```
 
### Model.exists()


##### Parameters:


* `filter` «Object»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())


##### Returns:


* «Query»



Returns a document with `_id` only if at least one document exists in the database that matches the given `filter`, and `null` otherwise.

 Under the hood, `MyModel.exists({ answer: 42 })` is equivalent to `MyModel.findOne({ answer: 42 }).select({ _id: 1 }).lean()`

 ####   [Example:](#example)

 
```
await Character.deleteMany({});
await Character.create({ name: 'Jean-Luc Picard' });

await Character.exists({ name: /picard/i }); // { \_id: ... }
await Character.exists({ name: /riker/i }); // null

```
 This function triggers the following middleware.

 * `findOne()`

 
### Model.find()


##### Parameters:


* `filter` «Object|ObjectId»
* `[projection]` «Object|String|Array[String]» optional fields to return, see [`Query.prototype.select()`](query#Query.prototype.select())
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [field selection](query#Query.prototype.select())
* [query casting](../tutorials/query_casting)



Finds documents.

 Mongoose casts the `filter` to match the model's schema before the command is sent. See our [query casting tutorial](../tutorials/query_casting) for more information on how Mongoose casts `filter`.

 ####   [Example:](#example)

 
```
// find all documents
await MyModel.find({});

// find all documents named john and at least 18
await MyModel.find({ name: 'john', age: { $gte: 18 } }).exec();

// executes, name LIKE john and only selecting the "name" and "friends" fields
await MyModel.find({ name: /john/i }, 'name friends').exec();

// passing options
await MyModel.find({ name: /john/i }, null, { skip: 10 }).exec();

```
 
### Model.findById()


##### Parameters:


* `id` «Any» value of `_id` to query by
* `[projection]` «Object|String|Array[String]» optional fields to return, see [`Query.prototype.select()`](query#Query.prototype.select())
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())


##### Returns:


* «Query»


##### See:


* [field selection](query#Query.prototype.select())
* [lean queries](../tutorials/lean)
* [findById in Mongoose](https://masteringjs.io/tutorials/mongoose/find-by-id)



Finds a single document by its \_id field. `findById(id)` is almost\* equivalent to `findOne({ _id: id })`. If you want to query by a document's `_id`, use `findById()` instead of `findOne()`.

 The `id` is cast based on the Schema before sending the command.

 This function triggers the following middleware.

 * `findOne()`

 \* Except for how it treats `undefined`. If you use `findOne()`, you'll see that `findOne(undefined)` and `findOne({ _id: undefined })` are equivalent to `findOne({})` and return arbitrary documents. However, mongoose translates `findById(undefined)` into `findOne({ _id: null })`.

 ####   [Example:](#example)

 
```
// Find the adventure with the given `id`, or `null` if not found
await Adventure.findById(id).exec();

// select only the adventures name and length
await Adventure.findById(id, 'name length').exec();

```
 
### Model.findByIdAndDelete()


##### Parameters:


* `id` «Object|Number|String» value of `_id` to query by
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [Model.findOneAndRemove](#Model.findOneAndRemove())
* [mongodb](https://www.mongodb.com/docs/manual/reference/command/findAndModify/)



Issue a MongoDB `findOneAndDelete()` command by a document's \_id field. In other words, `findByIdAndDelete(id)` is a shorthand for `findOneAndDelete({ _id: id })`.

 This function triggers the following middleware.

 * `findOneAndDelete()`

 
### Model.findByIdAndRemove()


##### Parameters:


* `id` «Object|Number|String» value of `_id` to query by
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.projection=null]` «Object|String|Array[String]» optional fields to return, see [`Query.prototype.select()`](query#Query.prototype.select())
+ `[options.sort]` «Object|String» if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.select]` «Object|String» sets the document fields to return.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [Model.findOneAndRemove](#Model.findOneAndRemove())
* [mongodb](https://www.mongodb.com/docs/manual/reference/command/findAndModify/)



Issue a mongodb findOneAndRemove command by a document's \_id field. `findByIdAndRemove(id, ...)` is equivalent to `findOneAndRemove({ _id: id }, ...)`.

 Finds a matching document, removes it, and returns the found document (if any).

 This function triggers the following middleware.

 * `findOneAndRemove()`

 ####   [Example:](#example)

 
```
A.findByIdAndRemove(id, options)  // return Query
A.findByIdAndRemove(id) // returns Query
A.findByIdAndRemove()           // returns Query

```
 
### Model.findByIdAndUpdate()


##### Parameters:


* `id` «Object|Number|String» value of `_id` to query by
* `[update]` «Object»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.returnDocument='before']` «String» Has two possible values, `'before'` and `'after'`. By default, it will return the document before the update was applied.
+ `[options.lean]` «Object» if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](query#Query.prototype.lean()) and [the Mongoose lean tutorial](../tutorials/lean).
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ `[options.overwrite=false]` «Boolean» By default, if you don't include any [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/) in `update`, Mongoose will wrap `update` in `$set` for you. This prevents you from accidentally overwriting the document. This option tells Mongoose to skip adding `$set`. An alternative to this would be using [Model.findOneAndReplace({ \_id: id }, update, options)](#Model.findOneAndReplace()).
+ `[options.sort]` «Object|String» if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
+ `[options.runValidators]` «Boolean» if true, runs [update validators](../validation#update-validators) on this command. Update validators validate the update operation against the model's schema
+ `[options.setDefaultsOnInsert=true]` «Boolean» If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](../defaults) specified in the model's schema if a new document is created
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.upsert=false]` «Boolean» if true, and no documents found, insert a new document
+ `[options.new=false]` «Boolean» if true, return the modified document rather than the original
+ `[options.select]` «Object|String» sets the document fields to return.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [Model.findOneAndUpdate](#Model.findOneAndUpdate())
* [mongodb](https://www.mongodb.com/docs/manual/reference/command/findAndModify/)



Issues a mongodb findOneAndUpdate command by a document's \_id field. `findByIdAndUpdate(id, ...)` is equivalent to `findOneAndUpdate({ _id: id }, ...)`.

 Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any).

 This function triggers the following middleware.

 * `findOneAndUpdate()`

 ####   [Example:](#example)

 
```
A.findByIdAndUpdate(id, update, options)  // returns Query
A.findByIdAndUpdate(id, update)           // returns Query
A.findByIdAndUpdate()                     // returns Query

```
 ####   [Note:](#note)

 All top level update keys which are not `atomic` operation names are treated as set operations:

 ####   [Example:](#example-1)

 
```
Model.findByIdAndUpdate(id, { name: 'jason bourne' }, options)

// is sent as
Model.findByIdAndUpdate(id, { $set: { name: 'jason bourne' }}, options)

```
 This helps prevent accidentally overwriting your document with `{ name: 'jason bourne' }`. To prevent this behaviour, see the `overwrite` option

 ####   [Note:](#note-1)

 `findOneAndX` and `findByIdAndX` functions support limited validation. You can enable validation by setting the `runValidators` option.

 If you need full-fledged validation, use the traditional approach of first retrieving the document.

 
```
const doc = await Model.findById(id)
doc.name = 'jason bourne';
await doc.save();

```
 
### Model.findOne()


##### Parameters:


* `[conditions]` «Object»
* `[projection]` «Object|String|Array[String]» optional fields to return, see [`Query.prototype.select()`](query#Query.prototype.select())
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [field selection](query#Query.prototype.select())
* [lean queries](../tutorials/lean)



Finds one document.

 The `conditions` are cast to their respective SchemaTypes before the command is sent.

 *Note:* `conditions` is optional, and if `conditions` is null or undefined, mongoose will send an empty `findOne` command to MongoDB, which will return an arbitrary document. If you're querying by `_id`, use `findById()` instead.

 ####   [Example:](#example)

 
```
// Find one adventure whose `country` is 'Croatia', otherwise `null`
await Adventure.findOne({ country: 'Croatia' }).exec();

// Model.findOne() no longer accepts a callback

// Select only the adventures name and length
await Adventure.findOne({ country: 'Croatia' }, 'name length').exec();

```
 
### Model.findOneAndDelete()


##### Parameters:


* `conditions` «Object»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.projection=null]` «Object|String|Array[String]» optional fields to return, see [`Query.prototype.select()`](query#Query.prototype.select())
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.sort]` «Object|String» if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
+ `[options.select]` «Object|String» sets the document fields to return.
+ `[options.maxTimeMS]` «Number» puts a time limit on the query - requires mongodb >= 2.6.0
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»



Issue a MongoDB `findOneAndDelete()` command.

 Finds a matching document, removes it, and returns the found document (if any).

 This function triggers the following middleware.

 * `findOneAndDelete()`

 This function differs slightly from `Model.findOneAndRemove()` in that `findOneAndRemove()` becomes a [MongoDB `findAndModify()` command](https://www.mongodb.com/docs/manual/reference/method/db.collection.findAndModify/), as opposed to a `findOneAndDelete()` command. For most mongoose use cases, this distinction is purely pedantic. You should use `findOneAndDelete()` unless you have a good reason not to.

 ####   [Example:](#example)

 
```
A.findOneAndDelete(conditions, options)  // return Query
A.findOneAndDelete(conditions) // returns Query
A.findOneAndDelete()           // returns Query

```
 `findOneAndX` and `findByIdAndX` functions support limited validation. You can enable validation by setting the `runValidators` option.

 If you need full-fledged validation, use the traditional approach of first retrieving the document.

 
```
const doc = await Model.findById(id)
doc.name = 'jason bourne';
await doc.save();

```
 
### Model.findOneAndRemove()


##### Parameters:


* `conditions` «Object»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.projection=null]` «Object|String|Array[String]» optional fields to return, see [`Query.prototype.select()`](query#Query.prototype.select())
+ `[options.sort]` «Object|String» if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.select]` «Object|String» sets the document fields to return.
+ `[options.maxTimeMS]` «Number» puts a time limit on the query - requires mongodb >= 2.6.0
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/command/findAndModify/)



Issue a mongodb findOneAndRemove command.

 Finds a matching document, removes it, and returns the found document (if any).

 This function triggers the following middleware.

 * `findOneAndRemove()`

 ####   [Example:](#example)

 
```
A.findOneAndRemove(conditions, options)  // return Query
A.findOneAndRemove(conditions) // returns Query
A.findOneAndRemove()           // returns Query

```
 `findOneAndX` and `findByIdAndX` functions support limited validation. You can enable validation by setting the `runValidators` option.

 If you need full-fledged validation, use the traditional approach of first retrieving the document.

 
```
const doc = await Model.findById(id);
doc.name = 'jason bourne';
await doc.save();

```
 
### Model.findOneAndReplace()


##### Parameters:


* `filter` «Object» Replace the first document that matches this filter
* `[replacement]` «Object» Replace with this document
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.returnDocument='before']` «String» Has two possible values, `'before'` and `'after'`. By default, it will return the document before the update was applied.
+ `[options.lean]` «Object» if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](query#Query.prototype.lean()) and [the Mongoose lean tutorial](../tutorials/lean).
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ `[options.projection=null]` «Object|String|Array[String]» optional fields to return, see [`Query.prototype.select()`](query#Query.prototype.select())
+ `[options.sort]` «Object|String» if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.select]` «Object|String» sets the document fields to return.
+ `[options.maxTimeMS]` «Number» puts a time limit on the query - requires mongodb >= 2.6.0
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»



Issue a MongoDB `findOneAndReplace()` command.

 Finds a matching document, replaces it with the provided doc, and returns the document.

 This function triggers the following query middleware.

 * `findOneAndReplace()`

 ####   [Example:](#example)

 
```
A.findOneAndReplace(filter, replacement, options)  // return Query
A.findOneAndReplace(filter, replacement) // returns Query
A.findOneAndReplace()                    // returns Query

```
 
### Model.findOneAndUpdate()


##### Parameters:


* `[conditions]` «Object»
* `[update]` «Object»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.returnDocument='before']` «String» Has two possible values, `'before'` and `'after'`. By default, it will return the document before the update was applied.
+ `[options.lean]` «Object» if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](query#Query.prototype.lean()) and [the Mongoose lean tutorial](../tutorials/lean).
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ `[options.overwrite=false]` «Boolean» By default, if you don't include any [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/) in `update`, Mongoose will wrap `update` in `$set` for you. This prevents you from accidentally overwriting the document. This option tells Mongoose to skip adding `$set`. An alternative to this would be using [Model.findOneAndReplace(conditions, update, options, callback)](#Model.findOneAndReplace()).
+ `[options.upsert=false]` «Boolean» if true, and no documents found, insert a new document
+ `[options.projection=null]` «Object|String|Array[String]» optional fields to return, see [`Query.prototype.select()`](query#Query.prototype.select())
+ `[options.new=false]` «Boolean» if true, return the modified document rather than the original
+ `[options.fields]` «Object|String» Field selection. Equivalent to `.select(fields).findOneAndUpdate()`
+ `[options.maxTimeMS]` «Number» puts a time limit on the query - requires mongodb >= 2.6.0
+ `[options.sort]` «Object|String» if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
+ `[options.runValidators]` «Boolean» if true, runs [update validators](../validation#update-validators) on this command. Update validators validate the update operation against the model's schema
+ `[options.setDefaultsOnInsert=true]` «Boolean» If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](../defaults) specified in the model's schema if a new document is created
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [Tutorial](../tutorials/findoneandupdate)
* [mongodb](https://www.mongodb.com/docs/manual/reference/command/findAndModify/)



Issues a mongodb findOneAndUpdate command.

 Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes if `callback` is passed else a Query object is returned.

 ####   [Example:](#example)

 
```
A.findOneAndUpdate(conditions, update, options)  // returns Query
A.findOneAndUpdate(conditions, update)           // returns Query
A.findOneAndUpdate()                             // returns Query

```
 ####   [Note:](#note)

 All top level update keys which are not `atomic` operation names are treated as set operations:

 ####   [Example:](#example-1)

 
```
const query = { name: 'borne' };
Model.findOneAndUpdate(query, { name: 'jason bourne' }, options)

// is sent as
Model.findOneAndUpdate(query, { $set: { name: 'jason bourne' }}, options)

```
 ####   [Note:](#note-1)

 `findOneAndX` and `findByIdAndX` functions support limited validation that you can enable by setting the `runValidators` option.

 If you need full-fledged validation, use the traditional approach of first retrieving the document.

 
```
const doc = await Model.findById(id);
doc.name = 'jason bourne';
await doc.save();

```
 
### Model.hydrate()


##### Parameters:


* `obj` «Object»
* `[projection]` «Object|String|Array[String]» optional projection containing which fields should be selected for this document
* `[options]` «Object» optional options
+ `[options.setters=false]` «Boolean» if true, apply schema setters when hydrating


##### Returns:


* «Document» document instance



Shortcut for creating a new Document from existing raw data, pre-saved in the DB. The document returned has no paths marked as modified initially.

 ####   [Example:](#example)

 
```
// hydrate previous data into a Mongoose document
const mongooseCandy = Candy.hydrate({ \_id: '54108337212ffb6d459f854c', type: 'jelly bean' });

```
 
### Model.init()



This function is responsible for building [indexes](https://www.mongodb.com/docs/manual/indexes/), unless [`autoIndex`](../guide#autoIndex) is turned off.

 Mongoose calls this function automatically when a model is created using [`mongoose.model()`](mongoose#Mongoose.prototype.model()) or [`connection.model()`](connection#Connection.prototype.model()), so you don't need to call `init()` to trigger index builds.

 However, you *may* need to call `init()` to get back a promise that will resolve when your indexes are finished. Calling `await Model.init()` is helpful if you need to wait for indexes to build before continuing. For example, if you want to wait for unique indexes to build before continuing with a test case.

 ####   [Example:](#example)

 
```
const eventSchema = new Schema({ thing: { type: 'string', unique: true } })
// This calls `Event.init()` implicitly, so you don't need to call
// `Event.init()` on your own.
const Event = mongoose.model('Event', eventSchema);

await Event.init();
console.log('Indexes are done building!');

```
 
### Model.insertMany()


##### Parameters:


* `doc(s)` «Array|Object|[object Object]»
* `[options]` «Object» see the [mongodb driver options](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#insertMany)
+ `[options.ordered=true]` «Boolean» if true, will fail fast on the first error encountered. If false, will insert all the documents it can and report errors later. An `insertMany()` with `ordered = false` is called an "unordered" `insertMany()`.
+ `[options.rawResult=false]` «Boolean» if false, the returned promise resolves to the documents that passed mongoose document validation. If `true`, will return the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/InsertManyResult.html) with a `mongoose` property that contains `validationErrors` and `results` if this is an unordered `insertMany`.
+ `[options.lean=false]` «Boolean» if `true`, skips hydrating and validating the documents. This option is useful if you need the extra performance, but Mongoose won't validate the documents before inserting.
+ `[options.limit=null]` «Number» this limits the number of documents being processed (validation/casting) by mongoose in parallel, this does **NOT** send the documents in batches to MongoDB. Use this option if you're processing a large number of documents and your app is running out of memory.
+ `[options.populate=null]` «String|Object|Array» populates the result documents. This option is a no-op if `rawResult` is set.
+ `[options.throwOnValidationError=false]` «Boolean» If true and `ordered: false`, throw an error if one of the operations failed validation, but all valid operations completed successfully.


##### Returns:


* «Promise» resolving to the raw result from the MongoDB driver if `options.rawResult` was `true`, or the documents that passed validation, otherwise



Shortcut for validating an array of documents and inserting them into MongoDB if they're all valid. This function is faster than `.create()` because it only sends one operation to the server, rather than one for each document.

 Mongoose always validates each document **before** sending `insertMany` to MongoDB. So if one document has a validation error, no documents will be saved, unless you set [the `ordered` option to false](https://www.mongodb.com/docs/manual/reference/method/db.collection.insertMany/#error-handling).

 This function does **not** trigger save middleware.

 This function triggers the following middleware.

 * `insertMany()`

 ####   [Example:](#example)

 
```
await Movies.insertMany([
  { name: 'Star Wars' },
  { name: 'The Empire Strikes Back' }
]);

```
 
### Model.inspect()



Helper for console.log. Given a model named 'MyModel', returns the string `'Model { MyModel }'`.

 ####   [Example:](#example)

 
```
const MyModel = mongoose.model('Test', Schema({ name: String }));
MyModel.inspect(); // 'Model { Test }'
console.log(MyModel); // Prints 'Model { Test }'

```
 
### Model.listIndexes()


##### Returns:


* «Promise»



Lists the indexes currently defined in MongoDB. This may or may not be the same as the indexes defined in your schema depending on whether you use the [`autoIndex` option](../guide#autoIndex) and if you build indexes manually.

 
### Model.populate()


##### Parameters:


* `docs` «Document|Array» Either a single document or array of documents to populate.
* `options` «Object|String» Either the paths to populate or an object specifying all parameters
+ `[options.path=null]` «string» The path to populate.
+ `[options.populate=null]` «string|PopulateOptions» Recursively populate paths in the populated documents. See [deep populate docs](../populate#deep-populate).
+ `[options.retainNullValues=false]` «boolean» By default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
+ `[options.getters=false]` «boolean» If true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](../schematypes#schematype-options).
+ `[options.clone=false]` «boolean» When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
+ `[options.match=null]` «Object|Function» Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/), or a function that returns a filter object.
+ `[options.skipInvalidIds=false]` «Boolean» By default, Mongoose throws a cast error if `localField` and `foreignField` schemas don't line up. If you enable this option, Mongoose will instead filter out any `localField` properties that cannot be casted to `foreignField`'s schema type.
+ `[options.perDocumentLimit=null]` «Number» For legacy reasons, `limit` with `populate()` may give incorrect results because it only executes a single query for every document being populated. If you set `perDocumentLimit`, Mongoose will ensure correct `limit` per document by executing a separate query for each document to `populate()`. For example, `.find().populate({ path: 'test', perDocumentLimit: 2 })` will execute 2 additional queries if `.find()` returns 2 documents.
+ `[options.strictPopulate=true]` «Boolean» Set to false to allow populating paths that aren't defined in the given model's schema.
+ `[options.options=null]` «Object» Additional options like `limit` and `lean`.
+ `[options.transform=null]` «Function» Function that Mongoose will call on every populated document that allows you to transform the populated document.

* `[callback(err,doc)]` «Function» Optional callback, executed upon completion. Receives `err` and the `doc(s)`.


##### Returns:


* «Promise»



Populates document references.

 Changed in Mongoose 6: the model you call `populate()` on should be the "local field" model, **not** the "foreign field" model.

 ####   [Available top-level options:](#available-top-level-options)

 * path: space delimited path(s) to populate
* select: optional fields to select
* match: optional query conditions to match
* model: optional name of the model to use for population
* options: optional query options like sort, limit, etc
* justOne: optional boolean, if true Mongoose will always set `path` to a document, or `null` if no document was found. If false, Mongoose will always set `path` to an array, which will be empty if no documents are found. Inferred from schema by default.
* strictPopulate: optional boolean, set to `false` to allow populating paths that aren't in the schema.

 ####   [Example:](#example)

 
```
const Dog = mongoose.model('Dog', new Schema({ name: String, breed: String }));
const Person = mongoose.model('Person', new Schema({
  name: String,
  pet: { type: mongoose.ObjectId, ref: 'Dog' }
}));

const pets = await Pet.create([
  { name: 'Daisy', breed: 'Beagle' },
  { name: 'Einstein', breed: 'Catalan Sheepdog' }
]);

// populate many plain objects
const users = [
  { name: 'John Wick', dog: pets[0].\_id },
  { name: 'Doc Brown', dog: pets[1].\_id }
];
await User.populate(users, { path: 'dog', select: 'name' });
users[0].dog.name; // 'Daisy'
users[0].dog.breed; // undefined because of `select`

```
 
### Model.prototype.$model()


##### Parameters:


* `name` «String» model name


##### Returns:


* «Model»



Returns another Model instance.

 ####   [Example:](#example)

 
```
const doc = new Tank;
await doc.model('User').findById(id);

```
 
### Model.prototype.$where


##### Type:


* «property»



Additional properties to attach to the query when calling `save()` and `isNew` is false.

 
### Model.prototype.base


##### Type:


* «property»



Base Mongoose instance the model uses.

 
### Model.prototype.baseModelName


##### Type:


* «property»



If this is a discriminator model, `baseModelName` is the name of the base model.

 
### Model.prototype.collection


##### Type:


* «property»



The collection instance this model uses. A Mongoose collection is a thin wrapper around a [MongoDB Node.js driver collection]([MongoDB Node.js driver collection](https://mongodb.github.io/node-mongodb-native/Next/classes/Collection.html)). Using `Model.collection` means you bypass Mongoose middleware, validation, and casting.

 This property is read-only. Modifying this property is a no-op.

 
### Model.prototype.collection


##### Type:


* «property»



Collection the model uses.

 
### Model.prototype.db


##### Type:


* «property»



Connection the model uses.

 
### Model.prototype.deleteOne()


##### Returns:


* «Promise» Promise



Removes this document from the db. Equivalent to `.remove()`.

 ####   [Example:](#example)

 
```
product = await product.deleteOne();
await Product.findById(product.\_id); // null

```
 
### Model.prototype.discriminators


##### Type:


* «property»



Registered discriminators for this model.

 
### Model.prototype.increment()


##### See:


* [versionKeys](../guide#versionKey)



Signal that we desire an increment of this documents version.

 ####   [Example:](#example)

 
```
const doc = await Model.findById(id);
doc.increment();
await doc.save();

```
 
### Model.prototype.model()


##### Parameters:


* `name` «String» model name


##### Returns:


* «Model»



Returns another Model instance.

 ####   [Example:](#example)

 
```
const doc = new Tank;
await doc.model('User').findById(id);

```
 
### Model.prototype.modelName


##### Type:


* «property»



The name of the model

 
### Model.prototype.save()


##### Parameters:


* `[options]` «Object» options optional options
+ `[options.session=null]` «Session» the [session](https://www.mongodb.com/docs/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](document#Document.prototype.session()).
+ `[options.safe]` «Object» (DEPRECATED) overrides [schema's safe option](../guide#safe). Use the `w` option instead.
+ `[options.validateBeforeSave]` «Boolean» set to false to save without validating.
+ `[options.validateModifiedOnly=false]` «Boolean» if `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
+ `[options.w]` «Number|String» set the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/#w-option). Overrides the [schema-level `writeConcern` option](../guide#writeConcern)
+ `[options.j]` «Boolean» set to true for MongoDB to wait until this `save()` has been [journaled before resolving the returned promise](https://www.mongodb.com/docs/manual/reference/write-concern/#j-option). Overrides the [schema-level `writeConcern` option](../guide#writeConcern)
+ `[options.wtimeout]` «Number» sets a [timeout for the write concern](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](../guide#writeConcern).
+ `[options.checkKeys=true]` «Boolean» the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://docs.mongodb.com/manual/reference/limits/#mongodb-limit-Restrictions-on-Field-Names)
+ `[options.timestamps=true]` «Boolean» if `false` and [timestamps](../guide#timestamps) are enabled, skip timestamps for this `save()`.


##### Returns:


* «Promise»


##### See:


* [middleware](../middleware)



Saves this document by inserting a new document into the database if [document.isNew](document#Document.prototype.isNew) is `true`, or sends an [updateOne](document#Document.prototype.updateOne()) operation with just the modified paths if `isNew` is `false`.

 ####   [Example:](#example)

 
```
product.sold = Date.now();
product = await product.save();

```
 If save is successful, the returned promise will fulfill with the document saved.

 ####   [Example:](#example-1)

 
```
const newProduct = await product.save();
newProduct === product; // true

```
 
### Model.replaceOne()


##### Parameters:


* `filter` «Object»
* `doc` «Object»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.upsert=false]` «Boolean» if true, and no documents found, insert a new document
+ `[options.writeConcern=null]` «Object» sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](../guide#writeConcern)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [Query docs](../queries)
* [UpdateResult](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/UpdateResult.html)



Replace the existing document with the given document (no atomic operators like `$set`).

 ####   [Example:](#example)

 
```
const res = await Person.replaceOne({ \_id: 24601 }, { name: 'Jean Valjean' });
res.matchedCount; // Number of documents matched
res.modifiedCount; // Number of documents modified
res.acknowledged; // Boolean indicating everything went smoothly.
res.upsertedId; // null or an id containing a document that had to be upserted.
res.upsertedCount; // Number indicating how many documents had to be upserted. Will either be 0 or 1.

```
 This function triggers the following middleware.

 * `replaceOne()`

 
### Model.schema


##### Type:


* «property»



Schema the model uses.

 
### Model.startSession()


##### Parameters:


* `[options]` «Object» see the [mongodb driver options](https://mongodb.github.io/node-mongodb-native/4.9/classes/MongoClient.html#startSession)
+ `[options.causalConsistency=true]` «Boolean» set to false to disable causal consistency


##### Returns:


* «Promise<ClientSession>» promise that resolves to a MongoDB driver `ClientSession`



*Requires MongoDB >= 3.6.0.* Starts a [MongoDB session](https://www.mongodb.com/docs/manual/release-notes/3.6/#client-sessions) for benefits like causal consistency, [retryable writes](https://www.mongodb.com/docs/manual/core/retryable-writes/), and [transactions](https://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html).

 Calling `MyModel.startSession()` is equivalent to calling `MyModel.db.startSession()`.

 This function does not trigger any middleware.

 ####   [Example:](#example)

 
```
const session = await Person.startSession();
let doc = await Person.findOne({ name: 'Ned Stark' }, null, { session });
await doc.remove();
// `doc` will always be null, even if reading from a replica set
// secondary. Without causal consistency, it is possible to
// get a doc back from the below query if the query reads from a
// secondary that is experiencing replication lag.
doc = await Person.findOne({ name: 'Ned Stark' }, null, { session, readPreference: 'secondary' });

```
 
### Model.syncIndexes()


##### Parameters:


* `[options]` «Object» options to pass to `ensureIndexes()`
+ `[options.background=null]` «Boolean» if specified, overrides each index's `background` property


##### Returns:


* «Promise»



Makes the indexes in MongoDB match the indexes defined in this model's schema. This function will drop any indexes that are not defined in the model's schema except the `_id` index, and build any indexes that are in your schema but not in MongoDB.

 See the [introductory blog post](https://thecodebarbarian.com/whats-new-in-mongoose-5-2-syncindexes) for more information.

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: { type: String, unique: true } });
const Customer = mongoose.model('Customer', schema);
await Customer.collection.createIndex({ age: 1 }); // Index is not in schema
// Will drop the 'age' index and create an index on `name`
await Customer.syncIndexes();

```
 
### Model.translateAliases()


##### Parameters:


* `fields` «Object» fields/conditions that may contain aliased keys
* `[errorOnDuplicates]` «Boolean» if true, throw an error if there's both a key and an alias for that key in `fields`


##### Returns:


* «Object» the translated 'pure' fields/conditions



Translate any aliases fields/conditions so the final query or document object is pure

 ####   [Example:](#example)

 
```
await Character.find(Character.translateAliases({
   '名': 'Eddard Stark' // Alias for 'name'
});

```
 By default, `translateAliases()` overwrites raw fields with aliased fields. So if `n` is an alias for `name`, `{ n: 'alias', name: 'raw' }` will resolve to `{ name: 'alias' }`. However, you can set the `errorOnDuplicates` option to throw an error if there are potentially conflicting paths. The `translateAliases` option for queries uses `errorOnDuplicates`.

 ####   [Note:](#note)

 Only translate arguments of object type anything else is returned raw

 
### Model.updateMany()


##### Parameters:


* `filter` «Object»
* `update` «Object|Array»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.upsert=false]` «Boolean» if true, and no documents found, insert a new document
+ `[options.writeConcern=null]` «Object» sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](../guide#writeConcern)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [Query docs](../queries)
* [MongoDB docs](https://www.mongodb.com/docs/manual/reference/command/update/#update-command-output)
* [UpdateResult](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/UpdateResult.html)



Same as `updateOne()`, except MongoDB will update *all* documents that match `filter` (as opposed to just the first one) regardless of the value of the `multi` option.

 **Note** updateMany will *not* fire update middleware. Use `pre('updateMany')` and `post('updateMany')` instead.

 ####   [Example:](#example)

 
```
const res = await Person.updateMany({ name: /Stark$/ }, { isDeleted: true });
res.matchedCount; // Number of documents matched
res.modifiedCount; // Number of documents modified
res.acknowledged; // Boolean indicating everything went smoothly.
res.upsertedId; // null or an id containing a document that had to be upserted.
res.upsertedCount; // Number indicating how many documents had to be upserted. Will either be 0 or 1.

```
 This function triggers the following middleware.

 * `updateMany()`

 
### Model.updateOne()


##### Parameters:


* `filter` «Object»
* `update` «Object|Array»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.upsert=false]` «Boolean» if true, and no documents found, insert a new document
+ `[options.writeConcern=null]` «Object» sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](../guide#writeConcern)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query»


##### See:


* [Query docs](../queries)
* [MongoDB docs](https://www.mongodb.com/docs/manual/reference/command/update/#update-command-output)
* [UpdateResult](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/UpdateResult.html)



Update *only* the first document that matches `filter`.

 * Use `replaceOne()` if you want to overwrite an entire document rather than using atomic operators like `$set`.

 ####   [Example:](#example)

 
```
const res = await Person.updateOne({ name: 'Jean-Luc Picard' }, { ship: 'USS Enterprise' });
res.matchedCount; // Number of documents matched
res.modifiedCount; // Number of documents modified
res.acknowledged; // Boolean indicating everything went smoothly.
res.upsertedId; // null or an id containing a document that had to be upserted.
res.upsertedCount; // Number indicating how many documents had to be upserted. Will either be 0 or 1.

```
 This function triggers the following middleware.

 * `updateOne()`

 
### Model.validate()


##### Parameters:


* `obj` «Object»
* `pathsToValidate` «Array|String»
* `[context]` «Object»


##### Returns:


* «Promise,undefined,void»



Casts and validates the given object against this model's schema, passing the given `context` to custom validators.

 ####   [Example:](#example)

 
```
const Model = mongoose.model('Test', Schema({
  name: { type: String, required: true },
  age: { type: Number, required: true }
});

try {
  await Model.validate({ name: null }, ['name'])
} catch (err) {
  err instanceof mongoose.Error.ValidationError; // true
  Object.keys(err.errors); // ['name']
}

```
 
### Model.watch()


##### Parameters:


* `[pipeline]` «Array»
* `[options]` «Object» see the [mongodb driver options](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#watch)
+ `[options.hydrate=false]` «Boolean» if true and `fullDocument: 'updateLookup'` is set, Mongoose will automatically hydrate `fullDocument` into a fully fledged Mongoose document


##### Returns:


* «ChangeStream» mongoose-specific change stream wrapper, inherits from EventEmitter



*Requires a replica set running MongoDB >= 3.6.0.* Watches the underlying collection for changes using [MongoDB change streams](https://www.mongodb.com/docs/manual/changeStreams/).

 This function does **not** trigger any middleware. In particular, it does **not** trigger aggregate middleware.

 The ChangeStream object is an event emitter that emits the following events:

 * 'change': A change occurred, see below example
* 'error': An unrecoverable error occurred. In particular, change streams currently error out if they lose connection to the replica set primary. Follow [this GitHub issue](https://github.com/Automattic/mongoose/issues/6799) for updates.
* 'end': Emitted if the underlying stream is closed
* 'close': Emitted if the underlying stream is closed

 ####   [Example:](#example)

 
```
const doc = await Person.create({ name: 'Ned Stark' });
const changeStream = Person.watch().on('change', change => console.log(change));
// Will print from the above `console.log()`:
// { \_id: { \_data: ... },
// operationType: 'delete',
// ns: { db: 'mydb', coll: 'Person' },
// documentKey: { \_id: 5a51b125c5500f5aa094c7bd } }
await doc.remove();

```
 
### Model.where()


##### Parameters:


* `path` «String»
* `[val]` «Object» optional value


##### Returns:


* «Query»



Creates a Query, applies the passed conditions, and returns the Query.

 For example, instead of writing:

 
```
User.find({ age: { $gte: 21, $lte: 65 } });

```
 we can instead write:

 
```
User.where('age').gte(21).lte(65).exec();

```
 Since the Query class also supports `where` you can continue chaining

 
```
User
.where('age').gte(21).lte(65)
.where('name', /^b/i)
... etc

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/model.html>

Mongoose
========



### Mongoose()


##### Parameters:


* `options` «Object» see [`Mongoose#set()` docs](#Mongoose.prototype.set())



Mongoose constructor.

 The exports object of the `mongoose` module is an instance of this class. Most apps will only use this one instance.

 ####   [Example:](#example)

 
```
const mongoose = require('mongoose');
mongoose instanceof mongoose.Mongoose; // true

// Create a new Mongoose instance with its own `connect()`, `set()`, `model()`, etc.
const m = new mongoose.Mongoose();

```
 
### Mongoose.prototype.Aggregate()



The Mongoose Aggregate constructor

 
### Mongoose.prototype.CastError()


##### Parameters:


* `type` «String» The name of the type
* `value` «Any» The value that failed to cast
* `path` «String» The path `a.b.c` in the doc where this cast error occurred
* `[reason]` «Error» The original error that was thrown



The Mongoose CastError constructor

 
### Mongoose.prototype.Collection()



The Mongoose Collection constructor

 
### Mongoose.prototype.Connection()



The Mongoose [Connection](connection#Connection()) constructor

 
### Mongoose.prototype.ConnectionStates


##### Type:


* «property»



Expose connection states for user-land

 
### Mongoose.prototype.Date


##### Type:


* «property»



The Mongoose Date [SchemaType](../schematypes).

 ####   [Example:](#example)

 
```
const schema = new Schema({ test: Date });
schema.path('test') instanceof mongoose.Date; // true

```
 
### Mongoose.prototype.Decimal128


##### Type:


* «property»



The Mongoose Decimal128 [SchemaType](../schematypes). Used for declaring paths in your schema that should be [128-bit decimal floating points](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-decimal.html). Do not use this to create a new Decimal128 instance, use `mongoose.Types.Decimal128` instead.

 ####   [Example:](#example)

 
```
const vehicleSchema = new Schema({ fuelLevel: mongoose.Decimal128 });

```
 
### Mongoose.prototype.Document()



The Mongoose [Document](document#Document()) constructor.

 
### Mongoose.prototype.DocumentProvider()



The Mongoose DocumentProvider constructor. Mongoose users should not have to use this directly

 
### Mongoose.prototype.Error()



The [MongooseError](error#Error()) constructor.

 
### Mongoose.prototype.Mixed


##### Type:


* «property»



The Mongoose Mixed [SchemaType](../schematypes). Used for declaring paths in your schema that Mongoose's change tracking, casting, and validation should ignore.

 ####   [Example:](#example)

 
```
const schema = new Schema({ arbitrary: mongoose.Mixed });

```
 
### Mongoose.prototype.Model()



The Mongoose [Model](model#Model()) constructor.

 
### Mongoose.prototype.Mongoose()



The Mongoose constructor

 The exports of the mongoose module is an instance of this class.

 ####   [Example:](#example)

 
```
const mongoose = require('mongoose');
const mongoose2 = new mongoose.Mongoose();

```
 
### Mongoose.prototype.Number


##### Type:


* «property»



The Mongoose Number [SchemaType](../schematypes). Used for declaring paths in your schema that Mongoose should cast to numbers.

 ####   [Example:](#example)

 
```
const schema = new Schema({ num: mongoose.Number });
// Equivalent to:
const schema = new Schema({ num: 'number' });

```
 
### Mongoose.prototype.ObjectId


##### Type:


* «property»



The Mongoose ObjectId [SchemaType](../schematypes). Used for declaring paths in your schema that should be [MongoDB ObjectIds](https://www.mongodb.com/docs/manual/reference/method/ObjectId/). Do not use this to create a new ObjectId instance, use `mongoose.Types.ObjectId` instead.

 ####   [Example:](#example)

 
```
const childSchema = new Schema({ parentId: mongoose.ObjectId });

```
 
### Mongoose.prototype.Query()



The Mongoose [Query](query#Query()) constructor.

 
### Mongoose.prototype.STATES


##### Type:


* «property»



Expose connection states for user-land

 
### Mongoose.prototype.Schema()



The Mongoose [Schema](schema#Schema()) constructor

 ####   [Example:](#example)

 
```
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CatSchema = new Schema(..);

```
 
### Mongoose.prototype.SchemaType()



The Mongoose [SchemaType](schematype#SchemaType()) constructor

 
### Mongoose.prototype.SchemaTypeOptions()



The constructor used for schematype options

 
### Mongoose.prototype.SchemaTypes


##### Type:


* «property»


##### See:


* [Schema.SchemaTypes](../schematypes)



The various Mongoose SchemaTypes.

 ####   [Note:](#note)

 *Alias of mongoose.Schema.Types for backwards compatibility.*

 
### Mongoose.prototype.Types


##### Type:


* «property»



The various Mongoose Types.

 ####   [Example:](#example)

 
```
const mongoose = require('mongoose');
const array = mongoose.Types.Array;

```
 ####   [Types:](#types)

 * [Array](../schematypes#arrays)
* [Buffer](../schematypes#buffers)
* [Embedded](../schematypes#schemas)
* [DocumentArray](documentarraypath)
* [Decimal128](#Mongoose.prototype.Decimal128)
* [ObjectId](../schematypes#objectids)
* [Map](../schematypes#maps)
* [Subdocument](../schematypes#schemas)

 Using this exposed access to the `ObjectId` type, we can construct ids on demand.

 
```
const ObjectId = mongoose.Types.ObjectId;
const id1 = new ObjectId;

```
 
### Mongoose.prototype.VirtualType()



The Mongoose [VirtualType](virtualtype#VirtualType()) constructor

 
### Mongoose.prototype.connect()


##### Parameters:


* `uri` «String» mongodb URI to connect to
* `[options]` «Object» passed down to the [MongoDB driver's `connect()` function](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html), except for 4 mongoose-specific options explained below.
+ `[options.bufferCommands=true]` «Boolean» Mongoose specific option. Set to false to [disable buffering](https://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
+ `[options.bufferTimeoutMS=10000]` «Number» Mongoose specific option. If `bufferCommands` is true, Mongoose will throw an error after `bufferTimeoutMS` if the operation is still buffered.
+ `[options.dbName]` «String» The name of the database we want to use. If not provided, use database name from connection string.
+ `[options.user]` «String» username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
+ `[options.pass]` «String» password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
+ `[options.maxPoolSize=100]` «Number» The maximum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
+ `[options.minPoolSize=0]` «Number» The minimum number of sockets the MongoDB driver will keep open for this connection.
+ `[options.serverSelectionTimeoutMS]` «Number» If `useUnifiedTopology = true`, the MongoDB driver will try to find a server to send any given operation to, and keep retrying for `serverSelectionTimeoutMS` milliseconds before erroring out. If not set, the MongoDB driver defaults to using `30000` (30 seconds).
+ `[options.heartbeatFrequencyMS]` «Number» If `useUnifiedTopology = true`, 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.
+ `[options.autoIndex=true]` «Boolean» Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
+ `[options.promiseLibrary]` «Class» Sets the [underlying driver's promise library](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html#promiseLibrary).
+ `[options.socketTimeoutMS=0]` «Number» How long the MongoDB driver will wait before killing a socket due to inactivity *after initial connection*. A socket may be inactive because of either no activity or a long-running operation. `socketTimeoutMS` defaults to 0, which means Node.js will not time out the socket due to inactivity. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
+ `[options.family=0]` «Number» Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0`, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
+ `[options.autoCreate=false]` «Boolean» Set to `true` to make Mongoose automatically call `createCollection()` on every model created on this connection.

* `[callback]` «Function»


##### Returns:


* «Promise» resolves to `this` if connection succeeded


##### See:


* [Mongoose#createConnection](#Mongoose.prototype.createConnection())



Opens the default mongoose connection.

 ####   [Example:](#example)

 
```
mongoose.connect('mongodb://user:pass@127.0.0.1:port/database');

// replica sets
const uri = 'mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/mydatabase';
mongoose.connect(uri);

// with options
mongoose.connect(uri, options);

// optional callback that gets fired when initial connection completed
const uri = 'mongodb://nonexistent.domain:27000';
mongoose.connect(uri, function(error) {
  // if error is truthy, the initial connection failed.
})

```
 
### Mongoose.prototype.connection


##### Type:


* «Connection»



The Mongoose module's default connection. Equivalent to `mongoose.connections[0]`, see [`connections`](#Mongoose.prototype.connections).

 ####   [Example:](#example)

 
```
const mongoose = require('mongoose');
mongoose.connect(...);
mongoose.connection.on('error', cb);

```
 This is the connection used by default for every model created using [mongoose.model](#Mongoose.prototype.model()).

 To create a new connection, use [`createConnection()`](#Mongoose.prototype.createConnection()).

 
### Mongoose.prototype.connections


##### Type:


* «Array»



An array containing all [connections](connection) associated with this Mongoose instance. By default, there is 1 connection. Calling [`createConnection()`](#Mongoose.prototype.createConnection()) adds a connection to this array.

 ####   [Example:](#example)

 
```
const mongoose = require('mongoose');
mongoose.connections.length; // 1, just the default connection
mongoose.connections[0] === mongoose.connection; // true

mongoose.createConnection('mongodb://127.0.0.1:27017/test');
mongoose.connections.length; // 2

```
 
### Mongoose.prototype.createConnection()


##### Parameters:


* `uri` «String» mongodb URI to connect to
* `[options]` «Object» passed down to the [MongoDB driver's `connect()` function](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html), except for 4 mongoose-specific options explained below.
+ `[options.bufferCommands=true]` «Boolean» Mongoose specific option. Set to false to [disable buffering](https://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
+ `[options.dbName]` «String» The name of the database you want to use. If not provided, Mongoose uses the database name from connection string.
+ `[options.user]` «String» username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
+ `[options.pass]` «String» password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
+ `[options.autoIndex=true]` «Boolean» Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
+ `[options.promiseLibrary]` «Class» Sets the [underlying driver's promise library](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html#promiseLibrary).
+ `[options.maxPoolSize=5]` «Number» The maximum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
+ `[options.minPoolSize=1]` «Number» The minimum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
+ `[options.socketTimeoutMS=0]` «Number» How long the MongoDB driver will wait before killing a socket due to inactivity *after initial connection*. Defaults to 0, which means Node.js will not time out the socket due to inactivity. A socket may be inactive because of either no activity or a long-running operation. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
+ `[options.family=0]` «Number» Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0`, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.


##### Returns:


* «Connection» the created Connection object. Connections are not thenable, so you can't do `await mongoose.createConnection()`. To await use `mongoose.createConnection(uri).asPromise()` instead.



Creates a Connection instance.

 Each `connection` instance maps to a single database. This method is helpful when managing multiple db connections.

 *Options passed take precedence over options included in connection strings.*

 ####   [Example:](#example)

 
```
// with mongodb:// URI
db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database');

// and options
const opts = { db: { native\_parser: true }}
db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database', opts);

// replica sets
db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/database');

// and options
const opts = { replset: { strategy: 'ping', rs\_name: 'testSet' }}
db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/database', opts);

// initialize now, connect later
db = mongoose.createConnection();
db.openUri('127.0.0.1', 'database', port, [opts]);

```
 
### Mongoose.prototype.deleteModel()


##### Parameters:


* `name` «String|RegExp» if string, the name of the model to remove. If regexp, removes all models whose name matches the regexp.


##### Returns:


* «Mongoose» this



Removes the model named `name` from the default connection, if it exists. You can use this function to clean up any models you created in your tests to prevent OverwriteModelErrors.

 Equivalent to `mongoose.connection.deleteModel(name)`.

 ####   [Example:](#example)

 
```
mongoose.model('User', new Schema({ name: String }));
console.log(mongoose.model('User')); // Model object
mongoose.deleteModel('User');
console.log(mongoose.model('User')); // undefined

// Usually useful in a Mocha `afterEach()` hook
afterEach(function() {
  mongoose.deleteModel(/.+/); // Delete every model
});

```
 
### Mongoose.prototype.disconnect()


##### Returns:


* «Promise» resolves when all connections are closed, or rejects with the first error that occurred.



Runs `.close()` on all connections in parallel.

 
### Mongoose.prototype.driver


~DEPRECATED~##### Type:


* «property»



Object with `get()` and `set()` containing the underlying driver this Mongoose instance uses to communicate with the database. A driver is a Mongoose-specific interface that defines functions like `find()`.

 
### Mongoose.prototype.get()


##### Parameters:


* `key` «String»



Gets mongoose options

 ####   [Example:](#example)

 
```
mongoose.get('test') // returns the 'test' value

```
 
### Mongoose.prototype.isObjectIdOrHexString()


##### Parameters:


* `v` «Any»



Returns true if the given value is a Mongoose ObjectId (using `instanceof`) or if the given value is a 24 character hex string, which is the most commonly used string representation of an ObjectId.

 This function is similar to `isValidObjectId()`, but considerably more strict, because `isValidObjectId()` will return `true` for *any* value that Mongoose can convert to an ObjectId. That includes Mongoose documents, any string of length 12, and any number. `isObjectIdOrHexString()` returns true only for `ObjectId` instances or 24 character hex strings, and will return false for numbers, documents, and strings of length 12.

 ####   [Example:](#example)

 
```
mongoose.isObjectIdOrHexString(new mongoose.Types.ObjectId()); // true
mongoose.isObjectIdOrHexString('62261a65d66c6be0a63c051f'); // true

mongoose.isObjectIdOrHexString('0123456789ab'); // false
mongoose.isObjectIdOrHexString(6); // false
mongoose.isObjectIdOrHexString(new User({ name: 'test' })); // false
mongoose.isObjectIdOrHexString({ test: 42 }); // false

```
 
### Mongoose.prototype.isValidObjectId()


##### Parameters:


* `v` «Any»



Returns true if Mongoose can cast the given value to an ObjectId, or false otherwise.

 ####   [Example:](#example)

 
```
mongoose.isValidObjectId(new mongoose.Types.ObjectId()); // true
mongoose.isValidObjectId('0123456789ab'); // true
mongoose.isValidObjectId(6); // true
mongoose.isValidObjectId(new User({ name: 'test' })); // true

mongoose.isValidObjectId({ test: 42 }); // false

```
 
### Mongoose.prototype.model()


##### Parameters:


* `name` «String|Function» model name or class extending Model
* `[schema]` «Schema» the schema to use.
* `[collection]` «String» name (optional, inferred from model name)


##### Returns:


* «Model» The model associated with `name`. Mongoose will create the model if it doesn't already exist.



Defines a model or retrieves it.

 Models defined on the `mongoose` instance are available to all connection created by the same `mongoose` instance.

 If you call `mongoose.model()` with twice the same name but a different schema, you will get an `OverwriteModelError`. If you call `mongoose.model()` with the same name and same schema, you'll get the same schema back.

 ####   [Example:](#example)

 
```
const mongoose = require('mongoose');

// define an Actor model with this mongoose instance
const schema = new Schema({ name: String });
mongoose.model('Actor', schema);

// create a new connection
const conn = mongoose.createConnection(..);

// create Actor model
const Actor = conn.model('Actor', schema);
conn.model('Actor') === Actor; // true
conn.model('Actor', schema) === Actor; // true, same schema
conn.model('Actor', schema, 'actors') === Actor; // true, same schema and collection name

// This throws an `OverwriteModelError` because the schema is different.
conn.model('Actor', new Schema({ name: String }));

```
 *When no `collection` argument is passed, Mongoose uses the model name. If you don't like this behavior, either pass a collection name, use `mongoose.pluralize()`, or set your schemas collection name option.*

 ####   [Example:](#example-1)

 
```
const schema = new Schema({ name: String }, { collection: 'actor' });

// or

schema.set('collection', 'actor');

// or

const collectionName = 'actor'
const M = mongoose.model('Actor', schema, collectionName)

```
 
### Mongoose.prototype.modelNames()


##### Returns:


* «Array»



Returns an array of model names created on this instance of Mongoose.

 ####   [Note:](#note)

 *Does not include names of models created using `connection.model()`.*

 
### Mongoose.prototype.mongo


##### Type:


* «property»



The [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver Mongoose uses.

 
### Mongoose.prototype.mquery


##### Type:


* «property»



The [mquery](https://github.com/aheckmann/mquery) query builder Mongoose uses.

 
### Mongoose.prototype.now()



Mongoose uses this function to get the current time when setting [timestamps](../guide#timestamps). You may stub out this function using a tool like [Sinon](https://www.npmjs.com/package/sinon) for testing.

 
### Mongoose.prototype.overwriteMiddlewareResult()


##### Parameters:


* `result` «any»



Use this function in `post()` middleware to replace the result

 ####   [Example:](#example)

 
```
schema.post('find', function(res) {
  // Normally you have to modify `res` in place. But with
  // `overwriteMiddlewarResult()`, you can make `find()` return a
  // completely different value.
  return mongoose.overwriteMiddlewareResult(res.filter(doc => !doc.isDeleted));
});

```
 
### Mongoose.prototype.plugin()


##### Parameters:


* `fn` «Function» plugin callback
* `[opts]` «Object» optional options


##### Returns:


* «Mongoose» this


##### See:


* [plugins](../plugins)



Declares a global plugin executed on all Schemas.

 Equivalent to calling `.plugin(fn)` on each Schema you create.

 
### Mongoose.prototype.pluralize()


##### Parameters:


* `[fn]` «Function|null» overwrites the function used to pluralize collection names


##### Returns:


* «Function,null» the current function used to pluralize collection names, defaults to the legacy function from `mongoose-legacy-pluralize`.



Getter/setter around function for pluralizing collection names.

 
### Mongoose.prototype.sanitizeFilter()


##### Parameters:


* `filter` «Object»



Sanitizes query filters against [query selector injection attacks](https://thecodebarbarian.com/2014/09/04/defending-against-query-selector-injection-attacks.html) by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`.

 
```
const obj = { username: 'val', pwd: { $ne: null } };
sanitizeFilter(obj);
obj; // { username: 'val', pwd: { $eq: { $ne: null } } });

```
 
### Mongoose.prototype.set()


##### Parameters:


* `key` «String|Object» The name of the option or a object of multiple key-value pairs
* `value` «String|Function|Boolean» The value of the option, unused if "key" is a object



Sets mongoose options

 `key` can be used a object to set multiple options at once. If a error gets thrown for one option, other options will still be evaluated.

 ####   [Example:](#example)

 
```
mongoose.set('test', value) // sets the 'test' option to `value`

mongoose.set('debug', true) // enable logging collection methods + arguments to the console/file

mongoose.set('debug', function(collectionName, methodName, ...methodArgs) {}); // use custom function to log collection methods + arguments

mongoose.set({ debug: true, autoIndex: false }); // set multiple options at once

```
 Currently supported options are:

 * `allowDiskUse`: Set to `true` to set `allowDiskUse` to true to all aggregation operations by default.
* `applyPluginsToChildSchemas`: `true` by default. Set to false to skip applying global plugins to child schemas
* `applyPluginsToDiscriminators`: `false` by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema.
* `autoCreate`: Set to `true` to make Mongoose call [`Model.createCollection()`](model#Model.createCollection()) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist.
* `autoIndex`: `true` by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
* `bufferCommands`: enable/disable mongoose's buffering mechanism for all connections and models
* `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).
* `cloneSchemas`: `false` by default. Set to `true` to `clone()` all schemas before compiling into a model.
* `debug`: If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arguments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
* `id`: If `true`, adds a `id` virtual to all schemas unless overwritten on a per-schema basis.
* `timestamps.createdAt.immutable`: `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](schematype#SchemaType.prototype.immutable) which means you can update the `createdAt`
* `maxTimeMS`: If set, attaches [maxTimeMS](https://www.mongodb.com/docs/manual/reference/operator/meta/maxTimeMS/) to every query
* `objectIdGetter`: `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
* `overwriteModels`: Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
* `returnOriginal`: If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](../tutorials/findoneandupdate) for more information.
* `runValidators`: `false` by default. Set to true to enable [update validators](../validation#update-validators) for all validators by default.
* `sanitizeFilter`: `false` by default. Set to true to enable the [sanitization of the query filters](#Mongoose.prototype.sanitizeFilter()) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`.
* `selectPopulatedPaths`: `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
* `strict`: `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
* `strictQuery`: `false` by default. May be `false`, `true`, or `'throw'`. Sets the default [strictQuery](../guide#strictQuery) mode for schemas.
* `toJSON`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](document#Document.prototype.toJSON()), for determining how Mongoose documents get serialized by `JSON.stringify()`
* `toObject`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](document#Document.prototype.toObject())

 
### Mongoose.prototype.setDriver()



Overwrites the current driver used by this Mongoose instance. A driver is a Mongoose-specific interface that defines functions like `find()`.

 
### Mongoose.prototype.skipMiddlewareFunction()


##### Parameters:


* `result` «any»



Use this function in `pre()` middleware to skip calling the wrapped function.

 ####   [Example:](#example)

 
```
schema.pre('save', function() {
  // Will skip executing `save()`, but will execute post hooks as if
  // `save()` had executed with the result `{ matchedCount: 0 }`
  return mongoose.skipMiddlewareFunction({ matchedCount: 0 });
});

```
 
### Mongoose.prototype.startSession()


##### Parameters:


* `[options]` «Object» see the [mongodb driver options](https://mongodb.github.io/node-mongodb-native/4.9/classes/MongoClient.html#startSession)
+ `[options.causalConsistency=true]` «Boolean» set to false to disable causal consistency

* `[callback]` «Function»


##### Returns:


* «Promise<ClientSession>» promise that resolves to a MongoDB driver `ClientSession`



*Requires MongoDB >= 3.6.0.* Starts a [MongoDB session](https://www.mongodb.com/docs/manual/release-notes/3.6/#client-sessions) for benefits like causal consistency, [retryable writes](https://www.mongodb.com/docs/manual/core/retryable-writes/), and [transactions](https://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html).

 Calling `mongoose.startSession()` is equivalent to calling `mongoose.connection.startSession()`. Sessions are scoped to a connection, so calling `mongoose.startSession()` starts a session on the [default mongoose connection](#Mongoose.prototype.connection).

 
### Mongoose.prototype.syncIndexes()


##### Parameters:


* `options` «Object»
* `options.continueOnError` «Boolean» `false` by default. If set to `true`, mongoose will not throw an error if one model syncing failed, and will return an object where the keys are the names of the models, and the values are the results/errors for each model.


##### Returns:


* «Promise» Returns a Promise, when the Promise resolves the value is a list of the dropped indexes.



Syncs all the indexes for the models registered with this connection.

 
### Mongoose.prototype.trusted()


##### Parameters:


* `obj` «Object»



Tells `sanitizeFilter()` to skip the given object when filtering out potential [query selector injection attacks](https://thecodebarbarian.com/2014/09/04/defending-against-query-selector-injection-attacks.html). Use this method when you have a known query selector that you want to use.

 
```
const obj = { username: 'val', pwd: trusted({ $type: 'string', $eq: 'my secret' }) };
sanitizeFilter(obj);

// Note that `sanitizeFilter()` did not add `$eq` around `$type`.
obj; // { username: 'val', pwd: { $type: 'string', $eq: 'my secret' } });

```
 
### Mongoose.prototype.version


##### Type:


* «property»



The Mongoose version

 ####   [Example:](#example)

 
```
console.log(mongoose.version); // '5.x.x'

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/mongoose.html>

Schemas
========

 If you haven't yet done so, please take a minute to read the [quickstart](index) to get an idea of how Mongoose works. If you are migrating from 6.x to 7.x please take a moment to read the [migration guide](migrating_to_7).

 Defining your schema
--------------------

 Everything in Mongoose starts with a Schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection.

 
```
import mongoose from 'mongoose';
const { Schema } = mongoose;

const blogSchema = new Schema({
  title: String, // String is shorthand for {type: String}
  author: String,
  body: String,
  comments: [{ body: String, date: Date }],
  date: { type: Date, default: Date.now },
  hidden: Boolean,
  meta: {
    votes: Number,
    favs: Number
  }
});

```
 If you want to add additional keys later, use the [Schema#add](api/schema#schema_Schema-add) method.

 Each key in our code `blogSchema` defines a property in our documents which will be cast to its associated [SchemaType](api/schematype#schematype_SchemaType). For example, we've defined a property `title` which will be cast to the [String](schematypes#strings) SchemaType and property `date` which will be cast to a `Date` SchemaType.

 Notice above that if a property only requires a type, it can be specified using a shorthand notation (contrast the `title` property above with the `date` property).

 Keys may also be assigned nested objects containing further key/type definitions like the `meta` property above. This will happen whenever a key's value is a POJO that doesn't have a `type` property.

 In these cases, Mongoose only creates actual schema paths for leaves in the tree. (like `meta.votes` and `meta.favs` above), and the branches do not have actual paths. A side-effect of this is that `meta` above cannot have its own validation. If validation is needed up the tree, a path needs to be created up the tree - see the [Subdocuments](subdocs) section for more information on how to do this. Also read the [Mixed](schematypes) subsection of the SchemaTypes guide for some gotchas.

 The permitted SchemaTypes are:

 * [String](schematypes#strings)
* [Number](schematypes#numbers)
* [Date](schematypes#dates)
* [Buffer](schematypes#buffers)
* [Boolean](schematypes#booleans)
* [Mixed](schematypes#mixed)
* [ObjectId](schematypes#objectids)
* [Array](schematypes#arrays)
* [Decimal128](api/mongoose#mongoose_Mongoose-Decimal128)
* [Map](schematypes#maps)
* [UUID](schematypes#uuid)

 Read more about [SchemaTypes here](schematypes).

 Schemas not only define the structure of your document and casting of properties, they also define document [instance methods](#methods), [static Model methods](#statics), [compound indexes](#indexes), and document lifecycle hooks called <middleware>.

 Creating a model
----------------

 To use our schema definition, we need to convert our `blogSchema` into a [Model](models) we can work with. To do so, we pass it into `mongoose.model(modelName, schema)`:

 
```
const Blog = mongoose.model('Blog', blogSchema);
// ready to go!

```
 Ids
---

 By default, Mongoose adds an `_id` property to your schemas.

 
```
const schema = new Schema();

schema.path('\_id'); // ObjectId { ... }

```
 When you create a new document with the automatically added `_id` property, Mongoose creates a new [`_id` of type ObjectId](https://masteringjs.io/tutorials/mongoose/objectid) to your document.

 
```
const Model = mongoose.model('Test', schema);

const doc = new Model();
doc.\_id instanceof mongoose.Types.ObjectId; // true

```
 You can also overwrite Mongoose's default `_id` with your own `_id`. Just be careful: Mongoose will refuse to save a document that doesn't have an `_id`, so you're responsible for setting `_id` if you define your own `_id` path.

 
```
const schema = new Schema({ \_id: Number });
const Model = mongoose.model('Test', schema);

const doc = new Model();
await doc.save(); // Throws "document must have an \_id before saving"

doc.\_id = 1;
await doc.save(); // works

```
 Instance methods
----------------

 Instances of `Models` are <documents>. Documents have many of their own [built-in instance methods](api/document). We may also define our own custom document instance methods.

 
```
// define a schema
const animalSchema = new Schema({ name: String, type: String },
  {
  // Assign a function to the "methods" object of our animalSchema through schema options.
  // By following this approach, there is no need to create a separate TS type to define the type of the instance functions.
    methods: {
      findSimilarTypes(cb) {
        return mongoose.model('Animal').find({ type: this.type }, cb);
      }
    }
  });

// Or, assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function(cb) {
  return mongoose.model('Animal').find({ type: this.type }, cb);
};

```
 Now all of our `animal` instances have a `findSimilarTypes` method available to them.

 
```
const Animal = mongoose.model('Animal', animalSchema);
const dog = new Animal({ type: 'dog' });

dog.findSimilarTypes((err, dogs) => {
  console.log(dogs); // woof
});

```
 * Overwriting a default mongoose document method may lead to unpredictable results. See [this](api/schema#schema_Schema-reserved) for more details.
* The example above uses the `Schema.methods` object directly to save an instance method. You can also use the `Schema.method()` helper as described [here](api/schema#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
-------

 You can also add static functions to your model. There are three equivalent ways to add a static:

 * Add a function property to the second argument of the schema-constructor (`statics`)
* Add a function property to `schema.statics`
* Call the [`Schema#static()` function](api/schema#schema_Schema-static)

 
```

// define a schema
const animalSchema = new Schema({ name: String, type: String },
  {
  // Assign a function to the "statics" object of our animalSchema through schema options.
  // By following this approach, there is no need to create a separate TS type to define the type of the statics functions.
    statics: {
      findByName(name) {
        return this.find({ name: new RegExp(name, 'i') });
      }
    }
  });

// Or, Assign a function to the "statics" object of our animalSchema
animalSchema.statics.findByName = function(name) {
  return this.find({ name: new RegExp(name, 'i') });
};
// Or, equivalently, you can call `animalSchema.static()`.
animalSchema.static('findByBreed', function(breed) { return this.find({ breed }); });

const Animal = mongoose.model('Animal', animalSchema);
let animals = await Animal.findByName('fido');
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
-------------

 You can also add query helper functions, which are like instance methods but for mongoose queries. Query helper methods let you extend mongoose's [chainable query builder API](queries).

 
```

// define a schema
const animalSchema = new Schema({ name: String, type: String },
  {
  // Assign a function to the "query" object of our animalSchema through schema options.
  // By following this approach, there is no need to create a separate TS type to define the type of the query functions.
    query: {
      byName(name) {
        return this.where({ name: new RegExp(name, 'i') });
      }
    }
  });

// Or, Assign a function to the "query" object of our animalSchema
animalSchema.query.byName = function(name) {
  return this.where({ name: new RegExp(name, 'i') });
};

const Animal = mongoose.model('Animal', animalSchema);

Animal.find().byName('fido').exec((err, animals) => {
  console.log(animals);
});

Animal.findOne().byName('fido').exec((err, animal) => {
  console.log(animal);
});

```
 Indexes
-------

 MongoDB supports [secondary indexes](http://www.mongodb.com/docs/manual/indexes/). With mongoose, we define these indexes within our `Schema` [at](api/schematype#schematype_SchemaType-index) [the](api/schematype#schematype_SchemaType-unique) [path](api/schematype#schematype_SchemaType-sparse) [level](api/schemadateoptions#schemadateoptions_SchemaDateOptions-expires) or the `schema` level. Defining indexes at the schema level is necessary when creating [compound indexes](https://www.mongodb.com/docs/manual/core/index-compound/).

 
```
const animalSchema = new Schema({
  name: String,
  type: String,
  tags: { type: [String], index: true } // path level
});

animalSchema.index({ name: 1, type: -1 }); // schema level

```
 See [SchemaType#index()](api/schematype#schematype_SchemaType-index) for other index options.

 When your application starts up, Mongoose automatically calls [`createIndex`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/#db.collection.createIndex) for each defined index in your schema. Mongoose will call `createIndex` for each index sequentially, and emit an 'index' event on the model when all the `createIndex` calls succeeded or when there was an error. While nice for development, it is recommended this behavior be disabled in production since index creation can cause a [significant performance impact](https://www.mongodb.com/docs/manual/core/index-creation/#index-build-impact-on-database-performance). Disable the behavior by setting the `autoIndex` option of your schema to `false`, or globally on the connection by setting the option `autoIndex` to `false`.

 
```
mongoose.connect('mongodb://user:pass@127.0.0.1:port/database', { autoIndex: false });
// or
mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database', { autoIndex: false });
// or
mongoose.set('autoIndex', false);
// or
animalSchema.set('autoIndex', false);
// or
new Schema({ /\* ... \*/ }, { autoIndex: false });

```
 Mongoose will emit an `index` event on the model when indexes are done building or an error occurred.

 
```
// Will cause an error because mongodb has an \_id index by default that
// is not sparse
animalSchema.index({ \_id: 1 }, { sparse: true });
const Animal = mongoose.model('Animal', animalSchema);

Animal.on('index', error => {
  // "\_id index cannot be sparse"
  console.log(error.message);
});

```
 See also the [Model#ensureIndexes](api/model#model_Model-ensureIndexes) method.

 Virtuals
--------

 [Virtuals](api/schema#schema_Schema-virtual) are document properties that you can get and set but that do not get persisted to MongoDB. The getters are useful for formatting or combining fields, while setters are useful for de-composing a single value into multiple values for storage.

 
```
// define a schema
const personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
});

// compile our model
const Person = mongoose.model('Person', personSchema);

// create a document
const axl = new Person({
  name: { first: 'Axl', last: 'Rose' }
});

```
 Suppose you want to print out the person's full name. You could do it yourself:

 
```
console.log(axl.name.first + ' ' + axl.name.last); // Axl Rose

```
 But [concatenating](https://masteringjs.io/tutorials/fundamentals/string-concat) the first and last name every time can get cumbersome. And what if you want to do some extra processing on the name, like [removing diacritics](https://www.npmjs.com/package/diacritics)? A [virtual property getter](api/virtualtype#virtualtype_VirtualType-get) lets you define a `fullName` property that won't get persisted to MongoDB.

 
```
// That can be done either by adding it to schema options:
const personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
}, {
  virtuals: {
    fullName: {
      get() {
        return this.name.first + ' ' + this.name.last;
      }
    }
  }
});

// Or by using the virtual method as following:
personSchema.virtual('fullName').get(function() {
  return this.name.first + ' ' + this.name.last;
});

```
 Now, mongoose will call your getter function every time you access the `fullName` property:

 
```
console.log(axl.fullName); // Axl Rose

```
 If you use `toJSON()` or `toObject()` Mongoose will *not* include virtuals by default. Pass `{ virtuals: true }` to [`toJSON()`](api/document#document_Document-toJSON) or `toObject()` to include virtuals.

 
```
// Convert `doc` to a POJO, with virtuals attached
doc.toObject({ virtuals: true });

// Equivalent:
doc.toJSON({ virtuals: true });

```
 The above caveat for `toJSON()` also includes the output of calling [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) on a Mongoose document, because [`JSON.stringify()` calls `toJSON()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Description). To include virtuals in `JSON.stringify()` output, you can either call `toObject({ virtuals: true })` on the document before calling `JSON.stringify()`, or set the `toJSON: { virtuals: true }` option on your schema.

 
```
// Explicitly add virtuals to `JSON.stringify()` output
JSON.stringify(doc.toObject({ virtuals: true }));

// Or, to automatically attach virtuals to `JSON.stringify()` output:
const personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
}, {
  toJSON: { virtuals: true } // <-- include virtuals in `JSON.stringify()`
});

```
 You can also add a custom setter to your virtual that will let you set both first name and last name via the `fullName` virtual.

 
```
// Again that can be done either by adding it to schema options:
const personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
}, {
  virtuals: {
    fullName: {
      get() {
        return this.name.first + ' ' + this.name.last;
      },
      set(v) {
        this.name.first = v.substr(0, v.indexOf(' '));
        this.name.last = v.substr(v.indexOf(' ') + 1);
      }
    }
  }
});

// Or by using the virtual method as following:
personSchema.virtual('fullName').
  get(function() {
    return this.name.first + ' ' + this.name.last;
  }).
  set(function(v) {
    this.name.first = v.substr(0, v.indexOf(' '));
    this.name.last = v.substr(v.indexOf(' ') + 1);
  });

axl.fullName = 'William Rose'; // Now `axl.name.first` is "William"

```
 Virtual property setters are applied before other validation. So the example above would still work even if the `first` and `last` name fields were required.

 Only non-virtual properties work as part of queries and for field selection. 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 are a particular type of virtual where the getter and setter seamlessly get and set another property. This is handy for saving network bandwidth, so you can convert a short property name stored in the database into a longer name for code readability.

 
```
const personSchema = new Schema({
  n: {
    type: String,
    // Now accessing `name` will get you the value of `n`, and setting `name` will set the value of `n`
    alias: 'name'
  }
});

// Setting `name` will propagate to `n`
const person = new Person({ name: 'Val' });
console.log(person); // { n: 'Val' }
console.log(person.toObject({ virtuals: true })); // { n: 'Val', name: 'Val' }
console.log(person.name); // "Val"

person.name = 'Not Val';
console.log(person); // { n: 'Not Val' }

```
 You can also declare aliases on nested paths. It is easier to use nested schemas and [subdocuments](subdocs), but you can also declare nested path aliases inline as long as you use the full nested path `nested.myProp` as the alias.

 
```
const childSchema = new Schema({
  n: {
    type: String,
    alias: 'name'
  }
}, { \_id: false });

const parentSchema = new Schema({
  // If in a child schema, alias doesn't need to include the full nested path
  c: childSchema,
  name: {
    f: {
      type: String,
      // Alias needs to include the full nested path if declared inline
      alias: 'name.first'
    }
  }
});

```
 Options
-------

 Schemas have a few configurable options which can be passed to the constructor or to the `set` method:

 
```
new Schema({ /\* ... \*/ }, options);

// or

const schema = new Schema({ /\* ... \*/ });
schema.set(option, value);

```
 Valid options:

 * [autoIndex](#autoIndex)
* [autoCreate](#autoCreate)
* [bufferCommands](#bufferCommands)
* [bufferTimeoutMS](#bufferTimeoutMS)
* [capped](#capped)
* [collection](#collection)
* [discriminatorKey](#discriminatorKey)
* [excludeIndexes](#excludeIndexes)
* [id](#id)
* [\_id](#_id)
* [minimize](#minimize)
* [read](#read)
* [writeConcern](#writeConcern)
* [shardKey](#shardKey)
* [statics](#statics)
* [strict](#strict)
* [strictQuery](#strictQuery)
* [toJSON](#toJSON)
* [toObject](#toObject)
* [typeKey](#typeKey)
* [validateBeforeSave](#validateBeforeSave)
* [versionKey](#versionKey)
* [optimisticConcurrency](#optimisticConcurrency)
* [collation](#collation)
* [timeseries](#timeseries)
* [selectPopulatedPaths](#selectPopulatedPaths)
* [skipVersioning](#skipVersioning)
* [timestamps](#timestamps)
* [storeSubdocValidationError](#storeSubdocValidationError)
* [collectionOptions](#collectionOptions)
* [methods](#methods)
* [query](#query-helpers)

 option: autoIndex
-----------------

 By default, Mongoose's [`init()` function](api/model#model_Model-init) creates all the indexes defined in your model's schema by calling [`Model.createIndexes()`](api/model#model_Model-createIndexes) after you successfully connect to MongoDB. Creating indexes automatically is great for development and test environments. But index builds can also create significant load on your production database. If you want to manage indexes carefully in production, you can set `autoIndex` to false.

 
```
const schema = new Schema({ /\* ... \*/ }, { autoIndex: false });
const Clock = mongoose.model('Clock', schema);
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#mongoose_Mongoose-set)

 option: 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 a capped collection if you set the [`capped` schema option](#capped).

 You can disable this behavior by setting `autoCreate` to `false` using [`mongoose.set('autoCreate', false)`](api/mongoose#mongoose_Mongoose-set). Like `autoIndex`, `autoCreate` is helpful for development and test environments, but you may want to disable it for production to avoid unnecessary database calls.

 Unfortunately, `createCollection()` cannot change an existing collection. For example, if you add `capped: { size: 1024 }` to your schema and the existing collection is not capped, `createCollection()` will **not** overwrite the existing collection. That is because the MongoDB server does not allow changing a collection's options without dropping the collection first.

 
```
const schema = new Schema({ name: String }, {
  autoCreate: false,
  capped: { size: 1024 }
});
const Test = mongoose.model('Test', schema);

// No-op if collection already exists, even if the collection is not capped.
// This means that `capped` won't be applied if the 'tests' collection already exists.
await Test.createCollection();

```
 option: bufferCommands
----------------------

 By default, mongoose buffers commands when the connection goes down until the driver manages to reconnect. To disable buffering, set `bufferCommands` to false.

 
```
const schema = new Schema({ /\* ... \*/ }, { bufferCommands: false });

```
 The schema `bufferCommands` option overrides the global `bufferCommands` option.

 
```
mongoose.set('bufferCommands', true);
// Schema option below overrides the above, if the schema option is set.
const schema = new Schema({ /\* ... \*/ }, { bufferCommands: false });

```
 option: 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).

 
```
// If an operation is buffered for more than 1 second, throw an error.
const schema = new Schema({ /\* ... \*/ }, { bufferTimeoutMS: 1000 });

```
 option: capped
--------------

 Mongoose supports MongoDBs [capped](https://www.mongodb.com/docs/manual/core/capped-collections/) collections. To specify the underlying MongoDB collection be `capped`, set the `capped` option to the maximum size of the collection in [bytes](https://www.mongodb.com/docs/manual/core/capped-collections/#create-a-capped-collection).

 
```
new Schema({ /\* ... \*/ }, { capped: 1024 });

```
 The `capped` option may also be set to an object if you want to pass additional options like [max](https://www.mongodb.com/docs/manual/core/capped-collections/#change-the-maximum-number-of-documents-in-a-capped-collection). In this case you must explicitly pass the `size` option, which is required.

 
```
new Schema({ /\* ... \*/ }, { capped: { size: 1024, max: 1000, autoIndexId: true } });

```
 option: collection
------------------

 Mongoose by default produces a collection name by passing the model name to the `utils.toCollectionName` method. This method pluralizes the name. Set this option if you need a different name for your collection.

 
```
const dataSchema = new Schema({ /\* ... \*/ }, { collection: 'data' });

```
 option: discriminatorKey
------------------------

 When you define a [discriminator](discriminators), Mongoose adds a path to your schema that stores which discriminator a document is an instance of. By default, Mongoose adds an `__t` path, but you can set `discriminatorKey` to overwrite this default.

 
```
const baseSchema = new Schema({}, { discriminatorKey: 'type' });
const BaseModel = mongoose.model('Test', baseSchema);

const personSchema = new Schema({ name: String });
const PersonModel = BaseModel.discriminator('Person', personSchema);

const doc = new PersonModel({ name: 'James T. Kirk' });
// Without `discriminatorKey`, Mongoose would store the discriminator
// key in `\_\_t` instead of `type`
doc.type; // 'Person'

```
 option: 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. Defaults to `false`.

 
```
const childSchema1 = Schema({
  name: { type: String, index: true }
});

const childSchema2 = Schema({
  name: { type: String, index: true }
}, { excludeIndexes: true });

// Mongoose will create an index on `child1.name`, but \*\*not\*\* `child2.name`, because `excludeIndexes`
// is true on `childSchema2`
const User = new Schema({
  name: { type: String, index: true },
  child1: childSchema1,
  child2: childSchema2
});

```
 option: 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 ObjectIds, its hexString. If you don't want an `id` getter added to your schema, you may disable it by passing this option at schema construction time.

 
```
// default behavior
const schema = new Schema({ name: String });
const Page = mongoose.model('Page', schema);
const p = new Page({ name: 'mongodb.org' });
console.log(p.id); // '50341373e894ad16347efe01'

// disabled id
const schema = new Schema({ name: String }, { id: false });
const Page = mongoose.model('Page', schema);
const p = new Page({ name: 'mongodb.org' });
console.log(p.id); // undefined

```
 option: \_id
------------

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

 You can **only** use this option on subdocuments. Mongoose can't save a document without knowing its id, so you will get an error if you try to save a document without an `_id`.

 
```
// default behavior
const schema = new Schema({ name: String });
const Page = mongoose.model('Page', schema);
const p = new Page({ name: 'mongodb.org' });
console.log(p); // { \_id: '50341373e894ad16347efe01', name: 'mongodb.org' }

// disabled \_id
const childSchema = new Schema({ name: String }, { \_id: false });
const parentSchema = new Schema({ children: [childSchema] });

const Model = mongoose.model('Model', parentSchema);

Model.create({ children: [{ name: 'Luke' }] }, (error, doc) => {
  // doc.children[0].\_id will be undefined
});

```
 option: minimize
----------------

 Mongoose will, by default, "minimize" schemas by removing empty objects.

 
```
const schema = new Schema({ name: String, inventory: {} });
const Character = mongoose.model('Character', schema);

// will store `inventory` field if it is not empty
const frodo = new Character({ name: 'Frodo', inventory: { ringOfPower: 1 } });
await frodo.save();
let doc = await Character.findOne({ name: 'Frodo' }).lean();
doc.inventory; // { ringOfPower: 1 }

// will not store `inventory` field if it is empty
const sam = new Character({ name: 'Sam', inventory: {} });
await sam.save();
doc = await Character.findOne({ name: 'Sam' }).lean();
doc.inventory; // undefined

```
 This behavior can be overridden by setting `minimize` option to `false`. It will then store empty objects.

 
```
const schema = new Schema({ name: String, inventory: {} }, { minimize: false });
const Character = mongoose.model('Character', schema);

// will store `inventory` if empty
const sam = new Character({ name: 'Sam', inventory: {} });
await sam.save();
doc = await Character.findOne({ name: 'Sam' }).lean();
doc.inventory; // {}

```
 To check whether an object is empty, you can use the `$isEmpty()` helper:

 
```
const sam = new Character({ name: 'Sam', inventory: {} });
sam.$isEmpty('inventory'); // true

sam.inventory.barrowBlade = 1;
sam.$isEmpty('inventory'); // false

```
 option: read
------------

 Allows setting [query#read](api/query#query_Query-read) options at the schema level, providing us a way to apply default [ReadPreferences](http://www.mongodb.com/docs/manual/applications/replication/#replica-set-read-preference) to all queries derived from a model.

 
```
const schema = new Schema({ /\* ... \*/ }, { read: 'primary' });            // also aliased as 'p'
const schema = new Schema({ /\* ... \*/ }, { read: 'primaryPreferred' });   // aliased as 'pp'
const schema = new Schema({ /\* ... \*/ }, { read: 'secondary' });          // aliased as 's'
const schema = new Schema({ /\* ... \*/ }, { read: 'secondaryPreferred' }); // aliased as 'sp'
const schema = new Schema({ /\* ... \*/ }, { read: 'nearest' });            // aliased as 'n'

```
 The alias of each pref is also permitted so instead of having to type out 'secondaryPreferred' and getting the spelling wrong, we can simply pass 'sp'.

 The read option also allows us to specify *tag sets*. These tell the [driver](https://github.com/mongodb/node-mongodb-native/) from which members of the replica-set it should attempt to read. Read more about tag sets [here](http://www.mongodb.com/docs/manual/applications/replication/#tag-sets) and [here](https://www.mongodb.com/docs/manual/core/read-preference).

 *NOTE: you may also specify the driver read preference [strategy](https://www.mongodb.com/docs/manual/core/read-preference/#read-preference-modes) option when connecting:*

 
```
// pings the replset members periodically to track network latency
const options = { replset: { strategy: 'ping' } };
mongoose.connect(uri, options);

const schema = new Schema({ /\* ... \*/ }, { read: ['nearest', { disk: 'ssd' }] });
mongoose.model('JellyBean', schema);

```
 option: writeConcern
--------------------

 Allows setting [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) at the schema level.

 
```
const schema = new Schema({ name: String }, {
  writeConcern: {
    w: 'majority',
    j: true,
    wtimeout: 1000
  }
});

```
 option: 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 insert/update operations. We just need to set this schema option to the same shard key and we’ll be all set.

 
```
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
--------------

 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 the db.

 
```
const thingSchema = new Schema({ /\* ... \*/ })
const Thing = mongoose.model('Thing', thingSchema);
const thing = new Thing({ iAmNotInTheSchema: true });
thing.save(); // iAmNotInTheSchema is not saved to the db

// set to false..
const thingSchema = new Schema({ /\* ... \*/ }, { strict: false });
const thing = new Thing({ iAmNotInTheSchema: true });
thing.save(); // iAmNotInTheSchema is now saved to the db!!

```
 This also affects the use of `doc.set()` to set a property value.

 
```
const thingSchema = new Schema({ /\* ... \*/ });
const Thing = mongoose.model('Thing', thingSchema);
const thing = new Thing;
thing.set('iAmNotInTheSchema', true);
thing.save(); // iAmNotInTheSchema is not saved to the db

```
 This value can be overridden at the model instance level by passing a second boolean argument:

 
```
const Thing = mongoose.model('Thing');
const thing = new Thing(doc, true);  // enables strict mode
const thing = new Thing(doc, false); // disables strict mode

```
 The `strict` option may also be set to `"throw"` which will cause errors to be produced instead of dropping the bad data.

 *NOTE: Any key/val set on the instance that does not exist in your schema is always ignored, regardless of schema option.*

 
```
const thingSchema = new Schema({ /\* ... \*/ });
const Thing = mongoose.model('Thing', thingSchema);
const thing = new Thing;
thing.iAmNotInTheSchema = true;
thing.save(); // iAmNotInTheSchema is never saved to the db

```
 option: 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.

 
```
const mySchema = new Schema({ field: Number }, { strict: true });
const MyModel = mongoose.model('Test', mySchema);
// Mongoose will filter out `notInSchema: 1` because `strict: true`, meaning this query will return
// \_all\_ documents in the 'tests' collection
MyModel.find({ notInSchema: 1 });

```
 The `strict` option does apply to updates. The `strictQuery` option is **just** for query filters.

 
```
// Mongoose will strip out `notInSchema` from the update if `strict` is
// not `false`
MyModel.updateMany({}, { $set: { notInSchema: 1 } });

```
 Mongoose has a separate `strictQuery` option to toggle strict mode for the `filter` parameter to queries.

 
```
const mySchema = new Schema({ field: Number }, {
  strict: true,
  strictQuery: false // Turn off strict mode for query filters
});
const MyModel = mongoose.model('Test', mySchema);
// Mongoose will not strip out `notInSchema: 1` because `strictQuery` is false
MyModel.find({ notInSchema: 1 });

```
 In general, we do **not** recommend passing user-defined objects as query filters:

 
```
// Don't do this!
const docs = await MyModel.find(req.query);

// Do this instead:
const docs = await MyModel.find({ name: req.query.name, age: req.query.age }).setOptions({ sanitizeFilter: true });

```
 In Mongoose 7, `strictQuery` is `false` by default. However, you can override this behavior globally:

 
```
// Set `strictQuery` to `true` to omit unknown fields in queries.
mongoose.set('strictQuery', true);

```
 option: 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.

 
```
const schema = new Schema({ name: String });
schema.path('name').get(function(v) {
  return v + ' is my name';
});
schema.set('toJSON', { getters: true, virtuals: false });
const M = mongoose.model('Person', schema);
const m = new M({ name: 'Max Headroom' });
console.log(m.toObject()); // { \_id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom' }
console.log(m.toJSON()); // { \_id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }
// since we know toJSON is called whenever a js object is stringified:
console.log(JSON.stringify(m)); // { "\_id": "504e0cd7dd992d9be2f20b6f", "name": "Max Headroom is my name" }

```
 To see all available `toJSON/toObject` options, read [this](api/document#document_Document-toObject).

 option: toObject
----------------

 Documents have a [toObject](api/document#document_Document-toObject) method which converts the mongoose document into a plain JavaScript object. This method accepts a few options. Instead of applying these options on a per-document basis, we may declare the options at the schema level and have them applied to all of the schema's documents by default.

 To have all virtuals show up in your `console.log` output, set the `toObject` option to `{ getters: true }`:

 
```
const schema = new Schema({ name: String });
schema.path('name').get(function(v) {
  return v + ' is my name';
});
schema.set('toObject', { getters: true });
const M = mongoose.model('Person', schema);
const m = new M({ name: 'Max Headroom' });
console.log(m); // { \_id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }

```
 To see all available `toObject` options, read [this](api/document#document_Document-toObject).

 option: typeKey
---------------

 By default, if you have an object with key 'type' in your schema, mongoose will interpret it as a type declaration.

 
```
// Mongoose interprets this as 'loc is a String'
const schema = new Schema({ loc: { type: String, coordinates: [Number] } });

```
 However, for applications like [geoJSON](http://www.mongodb.com/docs/manual/reference/geojson/), the 'type' property is important. If you want to control which key mongoose uses to find type declarations, set the 'typeKey' schema option.

 
```
const schema = new Schema({
  // Mongoose interprets this as 'loc is an object with 2 keys, type and coordinates'
  loc: { type: String, coordinates: [Number] },
  // Mongoose interprets this as 'name is a String'
  name: { $type: String }
}, { typeKey: '$type' }); // A '$type' key means this object is a type declaration

```
 option: 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 handle validation manually, and be able to save objects which don't pass validation, you can set `validateBeforeSave` to false.

 
```
const schema = new Schema({ name: String });
schema.set('validateBeforeSave', false);
schema.path('name').validate(function(value) {
  return value != null;
});
const M = mongoose.model('Person', schema);
const m = new M({ name: null });
m.validate(function(err) {
  console.log(err); // Will tell you that null is not allowed.
});
m.save(); // Succeeds despite being invalid

```
 option: versionKey
------------------

 The `versionKey` is a property set on each document when first created by Mongoose. This keys value contains the internal [revision](http://aaronheckmann.blogspot.com/2012/06/mongoose-v3-part-1-versioning.html) of the document. The `versionKey` option is a string that represents the path to use for versioning. The default is `__v`. If this conflicts with your application you can configure as such:

 
```
const schema = new Schema({ name: 'string' });
const Thing = mongoose.model('Thing', schema);
const thing = new Thing({ name: 'mongoose v3' });
await thing.save(); // { \_\_v: 0, name: 'mongoose v3' }

// customized versionKey
new Schema({ /\* ... \*/ }, { versionKey: '\_somethingElse' })
const Thing = mongoose.model('Thing', schema);
const thing = new Thing({ name: 'mongoose v3' });
thing.save(); // { \_somethingElse: 0, name: 'mongoose v3' }

```
 Note that Mongoose's default versioning is **not** a full [optimistic concurrency](https://en.wikipedia.org/wiki/Optimistic_concurrency_control) solution. Mongoose's default versioning only operates on arrays as shown below.

 
```
// 2 copies of the same document
const doc1 = await Model.findOne({ _id });
const doc2 = await Model.findOne({ _id });

// Delete first 3 comments from `doc1`
doc1.comments.splice(0, 3);
await doc1.save();

// The below `save()` will throw a VersionError, because you're trying to
// modify the comment at index 1, and the above `splice()` removed that
// comment.
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)

 Document versioning can also be disabled by setting the `versionKey` to `false`. *DO NOT disable versioning unless you [know what you are doing](http://aaronheckmann.blogspot.com/2012/06/mongoose-v3-part-1-versioning.html).*

 
```
new Schema({ /\* ... \*/ }, { versionKey: false });
const Thing = mongoose.model('Thing', schema);
const thing = new Thing({ name: 'no versioning please' });
thing.save(); // { name: 'no versioning please' }

```
 Mongoose *only* updates the version key when you use [`save()`](api/document#document_Document-save). If you use `update()`, `findOneAndUpdate()`, etc. Mongoose will **not** update the version key. As a workaround, you can use the below middleware.

 
```
schema.pre('findOneAndUpdate', function() {
  const update = this.getUpdate();
  if (update.\_\_v != null) {
    delete update.\_\_v;
  }
  const keys = ['$set', '$setOnInsert'];
  for (const key of keys) {
    if (update[key] != null && update[key].\_\_v != null) {
      delete update[key].\_\_v;
      if (Object.keys(update[key]).length === 0) {
        delete update[key];
      }
    }
  }
  update.$inc = update.$inc || {};
  update.$inc.\_\_v = 1;
});

```
 option: 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 you update it using `save()`.

 For example, suppose you have a `House` model that contains a list of `photos`, and a `status` that represents whether this house shows up in searches. Suppose that a house that has status `'APPROVED'` must have at least two `photos`. You might implement the logic of approving a house document as shown below:

 
```
async function markApproved(id) {
  const house = await House.findOne({ _id });
  if (house.photos.length < 2) {
    throw new Error('House must have at least two photos!');
  }

  house.status = 'APPROVED';
  await house.save();
}

```
 The `markApproved()` function looks right in isolation, but there might be a potential issue: what if another function removes the house's photos between the `findOne()` call and the `save()` call? For example, the below code will succeed:

 
```
const house = await House.findOne({ _id });
if (house.photos.length < 2) {
  throw new Error('House must have at least two photos!');
}

const house2 = await House.findOne({ _id });
house2.photos = [];
await house2.save();

// Marks the house as 'APPROVED' even though it has 0 photos!
house.status = 'APPROVED';
await house.save();

```
 If you set the `optimisticConcurrency` option on the `House` model's schema, the above script will throw an error.

 
```
const House = mongoose.model('House', Schema({
  status: String,
  photos: [String]
}, { optimisticConcurrency: true }));

const house = await House.findOne({ _id });
if (house.photos.length < 2) {
  throw new Error('House must have at least two photos!');
}

const house2 = await House.findOne({ _id });
house2.photos = [];
await house2.save();

// Throws 'VersionError: No matching document found for id "..." version 0'
house.status = 'APPROVED';
await house.save();

```
 option: 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).

 
```
const schema = new Schema({
  name: String
}, { collation: { locale: 'en\_US', strength: 1 } });

const MyModel = db.model('MyModel', schema);

MyModel.create([{ name: 'val' }, { name: 'Val' }]).
  then(() => {
    return MyModel.find({ name: 'val' });
  }).
  then((docs) => {
    // `docs` will contain both docs, because `strength: 1` means
    // MongoDB will ignore case when matching.
  });

```
 option: 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.

 
```
const schema = Schema({ name: String, timestamp: Date, metadata: Object }, {
  timeseries: {
    timeField: 'timestamp',
    metaField: 'metadata',
    granularity: 'hours'
  },
  autoCreate: false,
  expireAfterSeconds: 86400
});

// `Test` collection will be a timeseries collection
const Test = db.model('Test', schema);

```
 option: skipVersioning
----------------------

 `skipVersioning` allows excluding paths from versioning (i.e., the internal revision will not be incremented even if these paths are updated). DO NOT do this unless you know what you're doing. For subdocuments, include this on the parent document using the fully qualified path.

 
```
new Schema({ /\* ... \*/ }, { skipVersioning: { dontVersionMe: true } });
thing.dontVersionMe.push('hey');
thing.save(); // version is not incremented

```
 option: timestamps
------------------

 The `timestamps` option tells Mongoose to assign `createdAt` and `updatedAt` fields to your schema. The type assigned is [Date](schematypes#dates).

 By default, the names of the fields are `createdAt` and `updatedAt`. Customize the field names by setting `timestamps.createdAt` and `timestamps.updatedAt`.

 The way `timestamps` works under the hood is:

 * If you create a new document, mongoose simply sets `createdAt`, and `updatedAt` to the time of creation.
* If you update a document, mongoose will add `updatedAt` to the `$set` object.
* If you set `upsert: true` on an update operation, mongoose will use [`$setOnInsert`](https://www.mongodb.com/docs/manual/reference/operator/update/setOnInsert/) operator to add `createdAt` to the document in case the `upsert` operation resulted into a new inserted document.

 
```
const thingSchema = new Schema({ /\* ... \*/ }, { timestamps: { createdAt: 'created\_at' } });
const Thing = mongoose.model('Thing', thingSchema);
const thing = new Thing();
await thing.save(); // `created\_at` & `updatedAt` will be included

// With updates, Mongoose will add `updatedAt` to `$set`
await Thing.updateOne({}, { $set: { name: 'Test' } });

// If you set upsert: true, Mongoose will add `created\_at` to `$setOnInsert` as well
await Thing.findOneAndUpdate({}, { $set: { name: 'Test2' } });

// Mongoose also adds timestamps to bulkWrite() operations
// See https://mongoosejs.com/docs/api/model.html#model\_Model-bulkWrite
await Thing.bulkWrite([
  {
    insertOne: {
      document: {
        name: 'Jean-Luc Picard',
        ship: 'USS Stargazer'
      // Mongoose will add `created\_at` and `updatedAt`
      }
    }
  },
  {
    updateOne: {
      filter: { name: 'Jean-Luc Picard' },
      update: {
        $set: {
          ship: 'USS Enterprise'
        // Mongoose will add `updatedAt`
        }
      }
    }
  }
]);

```
 By default, Mongoose uses `new Date()` to get the current time. If you want to overwrite the function Mongoose uses to get the current time, you can set the `timestamps.currentTime` option. Mongoose will call the `timestamps.currentTime` function whenever it needs to get the current time.

 
```
const schema = Schema({
  createdAt: Number,
  updatedAt: Number,
  name: String
}, {
  // Make Mongoose use Unix time (seconds since Jan 1, 1970)
  timestamps: { currentTime: () => Math.floor(Date.now() / 1000) }
});

```
 option: pluginTags
------------------

 Mongoose supports defining global plugins, plugins that apply to all schemas.

 
```
// Add a `meta` property to all schemas
mongoose.plugin(function myPlugin(schema) {
  schema.add({ meta: {} });
});

```
 Sometimes, you may only want to apply a given plugin to some schemas. In that case, you can add `pluginTags` to a schema:

 
```
const schema1 = new Schema({
  name: String
}, { pluginTags: ['useMetaPlugin'] });

const schema2 = new Schema({
  name: String
});

```
 If you call `plugin()` with a `tags` option, Mongoose will only apply that plugin to schemas that have a matching entry in `pluginTags`.

 
```
// Add a `meta` property to all schemas
mongoose.plugin(function myPlugin(schema) {
  schema.add({ meta: {} });
}, { tags: ['useMetaPlugin'] });

```
  option: selectPopulatedPaths
-----------------------------

 By default, Mongoose will automatically `select()` any populated paths for you, unless you explicitly exclude them.

 
```
const bookSchema = new Schema({
  title: 'String',
  author: { type: 'ObjectId', ref: 'Person' }
});
const Book = mongoose.model('Book', bookSchema);

// By default, Mongoose will add `author` to the below `select()`.
await Book.find().select('title').populate('author');

// In other words, the below query is equivalent to the above
await Book.find().select('title author').populate('author');

```
 To opt out of selecting populated fields by default, set `selectPopulatedPaths` to `false` in your schema.

 
```
const bookSchema = new Schema({
  title: 'String',
  author: { type: 'ObjectId', ref: 'Person' }
}, { selectPopulatedPaths: false });
const Book = mongoose.model('Book', bookSchema);

// Because `selectPopulatedPaths` is false, the below doc will \*\*not\*\*
// contain an `author` property.
const doc = await Book.findOne().select('title').populate('author');

```
  option: 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 in the single nested schema path as well. For example:

 
```
const childSchema = new Schema({ name: { type: String, required: true } });
const parentSchema = new Schema({ child: childSchema });

const Parent = mongoose.model('Parent', parentSchema);

// Will contain an error for both 'child.name' \_and\_ 'child'
new Parent({ child: {} }).validateSync().errors;

```
 Set the `storeSubdocValidationError` to `false` on the child schema to make Mongoose only reports the parent error.

 
```
const childSchema = new Schema({
  name: { type: String, required: true }
}, { storeSubdocValidationError: false }); // <-- set on the child schema
const parentSchema = new Schema({ child: childSchema });

const Parent = mongoose.model('Parent', parentSchema);

// Will only contain an error for 'child.name'
new Parent({ child: {} }).validateSync().errors;

```
  option: 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. You can use the `collectionOptions` option to set any `createCollection()` options; Mongoose will use `collectionOptions` as the default values when calling `createCollection()` for your schema.

 
```
const schema = new Schema({ name: String }, {
  autoCreate: false,
  collectionOptions: {
    capped: true,
    max: 1000
  }
});
const Test = mongoose.model('Test', schema);

// Equivalent to `createCollection({ capped: true, max: 1000 })`
await Test.createCollection();

```
 With ES6 Classes
----------------

 Schemas have a [`loadClass()` method](api/schema#schema_Schema-loadClass) that you can use to create a Mongoose schema from an [ES6 class](https://thecodebarbarian.com/an-overview-of-es6-classes):

 * [ES6 class methods](https://masteringjs.io/tutorials/fundamentals/class#methods) become [Mongoose methods](guide#methods)
* [ES6 class statics](https://masteringjs.io/tutorials/fundamentals/class#statics) become [Mongoose statics](guide#statics)
* [ES6 getters and setters](https://masteringjs.io/tutorials/fundamentals/class#getterssetters) become [Mongoose virtuals](tutorials/virtuals)

 Here's an example of using `loadClass()` to create a schema from an ES6 class:

 
```
class MyClass {
  myMethod() { return 42; }
  static myStatic() { return 42; }
  get myVirtual() { return 42; }
}

const schema = new mongoose.Schema();
schema.loadClass(MyClass);

console.log(schema.methods); // { myMethod: [Function: myMethod] }
console.log(schema.statics); // { myStatic: [Function: myStatic] }
console.log(schema.virtuals); // { myVirtual: VirtualType { ... } }

```
 Pluggable
---------

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

 Further Reading
---------------

 Here's an [alternative introduction to Mongoose schemas](https://masteringjs.io/tutorials/mongoose/schema).

 To get the most out of MongoDB, you need to learn the basics of MongoDB schema design. SQL schema design (third normal form) was designed to [minimize storage costs](https://en.wikipedia.org/wiki/Third_normal_form), whereas MongoDB schema design is about making common queries as fast as possible. The [*6 Rules of Thumb for MongoDB Schema Design* blog series](https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-1) is an excellent resource for learning the basic rules for making your queries fast.

 Users looking to master MongoDB schema design in Node.js should look into [*The Little MongoDB Schema Design Book*](http://bit.ly/mongodb-schema-design) by Christian Kvalheim, the original author of the [MongoDB Node.js driver](http://npmjs.com/package/mongodb). 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
-------

 Now that we've covered `Schemas`, let's take a look at [SchemaTypes](schematypes).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/guide.html>

Documents
==========

 Mongoose [documents](api/document) represent a one-to-one mapping to documents as stored in MongoDB. Each document is an instance of its [Model](models).

 Documents vs Models
-------------------

 [Document](api/document#Document) and [Model](api/model#Model) are distinct classes in Mongoose. The Model class is a subclass of the Document class. When you use the [Model constructor](api/model#Model), you create a new document.

 
```
const MyModel = mongoose.model('Test', new Schema({ name: String }));
const doc = new MyModel();

doc instanceof MyModel; // true
doc instanceof mongoose.Model; // true
doc instanceof mongoose.Document; // true

```
 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
----------

 When you load documents from MongoDB using model functions like [`findOne()`](api/model#model_Model-findOne), you get a Mongoose document back.

 
```
const doc = await MyModel.findOne();

doc instanceof MyModel; // true
doc instanceof mongoose.Model; // true
doc instanceof mongoose.Document; // true

```
 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/).

 
```
doc.name = 'foo';

// Mongoose sends an `updateOne({ \_id: doc.\_id }, { $set: { name: 'foo' } })`
// to MongoDB.
await doc.save();

```
 The `save()` method returns a promise. If `save()` succeeds, the promise resolves to the document that was saved.

 
```
doc.save().then(savedDoc => {
  savedDoc === doc; // true
});

```
 If the document with the corresponding `_id` is not found, Mongoose will report a `DocumentNotFoundError`:

 
```
const doc = await MyModel.findOne();

// Delete the document so Mongoose won't be able to save changes
await MyModel.deleteOne({ \_id: doc.\_id });

doc.name = 'foo';
await doc.save(); // Throws DocumentNotFoundError

```
 Updating Using Queries
----------------------

 The [`save()`](api/model#model_Model-save) function is generally the right way to update a document with Mongoose. With `save()`, you get full <validation> and <middleware>.

 For cases when `save()` isn't flexible enough, Mongoose lets you create your own [MongoDB updates](https://www.mongodb.com/docs/manual/reference/operator/update/) with casting, [middleware](middleware#notes), and [limited validation](validation#update-validators).

 
```
// Update all documents in the `mymodels` collection
await MyModel.updateMany({}, { $set: { name: 'foo' } });

```
 *Note that `update()`, `updateMany()`, `findOneAndUpdate()`, etc. do **not** execute `save()` middleware. If you need save middleware and full validation, first query for the document and then `save()` it.*

 Validating
----------

 Documents are casted and validated before they are saved. Mongoose first casts values to the specified type and then validates them. Internally, Mongoose calls the document's [`validate()` method](api/document#document_Document-validate) before saving.

 
```
const schema = new Schema({ name: String, age: { type: Number, min: 0 } });
const Person = mongoose.model('Person', schema);

const p = new Person({ name: 'foo', age: 'bar' });
// Cast to Number failed for value "bar" at path "age"
await p.validate();

const p2 = new Person({ name: 'foo', age: -1 });
// Path `age` (-1) is less than minimum allowed value (0).
await p2.validate();

```
 Mongoose also supports limited validation on updates using the [`runValidators` option](validation#update-validators). Mongoose casts parameters to query functions like `findOne()`, `updateOne()` by default. However, Mongoose does *not* run validation on query function parameters by default. You need to set `runValidators: true` for Mongoose to validate.

 
```
// Cast to number failed for value "bar" at path "age"
await Person.updateOne({}, { age: 'bar' });

// Path `age` (-1) is less than minimum allowed value (0).
await Person.updateOne({}, { age: -1 }, { runValidators: true });

```
 Read the <validation> guide for more details.

 Overwriting
-----------

 There are 2 different ways to overwrite a document (replacing all keys in the document). One way is to use the [`Document#overwrite()` function](api/document#document_Document-overwrite) followed by `save()`.

 
```
const doc = await Person.findOne({ _id });

// Sets `name` and unsets all other properties
doc.overwrite({ name: 'Jean-Luc Picard' });
await doc.save();

```
 The other way is to use [`Model.replaceOne()`](api/model#model_Model-replaceOne).

 
```
// Sets `name` and unsets all other properties
await Person.replaceOne({ _id }, { name: 'Jean-Luc Picard' });

```
  Next Up
--------

 Now that we've covered Documents, let's take a look at [Subdocuments](subdocs).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/documents.html>

Query
=====



### Query()


##### Parameters:


* `[options]` «Object»
* `[model]` «Object»
* `[conditions]` «Object»
* `[collection]` «Object» Mongoose collection



Query constructor used for building queries. You do not need to instantiate a `Query` directly. Instead use Model functions like [`Model.find()`](model#Model.find()).

 ####   [Example:](#example)

 
```
const query = MyModel.find(); // `query` is an instance of `Query`
query.setOptions({ lean : true });
query.collection(MyModel.collection);
query.where('age').gte(21).exec(callback);

// You can instantiate a query directly. There is no need to do
// this unless you're an advanced user with a very good reason to.
const query = new mongoose.Query();

```
 
### Query.prototype.$where()


##### Parameters:


* `js` «String|Function» javascript string or function


##### Returns:


* «Query» this


##### See:


* [$where](https://www.mongodb.com/docs/manual/reference/operator/where/)



Specifies a javascript function or expression to pass to MongoDBs query system.

 ####   [Example:](#example)

 
```
query.$where('this.comments.length === 10 || this.name.length === 5')

// or

query.$where(function () {
  return this.comments.length === 10 || this.name.length === 5;
})

```
 ####   [Note:](#note)

 Only use `$where` when you have a condition that cannot be met using other MongoDB operators like `$lt`. **Be sure to read about all of [its caveats](https://www.mongodb.com/docs/manual/reference/operator/where/) before using.**

 
### Query.prototype.all()


##### Parameters:


* `[path]` «String»
* `val` «Array»


##### See:


* [$all](https://www.mongodb.com/docs/manual/reference/operator/all/)



Specifies an `$all` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 ####   [Example:](#example)

 
```
MyModel.find().where('pets').all(['dog', 'cat', 'ferret']);
// Equivalent:
MyModel.find().all('pets', ['dog', 'cat', 'ferret']);

```
 
### Query.prototype.allowDiskUse()


##### Parameters:


* `[v]` «Boolean» Enable/disable `allowDiskUse`. If called with 0 arguments, sets `allowDiskUse: true`


##### Returns:


* «Query» this



Sets the [`allowDiskUse` option](https://www.mongodb.com/docs/manual/reference/method/cursor.allowDiskUse/), which allows the MongoDB server to use more than 100 MB for this query's `sort()`. This option can let you work around `QueryExceededMemoryLimitNoDiskUseAllowed` errors from the MongoDB server.

 Note that this option requires MongoDB server >= 4.4. Setting this option is a no-op for MongoDB 4.2 and earlier.

 Calling `query.allowDiskUse(v)` is equivalent to `query.setOptions({ allowDiskUse: v })`

 ####   [Example:](#example)

 
```
await query.find().sort({ name: 1 }).allowDiskUse(true);
// Equivalent:
await query.find().sort({ name: 1 }).allowDiskUse();

```
 
### Query.prototype.and()


##### Parameters:


* `array` «Array» array of conditions


##### Returns:


* «Query» this


##### See:


* [$and](https://www.mongodb.com/docs/manual/reference/operator/and/)



Specifies arguments for a `$and` condition.

 ####   [Example:](#example)

 
```
query.and([{ color: 'green' }, { status: 'ok' }])

```
 
### Query.prototype.batchSize()


##### Parameters:


* `val` «Number»


##### See:


* [batchSize](https://www.mongodb.com/docs/manual/reference/method/cursor.batchSize/)



Specifies the batchSize option.

 ####   [Example:](#example)

 
```
query.batchSize(100)

```
 ####   [Note:](#note)

 Cannot be used with `distinct()`

 
### Query.prototype.box()


##### Parameters:


* `val1` «Object|Array<Number>» Lower Left Coordinates OR a object of lower-left(ll) and upper-right(ur) Coordinates
* `[val2]` «Array<Number>» Upper Right Coordinates


##### Returns:


* «Query» this


##### See:


* [$box](https://www.mongodb.com/docs/manual/reference/operator/box/)
* [within() Query#within](#Query.prototype.within())
* [MongoDB Geospatial Indexing](https://www.mongodb.com/docs/manual/core/geospatial-indexes/)



Specifies a `$box` condition

 ####   [Example:](#example)

 
```
const lowerLeft = [40.73083, -73.99756]
const upperRight= [40.741404,  -73.988135]

query.where('loc').within().box(lowerLeft, upperRight)
query.box({ ll : lowerLeft, ur : upperRight })

```
 
### Query.prototype.cast()


##### Parameters:


* `[model]` «Model» the model to cast to. If not set, defaults to `this.model`
* `[obj]` «Object»


##### Returns:


* «Object»



Casts this query to the schema of `model`

 ####   [Note:](#note)

 If `obj` is present, it is cast instead of this query.

 
### Query.prototype.catch()


##### Parameters:


* `[reject]` «Function»


##### Returns:


* «Promise»



Executes the query returning a `Promise` which will be resolved with either the doc(s) or rejected with the error. Like `.then()`, but only takes a rejection handler.

 More about [Promise `catch()` in JavaScript](https://masteringjs.io/tutorials/fundamentals/catch).

 
### Query.prototype.center()


~DEPRECATED~
*DEPRECATED* Alias for [circle](#Query.prototype.circle())

 **Deprecated.** Use [circle](#Query.prototype.circle()) instead.

 
### Query.prototype.centerSphere()


~DEPRECATED~##### Parameters:


* `[path]` «String»
* `val` «Object»


##### Returns:


* «Query» this


##### See:


* [MongoDB Geospatial Indexing](https://www.mongodb.com/docs/manual/core/geospatial-indexes/)
* [$centerSphere](https://www.mongodb.com/docs/manual/reference/operator/centerSphere/)



*DEPRECATED* Specifies a `$centerSphere` condition

 **Deprecated.** Use [circle](#Query.prototype.circle()) instead.

 ####   [Example:](#example)

 
```
const area = { center: [50, 50], radius: 10 };
query.where('loc').within().centerSphere(area);

```
 
### Query.prototype.circle()


##### Parameters:


* `[path]` «String»
* `area` «Object»


##### Returns:


* «Query» this


##### See:


* [$center](https://www.mongodb.com/docs/manual/reference/operator/center/)
* [$centerSphere](https://www.mongodb.com/docs/manual/reference/operator/centerSphere/)
* [$geoWithin](https://www.mongodb.com/docs/manual/reference/operator/geoWithin/)
* [MongoDB Geospatial Indexing](https://www.mongodb.com/docs/manual/core/geospatial-indexes/)



Specifies a `$center` or `$centerSphere` condition.

 ####   [Example:](#example)

 
```
const area = { center: [50, 50], radius: 10, unique: true }
query.where('loc').within().circle(area)
// alternatively
query.circle('loc', area);

// spherical calculations
const area = { center: [50, 50], radius: 10, unique: true, spherical: true }
query.where('loc').within().circle(area)
// alternatively
query.circle('loc', area);

```
 
### Query.prototype.clone()


##### Returns:


* «Query» copy



Make a copy of this query so you can re-execute it.

 ####   [Example:](#example)

 
```
const q = Book.findOne({ title: 'Casino Royale' });
await q.exec();
await q.exec(); // Throws an error because you can't execute a query twice

await q.clone().exec(); // Works

```
 
### Query.prototype.collation()


##### Parameters:


* `value` «Object»


##### Returns:


* «Query» this


##### See:


* [MongoDB docs](https://www.mongodb.com/docs/manual/reference/method/cursor.collation/#cursor.collation)



Adds a collation to this op (MongoDB 3.4 and up)

 
### Query.prototype.comment()


##### Parameters:


* `val` «String»


##### See:


* [comment](https://www.mongodb.com/docs/manual/reference/operator/comment/)



Specifies the `comment` option.

 ####   [Example:](#example)

 
```
query.comment('login query')

```
 ####   [Note:](#note)

 Cannot be used with `distinct()`

 
### Query.prototype.count()


~DEPRECATED~##### Parameters:


* `[filter]` «Object» count documents that match this object


##### Returns:


* «Query» this


##### See:


* [count](https://www.mongodb.com/docs/manual/reference/method/db.collection.count/)



Specifies this query as a `count` query.

 This method is deprecated. If you want to count the number of documents in a collection, e.g. `count({})`, use the [`estimatedDocumentCount()` function](#Query.prototype.estimatedDocumentCount()) instead. Otherwise, use the [`countDocuments()`](#Query.prototype.countDocuments()) function instead.

 This function triggers the following middleware.

 * `count()`

 ####   [Example:](#example)

 
```
const countQuery = model.where({ 'color': 'black' }).count();

query.count({ color: 'black' }).count().exec();

await query.count({ color: 'black' });

query.where('color', 'black').count();

```
 
### Query.prototype.countDocuments()


##### Parameters:


* `[filter]` «Object» mongodb selector
* `[options]` «Object»


##### Returns:


* «Query» this


##### See:


* [countDocuments](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#countDocuments)



Specifies this query as a `countDocuments()` query. Behaves like `count()`, except it always does a full collection scan when passed an empty filter `{}`.

 There are also minor differences in how `countDocuments()` handles [`$where` and a couple geospatial operators](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#countDocuments). versus `count()`.

 This function triggers the following middleware.

 * `countDocuments()`

 ####   [Example:](#example)

 
```
const countQuery = model.where({ 'color': 'black' }).countDocuments();

query.countDocuments({ color: 'black' }).count().exec();

await query.countDocuments({ color: 'black' });

query.where('color', 'black').countDocuments().exec();

```
 The `countDocuments()` function is similar to `count()`, but there are a [few operators that `countDocuments()` does not support](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#countDocuments). Below are the operators that `count()` supports but `countDocuments()` does not, and the suggested replacement:

 * `$where`: [`$expr`](https://www.mongodb.com/docs/manual/reference/operator/query/expr/)
* `$near`: [`$geoWithin`](https://www.mongodb.com/docs/manual/reference/operator/query/geoWithin/) with [`$center`](https://www.mongodb.com/docs/manual/reference/operator/query/center/#op._S_center)
* `$nearSphere`: [`$geoWithin`](https://www.mongodb.com/docs/manual/reference/operator/query/geoWithin/) with [`$centerSphere`](https://www.mongodb.com/docs/manual/reference/operator/query/centerSphere/#op._S_centerSphere)

 
### Query.prototype.cursor()


##### Parameters:


* `[options]` «Object»


##### Returns:


* «QueryCursor»


##### See:


* [QueryCursor](querycursor)



Returns a wrapper around a [mongodb driver cursor](https://mongodb.github.io/node-mongodb-native/4.9/classes/FindCursor.html). A QueryCursor exposes a Streams3 interface, as well as a `.next()` function.

 The `.cursor()` function triggers pre find hooks, but **not** post find hooks.

 ####   [Example:](#example)

 
```
// There are 2 ways to use a cursor. First, as a stream:
Thing.
  find({ name: /^hello/ }).
  cursor().
  on('data', function(doc) { console.log(doc); }).
  on('end', function() { console.log('Done!'); });

// Or you can use `.next()` to manually get the next doc in the stream.
// `.next()` returns a promise, so you can use promises or callbacks.
const cursor = Thing.find({ name: /^hello/ }).cursor();
cursor.next(function(error, doc) {
  console.log(doc);
});

// Because `.next()` returns a promise, you can use co
// to easily iterate through all documents without loading them
// all into memory.
const cursor = Thing.find({ name: /^hello/ }).cursor();
for (let doc = await cursor.next(); doc != null; doc = await cursor.next()) {
  console.log(doc);
}

```
 ####   [Valid options](#valid-options)

 * `transform`: optional function which accepts a mongoose document. The return value of the function will be emitted on `data` and returned by `.next()`.

 
### Query.prototype.deleteMany()


##### Parameters:


* `[filter]` «Object|Query» mongodb selector
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](#Query.prototype.setOptions())


##### Returns:


* «Query» this


##### See:


* [DeleteResult](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/DeleteResult.html)
* [deleteMany](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#deleteMany)



Declare and/or execute this query as a `deleteMany()` operation. Works like remove, except it deletes *every* document that matches `filter` in the collection, regardless of the value of `single`.

 This function triggers `deleteMany` middleware.

 ####   [Example:](#example)

 
```
await Character.deleteMany({ name: /Stark/, age: { $gte: 18 } });

```
 This function calls the MongoDB driver's [`Collection#deleteMany()` function](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#deleteMany). The returned [promise](../queries) resolves to an object that contains 3 properties:

 * `ok`: `1` if no errors occurred
* `deletedCount`: the number of documents deleted
* `n`: the number of documents deleted. Equal to `deletedCount`.

 ####   [Example:](#example-1)

 
```
const res = await Character.deleteMany({ name: /Stark/, age: { $gte: 18 } });
// `0` if no docs matched the filter, number of docs deleted otherwise
res.deletedCount;

```
 
### Query.prototype.deleteOne()


##### Parameters:


* `[filter]` «Object|Query» mongodb selector
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](#Query.prototype.setOptions())


##### Returns:


* «Query» this


##### See:


* [DeleteResult](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/DeleteResult.html)
* [deleteOne](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#deleteOne)



Declare and/or execute this query as a `deleteOne()` operation. Works like remove, except it deletes at most one document regardless of the `single` option.

 This function triggers `deleteOne` middleware.

 ####   [Example:](#example)

 
```
await Character.deleteOne({ name: 'Eddard Stark' });

```
 This function calls the MongoDB driver's [`Collection#deleteOne()` function](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#deleteOne). The returned [promise](../queries) resolves to an object that contains 3 properties:

 * `ok`: `1` if no errors occurred
* `deletedCount`: the number of documents deleted
* `n`: the number of documents deleted. Equal to `deletedCount`.

 ####   [Example:](#example-1)

 
```
const res = await Character.deleteOne({ name: 'Eddard Stark' });
// `1` if MongoDB deleted a doc, `0` if no docs matched the filter `{ name: ... }`
res.deletedCount;

```
 
### Query.prototype.distinct()


##### Parameters:


* `[field]` «String»
* `[filter]` «Object|Query»


##### Returns:


* «Query» this


##### See:


* [distinct](https://www.mongodb.com/docs/manual/reference/method/db.collection.distinct/)



Declares or executes a distinct() operation.

 This function does not trigger any middleware.

 ####   [Example:](#example)

 
```
distinct(field, conditions)
distinct(field)
distinct()

```
 
### Query.prototype.elemMatch()


##### Parameters:


* `path` «String|Object|Function»
* `filter` «Object|Function»


##### Returns:


* «Query» this


##### See:


* [$elemMatch](https://www.mongodb.com/docs/manual/reference/operator/elemMatch/)



Specifies an `$elemMatch` condition

 ####   [Example:](#example)

 
```
query.elemMatch('comment', { author: 'autobot', votes: {$gte: 5}})

query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}})

query.elemMatch('comment', function (elem) {
  elem.where('author').equals('autobot');
  elem.where('votes').gte(5);
})

query.where('comment').elemMatch(function (elem) {
  elem.where({ author: 'autobot' });
  elem.where('votes').gte(5);
})

```
 
### Query.prototype.equals()


##### Parameters:


* `val` «Object»


##### Returns:


* «Query» this



Specifies the complementary comparison value for paths specified with `where()`

 ####   [Example:](#example)

 
```
User.where('age').equals(49);

// is the same as

User.where('age', 49);

```
 
### Query.prototype.error()


##### Parameters:


* `err` «Error|null» if set, `exec()` will fail fast before sending the query to MongoDB


##### Returns:


* «Query» this



Gets/sets the error flag on this query. If this flag is not null or undefined, the `exec()` promise will reject without executing.

 ####   [Example:](#example)

 
```
Query().error(); // Get current error value
Query().error(null); // Unset the current error
Query().error(new Error('test')); // `exec()` will resolve with test
Schema.pre('find', function() {
  if (!this.getQuery().userId) {
    this.error(new Error('Not allowed to query without setting userId'));
  }
});

```
 Note that query casting runs **after** hooks, so cast errors will override custom errors.

 ####   [Example:](#example-1)

 
```
const TestSchema = new Schema({ num: Number });
const TestModel = db.model('Test', TestSchema);
TestModel.find({ num: 'not a number' }).error(new Error('woops')).exec(function(error) {
  // `error` will be a cast error because `num` failed to cast
});

```
 
### Query.prototype.estimatedDocumentCount()


##### Parameters:


* `[options]` «Object» passed transparently to the [MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/EstimatedDocumentCountOptions.html)


##### Returns:


* «Query» this


##### See:


* [estimatedDocumentCount](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#estimatedDocumentCount)



Specifies this query as a `estimatedDocumentCount()` query. Faster than using `countDocuments()` for large collections because `estimatedDocumentCount()` uses collection metadata rather than scanning the entire collection.

 `estimatedDocumentCount()` does **not** accept a filter. `Model.find({ foo: bar }).estimatedDocumentCount()` is equivalent to `Model.find().estimatedDocumentCount()`

 This function triggers the following middleware.

 * `estimatedDocumentCount()`

 ####   [Example:](#example)

 
```
await Model.find().estimatedDocumentCount();

```
 
### Query.prototype.exec()


##### Parameters:


* `[operation]` «String|Function»


##### Returns:


* «Promise»



Executes the query

 ####   [Example:](#example)

 
```
const promise = query.exec();
const promise = query.exec('update');

```
 
### Query.prototype.exists()


##### Parameters:


* `[path]` «String»
* `val` «Boolean»


##### Returns:


* «Query» this


##### See:


* [$exists](https://www.mongodb.com/docs/manual/reference/operator/exists/)



Specifies an `$exists` condition

 ####   [Example:](#example)

 
```
// { name: { $exists: true }}
Thing.where('name').exists()
Thing.where('name').exists(true)
Thing.find().exists('name')

// { name: { $exists: false }}
Thing.where('name').exists(false);
Thing.find().exists('name', false);

```
 
### Query.prototype.explain()


##### Parameters:


* `[verbose]` «String» The verbosity mode. Either 'queryPlanner', 'executionStats', or 'allPlansExecution'. The default is 'queryPlanner'


##### Returns:


* «Query» this



Sets the [`explain` option](https://www.mongodb.com/docs/manual/reference/method/cursor.explain/), which makes this query return detailed execution stats instead of the actual query result. This method is useful for determining what index your queries use.

 Calling `query.explain(v)` is equivalent to `query.setOptions({ explain: v })`

 ####   [Example:](#example)

 
```
const query = new Query();
const res = await query.find({ a: 1 }).explain('queryPlanner');
console.log(res);

```
 
### Query.prototype.finally()


##### Parameters:


* `[onFinally]` «Function»


##### Returns:


* «Promise»



Executes the query returning a `Promise` which will be resolved with `.finally()` chained.

 More about [Promise `finally()` in JavaScript](https://thecodebarbarian.com/using-promise-finally-in-node-js.html).

 
### Query.prototype.find()


##### Parameters:


* `[filter]` «Object|ObjectId» mongodb filter. If not specified, returns all documents.


##### Returns:


* «Query» this



Find all documents that match `selector`. The result will be an array of documents.

 If there are too many documents in the result to fit in memory, use [`Query.prototype.cursor()`](#Query.prototype.cursor())

 ####   [Example:](#example)

 
```
const arr = await Movie.find({ year: { $gte: 1980, $lte: 1989 } });

```
 
### Query.prototype.findOne()


##### Parameters:


* `[filter]` «Object» mongodb selector
* `[projection]` «Object» optional fields to return
* `[options]` «Object» see [`setOptions()`](#Query.prototype.setOptions())
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query» this


##### See:


* [findOne](https://www.mongodb.com/docs/manual/reference/method/db.collection.findOne/)
* [Query.select](#Query.prototype.select())



Declares the query a findOne operation. When executed, the first found document is passed to the callback.

 The result of the query is a single document, or `null` if no document was found.

 * *Note:* `conditions` is optional, and if `conditions` is null or undefined, mongoose will send an empty `findOne` command to MongoDB, which will return an arbitrary document. If you're querying by `_id`, use `Model.findById()` instead.

 This function triggers the following middleware.

 * `findOne()`

 ####   [Example:](#example)

 
```
const query = Kitten.where({ color: 'white' });
const kitten = await query.findOne();

```
 
### Query.prototype.findOneAndDelete()


##### Parameters:


* `[filter]` «Object»
* `[options]` «Object»
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)


##### Returns:


* «Query» this


##### See:


* [findAndModify command](https://www.mongodb.com/docs/manual/reference/command/findAndModify/)



Issues a MongoDB [findOneAndDelete](https://www.mongodb.com/docs/manual/reference/method/db.collection.findOneAndDelete/) command.

 Finds a matching document, removes it, and returns the found document (if any).

 This function triggers the following middleware.

 * `findOneAndDelete()`

 ####   [Available options](#available-options)

 * `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
* `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
* `rawResult`: if true, resolves to the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)

 ####   [Callback Signature](#callback-signature)

 
```
function(error, doc) {
  // error: any errors that occurred
  // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
}

```
 ####   [Example:](#example)

 
```
A.where().findOneAndDelete(conditions, options)  // return Query
A.where().findOneAndDelete(conditions) // returns Query
A.where().findOneAndDelete()           // returns Query

```
 
### Query.prototype.findOneAndRemove()


##### Parameters:


* `[conditions]` «Object»
* `[options]` «Object»
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)


##### Returns:


* «Query» this


##### See:


* [findAndModify command](https://www.mongodb.com/docs/manual/reference/command/findAndModify/)



Legacy alias for `findOneAndDelete()`.

 Finds a matching document, removes it, returns the found document (if any).

 This function triggers the following middleware.

 * `findOneAndRemove()`

 ####   [Available options](#available-options)

 * `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
* `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
* `rawResult`: if true, resolves to the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)

 ####   [Example:](#example)

 
```
A.where().findOneAndRemove(conditions, options)  // return Query
A.where().findOneAndRemove(conditions) // returns Query
A.where().findOneAndRemove()           // returns Query

```
 
### Query.prototype.findOneAndReplace()


##### Parameters:


* `[filter]` «Object»
* `[replacement]` «Object»
* `[options]` «Object»
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.new=false]` «Boolean» By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied.
+ `[options.lean]` «Object» if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](#Query.prototype.lean()) and [the Mongoose lean tutorial](../tutorials/lean).
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ `[options.returnOriginal=null]` «Boolean» An alias for the `new` option. `returnOriginal: false` is equivalent to `new: true`.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query» this



Issues a MongoDB [findOneAndReplace](https://www.mongodb.com/docs/manual/reference/method/db.collection.findOneAndReplace/) command.

 Finds a matching document, removes it, and returns the found document (if any).

 This function triggers the following middleware.

 * `findOneAndReplace()`

 ####   [Available options](#available-options)

 * `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
* `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
* `rawResult`: if true, resolves to the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)

 ####   [Callback Signature](#callback-signature)

 
```
function(error, doc) {
  // error: any errors that occurred
  // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
}

```
 ####   [Example:](#example)

 
```
A.where().findOneAndReplace(filter, replacement, options); // return Query
A.where().findOneAndReplace(filter); // returns Query
A.where().findOneAndReplace(); // returns Query

```
 
### Query.prototype.findOneAndUpdate()


##### Parameters:


* `[filter]` «Object|Query»
* `[doc]` «Object»
* `[options]` «Object»
+ `[options.rawResult]` «Boolean» if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.multipleCastError]` «Boolean» by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
+ `[options.new=false]` «Boolean» By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied.
+ `[options.lean]` «Object» if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](#Query.prototype.lean()) and [the Mongoose lean tutorial](../tutorials/lean).
+ `[options.session=null]` «ClientSession» The session associated with this query. See [transactions docs](../transactions).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ `[options.returnOriginal=null]` «Boolean» An alias for the `new` option. `returnOriginal: false` is equivalent to `new: true`.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.


##### Returns:


* «Query» this


##### See:


* [Tutorial](../tutorials/findoneandupdate)
* [findAndModify command](https://www.mongodb.com/docs/manual/reference/command/findAndModify/)
* [ModifyResult](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
* [findOneAndUpdate](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#findOneAndUpdate)



Issues a mongodb `findOneAndUpdate()` command.

 Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any).

 This function triggers the following middleware.

 * `findOneAndUpdate()`

 ####   [Available options](#available-options)

 * `new`: bool - if true, return the modified document rather than the original. defaults to false (changed in 4.0)
* `upsert`: bool - creates the object if it doesn't exist. defaults to false.
* `fields`: {Object|String} - Field selection. Equivalent to `.select(fields).findOneAndUpdate()`
* `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
* `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
* `runValidators`: if true, runs [update validators](../validation#update-validators) on this command. Update validators validate the update operation against the model's schema.
* `setDefaultsOnInsert`: `true` by default. If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](../defaults) specified in the model's schema if a new document is created.
* `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)

 ####   [Example:](#example)

 
```
query.findOneAndUpdate(conditions, update, options)  // returns Query
query.findOneAndUpdate(conditions, update)           // returns Query
query.findOneAndUpdate(update)                       // returns Query
query.findOneAndUpdate()                             // returns Query

```
 
### Query.prototype.geometry()


##### Parameters:


* `object` «Object» Must contain a `type` property which is a String and a `coordinates` property which is an Array. See the examples.


##### Returns:


* «Query» this


##### See:


* [$geometry](https://www.mongodb.com/docs/manual/reference/operator/geometry/)
* [Geospatial Support Enhancements](https://www.mongodb.com/docs/manual/release-notes/2.4/#geospatial-support-enhancements)
* [MongoDB Geospatial Indexing](https://www.mongodb.com/docs/manual/core/geospatial-indexes/)



Specifies a `$geometry` condition

 ####   [Example:](#example)

 
```
const polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]]
query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA })

// or
const polyB = [[ 0, 0 ], [ 1, 1 ]]
query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB })

// or
const polyC = [ 0, 0 ]
query.where('loc').within().geometry({ type: 'Point', coordinates: polyC })

// or
query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC })

```
 The argument is assigned to the most recent path passed to `where()`.

 ####   [Note:](#note)

 `geometry()` **must** come after either `intersects()` or `within()`.

 The `object` argument must contain `type` and `coordinates` properties.

 * type {String}
* coordinates {Array}

 
### Query.prototype.get()


##### Parameters:


* `path` «String|Object» path or object of key/value pairs to get


##### Returns:


* «Query» this



For update operations, returns the value of a path in the update's `$set`. Useful for writing getters/setters that can work with both update operations and `save()`.

 ####   [Example:](#example)

 
```
const query = Model.updateOne({}, { $set: { name: 'Jean-Luc Picard' } });
query.get('name'); // 'Jean-Luc Picard'

```
 
### Query.prototype.getFilter()


##### Returns:


* «Object» current query filter



Returns the current query filter (also known as conditions) as a [POJO](https://masteringjs.io/tutorials/fundamentals/pojo).

 ####   [Example:](#example)

 
```
const query = new Query();
query.find({ a: 1 }).where('b').gt(2);
query.getFilter(); // { a: 1, b: { $gt: 2 } }

```
 
### Query.prototype.getOptions()


##### Returns:


* «Object» the options



Gets query options.

 ####   [Example:](#example)

 
```
const query = new Query();
query.limit(10);
query.setOptions({ maxTimeMS: 1000 });
query.getOptions(); // { limit: 10, maxTimeMS: 1000 }

```
 
### Query.prototype.getPopulatedPaths()


##### Returns:


* «Array» an array of strings representing populated paths



Gets a list of paths to be populated by this query

 ####   [Example:](#example)

 
```
 bookSchema.pre('findOne', function() {
   let keys = this.getPopulatedPaths(); // ['author']
 });
 ...
 Book.findOne({}).populate('author');

```
 ####   [Example:](#example-1)

 
```
 // Deep populate
 const q = L1.find().populate({
   path: 'level2',
   populate: { path: 'level3' }
 });
 q.getPopulatedPaths(); // ['level2', 'level2.level3']

```
 
### Query.prototype.getQuery()


##### Returns:


* «Object» current query filter



Returns the current query filter. Equivalent to `getFilter()`.

 You should use `getFilter()` instead of `getQuery()` where possible. `getQuery()` will likely be deprecated in a future release.

 ####   [Example:](#example)

 
```
const query = new Query();
query.find({ a: 1 }).where('b').gt(2);
query.getQuery(); // { a: 1, b: { $gt: 2 } }

```
 
### Query.prototype.getUpdate()


##### Returns:


* «Object» current update operations



Returns the current update operations as a JSON object.

 ####   [Example:](#example)

 
```
const query = new Query();
query.updateOne({}, { $set: { a: 5 } });
query.getUpdate(); // { $set: { a: 5 } }

```
 
### Query.prototype.gt()


##### Parameters:


* `[path]` «String»
* `val` «Number»


##### See:


* [$gt](https://www.mongodb.com/docs/manual/reference/operator/gt/)



Specifies a `$gt` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 ####   [Example:](#example)

 
```
Thing.find().where('age').gt(21);

// or
Thing.find().gt('age', 21);

```
 
### Query.prototype.gte()


##### Parameters:


* `[path]` «String»
* `val` «Number»


##### See:


* [$gte](https://www.mongodb.com/docs/manual/reference/operator/gte/)



Specifies a `$gte` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 
### Query.prototype.hint()


##### Parameters:


* `val` «Object» a hint object


##### Returns:


* «Query» this


##### See:


* [$hint](https://www.mongodb.com/docs/manual/reference/operator/hint/)



Sets query hints.

 ####   [Example:](#example)

 
```
query.hint({ indexA: 1, indexB: -1 });

```
 ####   [Note:](#note)

 Cannot be used with `distinct()`

 
### Query.prototype.in()


##### Parameters:


* `[path]` «String»
* `val` «Array»


##### See:


* [$in](https://www.mongodb.com/docs/manual/reference/operator/in/)



Specifies an `$in` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 
### Query.prototype.intersects()


##### Parameters:


* `[arg]` «Object»


##### Returns:


* «Query» this


##### See:


* [$geometry](https://www.mongodb.com/docs/manual/reference/operator/geometry/)
* [geoIntersects](https://www.mongodb.com/docs/manual/reference/operator/geoIntersects/)



Declares an intersects query for `geometry()`.

 ####   [Example:](#example)

 
```
query.where('path').intersects().geometry({
  type: 'LineString',
  coordinates: [[180.0, 11.0], [180, 9.0]]
});

query.where('path').intersects({
  type: 'LineString',
  coordinates: [[180.0, 11.0], [180, 9.0]]
});

```
 ####   [Note:](#note)

 **MUST** be used after `where()`.

 ####   [Note:](#note-1)

 In Mongoose 3.7, `intersects` changed from a getter to a function. If you need the old syntax, use [this](https://github.com/ebensing/mongoose-within).

 
### Query.prototype.isPathSelectedInclusive()


##### Parameters:


* `path` «String»


##### Returns:


* «Boolean»



Wrapper function to call isPathSelectedInclusive on a query.

 
### Query.prototype.j()


##### Parameters:


* `val` «boolean»


##### Returns:


* «Query» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/write-concern/#j-option)



Requests acknowledgement that this operation has been persisted to MongoDB's on-disk journal. This option is only valid for operations that write to the database:

 * `deleteOne()`
* `deleteMany()`
* `findOneAndDelete()`
* `findOneAndReplace()`
* `findOneAndUpdate()`
* `updateOne()`
* `updateMany()`

 Defaults to the schema's [`writeConcern.j` option](../guide#writeConcern)

 ####   [Example:](#example)

 
```
await mongoose.model('Person').deleteOne({ name: 'Ned Stark' }).j(true);

```
 
### Query.prototype.lean()


##### Parameters:


* `bool` «Boolean|Object» defaults to true


##### Returns:


* «Query» this



Sets the lean option.

 Documents returned from queries with the `lean` option enabled are plain javascript objects, not [Mongoose Documents](document). They have no `save` method, getters/setters, virtuals, or other Mongoose features.

 ####   [Example:](#example)

 
```
new Query().lean() // true
new Query().lean(true)
new Query().lean(false)

const docs = await Model.find().lean();
docs[0] instanceof mongoose.Document; // false

```
 [Lean is great for high-performance, read-only cases](../tutorials/lean), especially when combined with [cursors](../queries#streaming).

 If you need virtuals, getters/setters, or defaults with `lean()`, you need to use a plugin. See:

 * [mongoose-lean-virtuals](https://plugins.mongoosejs.io/plugins/lean-virtuals)
* [mongoose-lean-getters](https://plugins.mongoosejs.io/plugins/lean-getters)
* [mongoose-lean-defaults](https://www.npmjs.com/package/mongoose-lean-defaults)

 
### Query.prototype.limit()


##### Parameters:


* `val` «Number»



Specifies the maximum number of documents the query will return.

 ####   [Example:](#example)

 
```
query.limit(20);

```
 ####   [Note:](#note)

 Cannot be used with `distinct()`

 
### Query.prototype.lt()


##### Parameters:


* `[path]` «String»
* `val` «Number»


##### See:


* [$lt](https://www.mongodb.com/docs/manual/reference/operator/lt/)



Specifies a `$lt` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 
### Query.prototype.lte()


##### Parameters:


* `[path]` «String»
* `val` «Number»


##### See:


* [$lte](https://www.mongodb.com/docs/manual/reference/operator/lte/)



Specifies a `$lte` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 
### Query.prototype.maxDistance()


##### Parameters:


* `[path]` «String»
* `val` «Number»


##### See:


* [$maxDistance](https://www.mongodb.com/docs/manual/reference/operator/maxDistance/)



Specifies a `maxDistance` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 
### Query.prototype.maxTimeMS()


##### Parameters:


* `[ms]` «Number» The number of milliseconds


##### Returns:


* «Query» this



Sets the [maxTimeMS](https://www.mongodb.com/docs/manual/reference/method/cursor.maxTimeMS/) option. This will tell the MongoDB server to abort if the query or write op has been running for more than `ms` milliseconds.

 Calling `query.maxTimeMS(v)` is equivalent to `query.setOptions({ maxTimeMS: v })`

 ####   [Example:](#example)

 
```
const query = new Query();
// Throws an error 'operation exceeded time limit' as long as there's
// >= 1 doc in the queried collection
const res = await query.find({ $where: 'sleep(1000) || true' }).maxTimeMS(100);

```
 
### Query.prototype.merge()


##### Parameters:


* `source` «Query|Object»


##### Returns:


* «Query» this



Merges another Query or conditions object into this one.

 When a Query is passed, conditions, field selection and options are merged.

 
### Query.prototype.mod()


##### Parameters:


* `[path]` «String»
* `val` «Array» must be of length 2, first element is `divisor`, 2nd element is `remainder`.


##### Returns:


* «Query» this


##### See:


* [$mod](https://www.mongodb.com/docs/manual/reference/operator/mod/)



Specifies a `$mod` condition, filters documents for documents whose `path` property is a number that is equal to `remainder` modulo `divisor`.

 ####   [Example:](#example)

 
```
// All find products whose inventory is odd
Product.find().mod('inventory', [2, 1]);
Product.find().where('inventory').mod([2, 1]);
// This syntax is a little strange, but supported.
Product.find().where('inventory').mod(2, 1);

```
 
### Query.prototype.model


##### Type:


* «property»



The model this query is associated with.

 ####   [Example:](#example)

 
```
const q = MyModel.find();
q.model === MyModel; // true

```
 
### Query.prototype.mongooseOptions()


##### Parameters:


* `options` «Object» if specified, overwrites the current options


##### Returns:


* «Object» the options



Getter/setter around the current mongoose-specific options for this query Below are the current Mongoose-specific options.

 * `populate`: an array representing what paths will be populated. Should have one entry for each call to [`Query.prototype.populate()`](#Query.prototype.populate())
* `lean`: if truthy, Mongoose will not [hydrate](model#Model.hydrate()) any documents that are returned from this query. See [`Query.prototype.lean()`](#Query.prototype.lean()) for more information.
* `strict`: controls how Mongoose handles keys that aren't in the schema for updates. This option is `true` by default, which means Mongoose will silently strip any paths in the update that aren't in the schema. See the [`strict` mode docs](../guide#strict) for more information.
* `strictQuery`: controls how Mongoose handles keys that aren't in the schema for the query `filter`. This option is `false` by default, which means Mongoose will allow `Model.find({ foo: 'bar' })` even if `foo` is not in the schema. See the [`strictQuery` docs](../guide#strictQuery) for more information.
* `nearSphere`: use `$nearSphere` instead of `near()`. See the [`Query.prototype.nearSphere()` docs](#Query.prototype.nearSphere())

 Mongoose maintains a separate object for internal options because Mongoose sends `Query.prototype.options` to the MongoDB server, and the above options are not relevant for the MongoDB server.

 
### Query.prototype.ne()


##### Parameters:


* `[path]` «String»
* `val` «any»


##### See:


* [$ne](https://www.mongodb.com/docs/manual/reference/operator/ne/)



Specifies a `$ne` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 
### Query.prototype.near()


##### Parameters:


* `[path]` «String»
* `val` «Object»


##### Returns:


* «Query» this


##### See:


* [$near](https://www.mongodb.com/docs/manual/reference/operator/near/)
* [$nearSphere](https://www.mongodb.com/docs/manual/reference/operator/nearSphere/)
* [$maxDistance](https://www.mongodb.com/docs/manual/reference/operator/maxDistance/)
* [MongoDB Geospatial Indexing](https://www.mongodb.com/docs/manual/core/geospatial-indexes/)



Specifies a `$near` or `$nearSphere` condition

 These operators return documents sorted by distance.

 ####   [Example:](#example)

 
```
query.where('loc').near({ center: [10, 10] });
query.where('loc').near({ center: [10, 10], maxDistance: 5 });
query.where('loc').near({ center: [10, 10], maxDistance: 5, spherical: true });
query.near('loc', { center: [10, 10], maxDistance: 5 });

```
 
### Query.prototype.nearSphere()


~DEPRECATED~##### See:


* [near()](#Query.prototype.near())
* [$near](https://www.mongodb.com/docs/manual/reference/operator/near/)
* [$nearSphere](https://www.mongodb.com/docs/manual/reference/operator/nearSphere/)
* [$maxDistance](https://www.mongodb.com/docs/manual/reference/operator/maxDistance/)



*DEPRECATED* Specifies a `$nearSphere` condition

 ####   [Example:](#example)

 
```
query.where('loc').nearSphere({ center: [10, 10], maxDistance: 5 });

```
 **Deprecated.** Use `query.near()` instead with the `spherical` option set to `true`.

 ####   [Example:](#example-1)

 
```
query.where('loc').near({ center: [10, 10], spherical: true });

```
 
### Query.prototype.nin()


##### Parameters:


* `[path]` «String»
* `val` «Array»


##### See:


* [$nin](https://www.mongodb.com/docs/manual/reference/operator/nin/)



Specifies an `$nin` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 
### Query.prototype.nor()


##### Parameters:


* `array` «Array» array of conditions


##### Returns:


* «Query» this


##### See:


* [$nor](https://www.mongodb.com/docs/manual/reference/operator/nor/)



Specifies arguments for a `$nor` condition.

 ####   [Example:](#example)

 
```
query.nor([{ color: 'green' }, { status: 'ok' }]);

```
 
### Query.prototype.or()


##### Parameters:


* `array` «Array» array of conditions


##### Returns:


* «Query» this


##### See:


* [$or](https://www.mongodb.com/docs/manual/reference/operator/or/)



Specifies arguments for an `$or` condition.

 ####   [Example:](#example)

 
```
query.or([{ color: 'red' }, { status: 'emergency' }]);

```
 
### Query.prototype.orFail()


##### Parameters:


* `[err]` «Function|Error» optional error to throw if no docs match `filter`. If not specified, `orFail()` will throw a `DocumentNotFoundError`


##### Returns:


* «Query» this



Make this query throw an error if no documents match the given `filter`. This is handy for integrating with async/await, because `orFail()` saves you an extra `if` statement to check if no document was found.

 ####   [Example:](#example)

 
```
// Throws if no doc returned
await Model.findOne({ foo: 'bar' }).orFail();

// Throws if no document was updated. Note that `orFail()` will still
// throw if the only document that matches is `{ foo: 'bar', name: 'test' }`,
// because `orFail()` will throw if no document was \_updated\_, not
// if no document was \_found\_.
await Model.updateOne({ foo: 'bar' }, { name: 'test' }).orFail();

// Throws "No docs found!" error if no docs match `{ foo: 'bar' }`
await Model.find({ foo: 'bar' }).orFail(new Error('No docs found!'));

// Throws "Not found" error if no document was found
await Model.findOneAndUpdate({ foo: 'bar' }, { name: 'test' }).
  orFail(() => Error('Not found'));

```
 
### Query.prototype.polygon()


##### Parameters:


* `[path]` «String|Array»
* `[...coordinatePairs]` «Array|Object»


##### Returns:


* «Query» this


##### See:


* [$polygon](https://www.mongodb.com/docs/manual/reference/operator/polygon/)
* [MongoDB Geospatial Indexing](https://www.mongodb.com/docs/manual/core/geospatial-indexes/)



Specifies a `$polygon` condition

 ####   [Example:](#example)

 
```
query.where('loc').within().polygon([10, 20], [13, 25], [7, 15]);
query.polygon('loc', [10, 20], [13, 25], [7, 15]);

```
 
### Query.prototype.populate()


##### Parameters:


* `path` «Object|String|Array[String]» either the path(s) to populate or an object specifying all parameters
* `[select]` «Object|String» Field selection for the population query
* `[model]` «Model» The model you wish to use for population. If not specified, populate will look up the model by the name in the Schema's `ref` field.
* `[match]` «Object» Conditions for the population query
* `[options]` «Object» Options for the population query (sort, etc)
+ `[options.path=null]` «String» The path to populate.
+ `[options.retainNullValues=false]` «boolean» by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
+ `[options.getters=false]` «boolean» if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](../schematypes#schematype-options).
+ `[options.clone=false]` «boolean» When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
+ `[options.match=null]` «Object|Function» Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/), or a function that returns a filter object.
+ `[options.transform=null]` «Function» Function that Mongoose will call on every populated document that allows you to transform the populated document.
+ `[options.options=null]` «Object» Additional options like `limit` and `lean`.


##### Returns:


* «Query» this


##### See:


* [population](../populate)
* [Query#select](#Query.prototype.select())
* [Model.populate](model#Model.populate())



Specifies paths which should be populated with other documents.

 ####   [Example:](#example)

 
```
let book = await Book.findOne().populate('authors');
book.title; // 'Node.js in Action'
book.authors[0].name; // 'TJ Holowaychuk'
book.authors[1].name; // 'Nathan Rajlich'

let books = await Book.find().populate({
  path: 'authors',
  // `match` and `sort` apply to the Author model,
  // not the Book model. These options do not affect
  // which documents are in `books`, just the order and
  // contents of each book document's `authors`.
  match: { name: new RegExp('.\*h.\*', 'i') },
  sort: { name: -1 }
});
books[0].title; // 'Node.js in Action'
// Each book's `authors` are sorted by name, descending.
books[0].authors[0].name; // 'TJ Holowaychuk'
books[0].authors[1].name; // 'Marc Harter'

books[1].title; // 'Professional AngularJS'
// Empty array, no authors' name has the letter 'h'
books[1].authors; // []

```
 Paths are populated after the query executes and a response is received. A separate query is then executed for each path specified for population. After a response for each query has also been returned, the results are passed to the callback.

 
### Query.prototype.post()


##### Parameters:


* `fn` «Function»


##### Returns:


* «Promise»



Add post [middleware](../middleware) to this query instance. Doesn't affect other queries.

 ####   [Example:](#example)

 
```
const q1 = Question.find({ answer: 42 });
q1.post(function middleware() {
  console.log(this.getFilter());
});
await q1.exec(); // Prints "{ answer: 42 }"

// Doesn't print anything, because `middleware()` is only
// registered on `q1`.
await Question.find({ answer: 42 });

```
 
### Query.prototype.pre()


##### Parameters:


* `fn` «Function»


##### Returns:


* «Promise»



Add pre [middleware](../middleware) to this query instance. Doesn't affect other queries.

 ####   [Example:](#example)

 
```
const q1 = Question.find({ answer: 42 });
q1.pre(function middleware() {
  console.log(this.getFilter());
});
await q1.exec(); // Prints "{ answer: 42 }"

// Doesn't print anything, because `middleware()` is only
// registered on `q1`.
await Question.find({ answer: 42 });

```
 
### Query.prototype.projection()


##### Parameters:


* `arg` «Object|null»


##### Returns:


* «Object» the current projection



Get/set the current projection (AKA fields). Pass `null` to remove the current projection.

 Unlike `projection()`, the `select()` function modifies the current projection in place. This function overwrites the existing projection.

 ####   [Example:](#example)

 
```
const q = Model.find();
q.projection(); // null

q.select('a b');
q.projection(); // { a: 1, b: 1 }

q.projection({ c: 1 });
q.projection(); // { c: 1 }

q.projection(null);
q.projection(); // null

```
 
### Query.prototype.read()


##### Parameters:


* `mode` «String» one of the listed preference options or aliases
* `[tags]` «Array» optional tags for this query


##### Returns:


* «Query» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/applications/replication/#read-preference)



Determines the MongoDB nodes from which to read.

 ####   [Preferences:](#preferences)

 
```
primary - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags.
secondary            Read from secondary if available, otherwise error.
primaryPreferred     Read from primary if available, otherwise a secondary.
secondaryPreferred   Read from a secondary if available, otherwise read from the primary.
nearest              All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection.

```
 Aliases

 
```
p   primary
pp  primaryPreferred
s   secondary
sp  secondaryPreferred
n   nearest

```
 ####   [Example:](#example)

 
```
new Query().read('primary')
new Query().read('p')  // same as primary

new Query().read('primaryPreferred')
new Query().read('pp') // same as primaryPreferred

new Query().read('secondary')
new Query().read('s')  // same as secondary

new Query().read('secondaryPreferred')
new Query().read('sp') // same as secondaryPreferred

new Query().read('nearest')
new Query().read('n')  // same as nearest

// read from secondaries with matching tags
new Query().read('s', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }])

```
 Read more about how to use read preferences [here](https://www.mongodb.com/docs/manual/applications/replication/#read-preference).

 
### Query.prototype.readConcern()


##### Parameters:


* `level` «String» one of the listed read concern level or their aliases


##### Returns:


* «Query» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/read-concern/)



Sets the readConcern option for the query.

 ####   [Example:](#example)

 
```
new Query().readConcern('local')
new Query().readConcern('l')  // same as local

new Query().readConcern('available')
new Query().readConcern('a')  // same as available

new Query().readConcern('majority')
new Query().readConcern('m')  // same as majority

new Query().readConcern('linearizable')
new Query().readConcern('lz') // same as linearizable

new Query().readConcern('snapshot')
new Query().readConcern('s')  // same as snapshot

```
 ####   [Read Concern Level:](#read-concern-level)

 
```
local         MongoDB 3.2+ The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back).
available     MongoDB 3.6+ The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back).
majority      MongoDB 3.2+ The query returns the data that has been acknowledged by a majority of the replica set members. The documents returned by the read operation are durable, even in the event of failure.
linearizable  MongoDB 3.4+ The query returns data that reflects all successful majority-acknowledged writes that completed prior to the start of the read operation. The query may wait for concurrently executing writes to propagate to a majority of replica set members before returning results.
snapshot      MongoDB 4.0+ Only available for operations within multi-document transactions. Upon transaction commit with write concern "majority", the transaction operations are guaranteed to have read from a snapshot of majority-committed data.

```
 Aliases

 
```
l   local
a   available
m   majority
lz  linearizable
s   snapshot

```
 Read more about how to use read concern [here](https://www.mongodb.com/docs/manual/reference/read-concern/).

 
### Query.prototype.regex()


##### Parameters:


* `[path]` «String»
* `val` «String|RegExp»


##### See:


* [$regex](https://www.mongodb.com/docs/manual/reference/operator/regex/)



Specifies a `$regex` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 
### Query.prototype.replaceOne()


##### Parameters:


* `[filter]` «Object»
* `[doc]` «Object» the update command
* `[options]` «Object»
+ `[options.multipleCastError]` «Boolean» by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.upsert=false]` «Boolean» if true, and no documents found, insert a new document
+ `[options.writeConcern=null]` «Object» sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](../guide#writeConcern)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.

* `[callback]` «Function» params are (error, writeOpResult)


##### Returns:


* «Query» this


##### See:


* [Model.update](model#Model.update())
* [Query docs](../queries)
* [update](https://www.mongodb.com/docs/manual/reference/method/db.collection.update/)
* [UpdateResult](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/UpdateResult.html)
* [MongoDB docs](https://www.mongodb.com/docs/manual/reference/command/update/#update-command-output)



Declare and/or execute this query as a replaceOne() operation. MongoDB will replace the existing document and will not accept any [atomic operators](https://www.mongodb.com/docs/manual/tutorial/model-data-for-atomic-operations/#pattern) (`$set`, etc.)

 **Note** replaceOne will *not* fire update middleware. Use `pre('replaceOne')` and `post('replaceOne')` instead.

 ####   [Example:](#example)

 
```
const res = await Person.replaceOne({ \_id: 24601 }, { name: 'Jean Valjean' });
res.acknowledged; // Indicates if this write result was acknowledged. If not, then all other members of this result will be undefined.
res.matchedCount; // Number of documents that matched the filter
res.modifiedCount; // Number of documents that were modified
res.upsertedCount; // Number of documents that were upserted
res.upsertedId; // Identifier of the inserted document (if an upsert took place)

```
 This function triggers the following middleware.

 * `replaceOne()`

 
### Query.prototype.select()


##### Parameters:


* `arg` «Object|String|Array[String]»


##### Returns:


* «Query» this


##### See:


* [SchemaType](schematype)



Specifies which document fields to include or exclude (also known as the query "projection")

 When using string syntax, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included. Lastly, if a path is prefixed with `+`, it forces inclusion of the path, which is useful for paths excluded at the [schema level](schematype#SchemaType.prototype.select()).

 A projection *must* be either inclusive or exclusive. In other words, you must either list the fields to include (which excludes all others), or list the fields to exclude (which implies all other fields are included). The [`_id` field is the only exception because MongoDB includes it by default](https://www.mongodb.com/docs/manual/tutorial/project-fields-from-query-results/#suppress-id-field).

 ####   [Example:](#example)

 
```
// include a and b, exclude other fields
query.select('a b');
// Equivalent syntaxes:
query.select(['a', 'b']);
query.select({ a: 1, b: 1 });

// exclude c and d, include other fields
query.select('-c -d');

// Use `+` to override schema-level `select: false` without making the
// projection inclusive.
const schema = new Schema({
  foo: { type: String, select: false },
  bar: String
});
// ...
query.select('+foo'); // Override foo's `select: false` without excluding `bar`

// or you may use object notation, useful when
// you have keys already prefixed with a "-"
query.select({ a: 1, b: 1 });
query.select({ c: 0, d: 0 });

Additional calls to select can override the previous selection:
query.select({ a: 1, b: 1 }).select({ b: 0 }); // selection is now { a: 1 }
query.select({ a: 0, b: 0 }).select({ b: 1 }); // selection is now { a: 0 }

```
 
### Query.prototype.selected()


##### Returns:


* «Boolean»



Determines if field selection has been made.

 
### Query.prototype.selectedExclusively()


##### Returns:


* «Boolean»



Determines if exclusive field selection has been made.

 
```
query.selectedExclusively(); // false
query.select('-name');
query.selectedExclusively(); // true
query.selectedInclusively(); // false

```
 
### Query.prototype.selectedInclusively()


##### Returns:


* «Boolean»



Determines if inclusive field selection has been made.

 
```
query.selectedInclusively(); // false
query.select('name');
query.selectedInclusively(); // true

```
 
### Query.prototype.session()


##### Parameters:


* `[session]` «ClientSession» from `await conn.startSession()`


##### Returns:


* «Query» this


##### See:


* [Connection.prototype.startSession()](connection#Connection.prototype.startSession())
* [mongoose.startSession()](mongoose#Mongoose.prototype.startSession())



Sets the [MongoDB session](https://www.mongodb.com/docs/manual/reference/server-sessions/) associated with this query. Sessions are how you mark a query as part of a [transaction](../transactions).

 Calling `session(null)` removes the session from this query.

 ####   [Example:](#example)

 
```
const s = await mongoose.startSession();
await mongoose.model('Person').findOne({ name: 'Axl Rose' }).session(s);

```
 
### Query.prototype.set()


##### Parameters:


* `path` «String|Object» path or object of key/value pairs to set
* `[val]` «Any» the value to set


##### Returns:


* «Query» this



Adds a `$set` to this query's update without changing the operation. This is useful for query middleware so you can add an update regardless of whether you use `updateOne()`, `updateMany()`, `findOneAndUpdate()`, etc.

 ####   [Example:](#example)

 
```
// Updates `{ $set: { updatedAt: new Date() } }`
new Query().updateOne({}, {}).set('updatedAt', new Date());
new Query().updateMany({}, {}).set({ updatedAt: new Date() });

```
 
### Query.prototype.setOptions()


##### Parameters:


* `options` «Object»


##### Returns:


* «Query» this



Sets query options. Some options only make sense for certain operations.

 ####   [Options:](#options)

 The following options are only for `find()`:

 * [tailable](https://www.mongodb.com/docs/manual/core/tailable-cursors/)
* [limit](https://www.mongodb.com/docs/manual/reference/method/cursor.limit/)
* [skip](https://www.mongodb.com/docs/manual/reference/method/cursor.skip/)
* [allowDiskUse](https://www.mongodb.com/docs/manual/reference/method/cursor.allowDiskUse/)
* [batchSize](https://www.mongodb.com/docs/manual/reference/method/cursor.batchSize/)
* [readPreference](https://www.mongodb.com/docs/manual/applications/replication/#read-preference)
* [hint](https://www.mongodb.com/docs/manual/reference/method/cursor.hint/)
* [comment](https://www.mongodb.com/docs/manual/reference/method/cursor.comment/)

 The following options are only for write operations: `updateOne()`, `updateMany()`, `replaceOne()`, `findOneAndUpdate()`, and `findByIdAndUpdate()`:

 * [upsert](https://www.mongodb.com/docs/manual/reference/method/db.collection.update/)
* [writeConcern](https://www.mongodb.com/docs/manual/reference/method/db.collection.update/)
* [timestamps](../guide#timestamps): If `timestamps` is set in the schema, set this option to `false` to skip timestamps for that particular update. Has no effect if `timestamps` is not enabled in the schema options.
* overwriteDiscriminatorKey: allow setting the discriminator key in the update. Will use the correct discriminator schema if the update changes the discriminator key.

 The following options are only for `find()`, `findOne()`, `findById()`, `findOneAndUpdate()`, `findOneAndReplace()`, `findOneAndDelete()`, and `findByIdAndUpdate()`:

 * [lean](#Query.prototype.lean())
* [populate](../populate)
* [projection](#Query.prototype.projection())
* sanitizeProjection
* useBigInt64

 The following options are only for all operations **except** `updateOne()`, `updateMany()`, `deleteOne()`, and `deleteMany()`:

 * [maxTimeMS](https://www.mongodb.com/docs/manual/reference/operator/meta/maxTimeMS/)

 The following options are for `find()`, `findOne()`, `findOneAndUpdate()`, `findOneAndRemove()`, `findOneAndDelete()`, `updateOne()`, and `deleteOne()`:

 * [sort](https://www.mongodb.com/docs/manual/reference/method/cursor.sort/)

 The following options are for `findOneAndUpdate()` and `findOneAndRemove()`

 * rawResult

 The following options are for all operations:

 * [strict](../guide#strict)
* [collation](https://www.mongodb.com/docs/manual/reference/collation/)
* [session](https://www.mongodb.com/docs/manual/reference/server-sessions/)
* [explain](https://www.mongodb.com/docs/manual/reference/method/cursor.explain/)

 
### Query.prototype.setQuery()


##### Parameters:


* `new` «Object» query conditions


##### Returns:


* «undefined,void»



Sets the query conditions to the provided JSON object.

 ####   [Example:](#example)

 
```
const query = new Query();
query.find({ a: 1 })
query.setQuery({ a: 2 });
query.getQuery(); // { a: 2 }

```
 
### Query.prototype.setUpdate()


##### Parameters:


* `new` «Object» update operation


##### Returns:


* «undefined,void»



Sets the current update operation to new value.

 ####   [Example:](#example)

 
```
const query = new Query();
query.updateOne({}, { $set: { a: 5 } });
query.setUpdate({ $set: { b: 6 } });
query.getUpdate(); // { $set: { b: 6 } }

```
 
### Query.prototype.size()


##### Parameters:


* `[path]` «String»
* `val` «Number»


##### See:


* [$size](https://www.mongodb.com/docs/manual/reference/operator/size/)



Specifies a `$size` query condition.

 When called with one argument, the most recent path passed to `where()` is used.

 ####   [Example:](#example)

 
```
const docs = await MyModel.where('tags').size(0).exec();
assert(Array.isArray(docs));
console.log('documents with 0 tags', docs);

```
 
### Query.prototype.skip()


##### Parameters:


* `val` «Number»


##### See:


* [cursor.skip](https://www.mongodb.com/docs/manual/reference/method/cursor.skip/)



Specifies the number of documents to skip.

 ####   [Example:](#example)

 
```
query.skip(100).limit(20);

```
 ####   [Note:](#note)

 Cannot be used with `distinct()`

 
### Query.prototype.slice()


##### Parameters:


* `[path]` «String»
* `val` «Number|Array» number of elements to slice or array with number of elements to skip and number of elements to slice


##### Returns:


* «Query» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/tutorial/query-documents/#projection)
* [$slice](https://www.mongodb.com/docs/manual/reference/projection/slice/#prj._S_slice)



Specifies a `$slice` projection for an array.

 ####   [Example:](#example)

 
```
query.slice('comments', 5); // Returns the first 5 comments
query.slice('comments', -5); // Returns the last 5 comments
query.slice('comments', [10, 5]); // Returns the first 5 comments after the 10-th
query.where('comments').slice(5); // Returns the first 5 comments
query.where('comments').slice([-10, 5]); // Returns the first 5 comments after the 10-th to last

```
 **Note:** If the absolute value of the number of elements to be sliced is greater than the number of elements in the array, all array elements will be returned.

 
```
 // Given `arr`: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 query.slice('arr', 20); // Returns [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 query.slice('arr', -20); // Returns [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

```
 **Note:** If the number of elements to skip is positive and greater than the number of elements in the array, an empty array will be returned.

 
```
 // Given `arr`: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 query.slice('arr', [20, 5]); // Returns []

```
 **Note:** If the number of elements to skip is negative and its absolute value is greater than the number of elements in the array, the starting position is the start of the array.

 
```
 // Given `arr`: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 query.slice('arr', [-20, 5]); // Returns [1, 2, 3, 4, 5]

```
 
### Query.prototype.sort()


##### Parameters:


* `arg` «Object|String|Array<Array<string|number>>»


##### Returns:


* «Query» this


##### See:


* [cursor.sort](https://www.mongodb.com/docs/manual/reference/method/cursor.sort/)



Sets the sort order

 If an object is passed, values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.

 If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending.

 ####   [Example:](#example)

 
```
// sort by "field" ascending and "test" descending
query.sort({ field: 'asc', test: -1 });

// equivalent
query.sort('field -test');

// also possible is to use a array with array key-value pairs
query.sort([['field', 'asc']]);

```
 ####   [Note:](#note)

 Cannot be used with `distinct()`

 
### Query.prototype.tailable()


##### Parameters:


* `bool` «Boolean» defaults to true
* `[opts]` «Object» options to set
+ `[opts.awaitData]` «Boolean» false by default. Set to true to keep the cursor open even if there's no data.
+ `[opts.maxAwaitTimeMS]` «Number» the maximum amount of time for the server to wait on new documents to satisfy a tailable cursor query. Requires `tailable` and `awaitData` to be true


##### See:


* [tailable](https://www.mongodb.com/docs/manual/tutorial/create-tailable-cursor/)



Sets the tailable option (for use with capped collections).

 ####   [Example:](#example)

 
```
query.tailable(); // true
query.tailable(true);
query.tailable(false);

// Set both `tailable` and `awaitData` options
query.tailable({ awaitData: true });

```
 ####   [Note:](#note)

 Cannot be used with `distinct()`

 
### Query.prototype.then()


##### Parameters:


* `[resolve]` «Function»
* `[reject]` «Function»


##### Returns:


* «Promise»



Executes the query returning a `Promise` which will be resolved with either the doc(s) or rejected with the error.

 More about [`then()` in JavaScript](https://masteringjs.io/tutorials/fundamentals/then).

 
### Query.prototype.toConstructor()


##### Returns:


* «Query» subclass-of-Query



Converts this query to a customized, reusable query constructor with all arguments and options retained.

 ####   [Example:](#example)

 
```
// Create a query for adventure movies and read from the primary
// node in the replica-set unless it is down, in which case we'll
// read from a secondary node.
const query = Movie.find({ tags: 'adventure' }).read('primaryPreferred');

// create a custom Query constructor based off these settings
const Adventure = query.toConstructor();

// further narrow down our query results while still using the previous settings
await Adventure().where({ name: /^Life/ }).exec();

// since Adventure is a stand-alone constructor we can also add our own
// helper methods and getters without impacting global queries
Adventure.prototype.startsWith = function (prefix) {
  this.where({ name: new RegExp('^' + prefix) })
  return this;
}
Object.defineProperty(Adventure.prototype, 'highlyRated', {
  get: function () {
    this.where({ rating: { $gt: 4.5 }});
    return this;
  }
})
await Adventure().highlyRated.startsWith('Life').exec();

```
 
### Query.prototype.transform()


##### Parameters:


* `fn` «Function» function to run to transform the query result


##### Returns:


* «Query» this



Runs a function `fn` and treats the return value of `fn` as the new value for the query to resolve to.

 Any functions you pass to `transform()` will run **after** any post hooks.

 ####   [Example:](#example)

 
```
const res = await MyModel.findOne().transform(res => {
  // Sets a `loadedAt` property on the doc that tells you the time the
  // document was loaded.
  return res == null ?
    res :
    Object.assign(res, { loadedAt: new Date() });
});

```
 
### Query.prototype.updateMany()


##### Parameters:


* `[filter]` «Object»
* `[update]` «Object|Array» the update command
* `[options]` «Object»
+ `[options.multipleCastError]` «Boolean» by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.upsert=false]` «Boolean» if true, and no documents found, insert a new document
+ `[options.writeConcern=null]` «Object» sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](../guide#writeConcern)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.

* `[callback]` «Function» params are (error, writeOpResult)


##### Returns:


* «Query» this


##### See:


* [Model.update](model#Model.update())
* [Query docs](../queries)
* [update](https://www.mongodb.com/docs/manual/reference/method/db.collection.update/)
* [UpdateResult](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/UpdateResult.html)
* [MongoDB docs](https://www.mongodb.com/docs/manual/reference/command/update/#update-command-output)



Declare and/or execute this query as an updateMany() operation. MongoDB will update *all* documents that match `filter` (as opposed to just the first one).

 **Note** updateMany will *not* fire update middleware. Use `pre('updateMany')` and `post('updateMany')` instead.

 ####   [Example:](#example)

 
```
const res = await Person.updateMany({ name: /Stark$/ }, { isDeleted: true });
res.n; // Number of documents matched
res.nModified; // Number of documents modified

```
 This function triggers the following middleware.

 * `updateMany()`

 
### Query.prototype.updateOne()


##### Parameters:


* `[filter]` «Object»
* `[update]` «Object|Array» the update command
* `[options]` «Object»
+ `[options.multipleCastError]` «Boolean» by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.upsert=false]` «Boolean» if true, and no documents found, insert a new document
+ `[options.writeConcern=null]` «Object» sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](../guide#writeConcern)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ `[options.translateAliases=null]` «Boolean» If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.

* `[callback]` «Function» params are (error, writeOpResult)


##### Returns:


* «Query» this


##### See:


* [Model.update](model#Model.update())
* [Query docs](../queries)
* [update](https://www.mongodb.com/docs/manual/reference/method/db.collection.update/)
* [UpdateResult](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/UpdateResult.html)
* [MongoDB docs](https://www.mongodb.com/docs/manual/reference/command/update/#update-command-output)



Declare and/or execute this query as an updateOne() operation. MongoDB will update *only* the first document that matches `filter`.

 * Use `replaceOne()` if you want to overwrite an entire document rather than using [atomic operators](https://www.mongodb.com/docs/manual/tutorial/model-data-for-atomic-operations/#pattern) like `$set`.

 **Note** updateOne will *not* fire update middleware. Use `pre('updateOne')` and `post('updateOne')` instead.

 ####   [Example:](#example)

 
```
const res = await Person.updateOne({ name: 'Jean-Luc Picard' }, { ship: 'USS Enterprise' });
res.acknowledged; // Indicates if this write result was acknowledged. If not, then all other members of this result will be undefined.
res.matchedCount; // Number of documents that matched the filter
res.modifiedCount; // Number of documents that were modified
res.upsertedCount; // Number of documents that were upserted
res.upsertedId; // Identifier of the inserted document (if an upsert took place)

```
 This function triggers the following middleware.

 * `updateOne()`

 
### Query.prototype.w()


##### Parameters:


* `val` «String|number» 0 for fire-and-forget, 1 for acknowledged by one server, 'majority' for majority of the replica set, or [any of the more advanced options](https://www.mongodb.com/docs/manual/reference/write-concern/#w-option).


##### Returns:


* «Query» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/write-concern/#w-option)



Sets the specified number of `mongod` servers, or tag set of `mongod` servers, that must acknowledge this write before this write is considered successful. This option is only valid for operations that write to the database:

 * `deleteOne()`
* `deleteMany()`
* `findOneAndDelete()`
* `findOneAndReplace()`
* `findOneAndUpdate()`
* `updateOne()`
* `updateMany()`

 Defaults to the schema's [`writeConcern.w` option](../guide#writeConcern)

 ####   [Example:](#example)

 
```
// The 'majority' option means the `deleteOne()` promise won't resolve
// until the `deleteOne()` has propagated to the majority of the replica set
await mongoose.model('Person').
  deleteOne({ name: 'Ned Stark' }).
  w('majority');

```
 
### Query.prototype.where()


##### Parameters:


* `[path]` «String|Object»
* `[val]` «any»


##### Returns:


* «Query» this



Specifies a `path` for use with chaining.

 ####   [Example:](#example)

 
```
// instead of writing:
User.find({age: {$gte: 21, $lte: 65}});

// we can instead write:
User.where('age').gte(21).lte(65);

// passing query conditions is permitted
User.find().where({ name: 'vonderful' })

// chaining
User
.where('age').gte(21).lte(65)
.where('name', /^vonderful/i)
.where('friends').slice(10)
.exec()

```
 
### Query.prototype.within()


##### Returns:


* «Query» this


##### See:


* [$polygon](https://www.mongodb.com/docs/manual/reference/operator/polygon/)
* [$box](https://www.mongodb.com/docs/manual/reference/operator/box/)
* [$geometry](https://www.mongodb.com/docs/manual/reference/operator/geometry/)
* [$center](https://www.mongodb.com/docs/manual/reference/operator/center/)
* [$centerSphere](https://www.mongodb.com/docs/manual/reference/operator/centerSphere/)



Defines a `$within` or `$geoWithin` argument for geo-spatial queries.

 ####   [Example:](#example)

 
```
query.where(path).within().box()
query.where(path).within().circle()
query.where(path).within().geometry()

query.where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true });
query.where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] });
query.where('loc').within({ polygon: [[],[],[],[]] });

query.where('loc').within([], [], []) // polygon
query.where('loc').within([], []) // box
query.where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry

```
 **MUST** be used after `where()`.

 ####   [Note:](#note)

 As of Mongoose 3.7, `$geoWithin` is always used for queries. To change this behavior, see [Query.use$geoWithin](#Query.prototype.use$geoWithin).

 ####   [Note:](#note-1)

 In Mongoose 3.7, `within` changed from a getter to a function. If you need the old syntax, use [this](https://github.com/ebensing/mongoose-within).

 
### Query.prototype.writeConcern()


##### Parameters:


* `writeConcern` «Object» the write concern value to set


##### Returns:


* «Query» this


##### See:


* [WriteConcernSettings](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/WriteConcernSettings.html)



Sets the 3 write concern parameters for this query:

 * `w`: Sets the specified number of `mongod` servers, or tag set of `mongod` servers, that must acknowledge this write before this write is considered successful.
* `j`: Boolean, set to `true` to request acknowledgement that this operation has been persisted to MongoDB's on-disk journal.
* `wtimeout`: If [`w > 1`](#Query.prototype.w()), the maximum amount of time to wait for this write to propagate through the replica set before this operation fails. The default is `0`, which means no timeout.

 This option is only valid for operations that write to the database:

 * `deleteOne()`
* `deleteMany()`
* `findOneAndDelete()`
* `findOneAndReplace()`
* `findOneAndUpdate()`
* `updateOne()`
* `updateMany()`

 Defaults to the schema's [`writeConcern` option](../guide#writeConcern)

 ####   [Example:](#example)

 
```
// The 'majority' option means the `deleteOne()` promise won't resolve
// until the `deleteOne()` has propagated to the majority of the replica set
await mongoose.model('Person').
  deleteOne({ name: 'Ned Stark' }).
  writeConcern({ w: 'majority' });

```
 
### Query.prototype.wtimeout()


##### Parameters:


* `ms` «number» number of milliseconds to wait


##### Returns:


* «Query» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout)



If [`w > 1`](#Query.prototype.w()), the maximum amount of time to wait for this write to propagate through the replica set before this operation fails. The default is `0`, which means no timeout.

 This option is only valid for operations that write to the database:

 * `deleteOne()`
* `deleteMany()`
* `findOneAndDelete()`
* `findOneAndReplace()`
* `findOneAndUpdate()`
* `updateOne()`
* `updateMany()`

 Defaults to the schema's [`writeConcern.wtimeout` option](../guide#writeConcern)

 ####   [Example:](#example)

 
```
// The `deleteOne()` promise won't resolve until this `deleteOne()` has
// propagated to at least `w = 2` members of the replica set. If it takes
// longer than 1 second, this `deleteOne()` will fail.
await mongoose.model('Person').
  deleteOne({ name: 'Ned Stark' }).
  w(2).
  wtimeout(1000);

```
 
### Query.prototype[Symbol.asyncIterator]()



Returns an asyncIterator for use with [`for/await/of` loops](https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js) This function *only* works for `find()` queries. You do not need to call this function explicitly, the JavaScript runtime will call it for you.

 ####   [Example:](#example)

 
```
for await (const doc of Model.aggregate([{ $sort: { name: 1 } }])) {
  console.log(doc.name);
}

```
 Node.js 10.x supports async iterators natively without any flags. You can enable async iterators in Node.js 8.x using the [`--harmony_async_iteration` flag](https://github.com/tc39/proposal-async-iteration/issues/117#issuecomment-346695187).

 **Note:** This function is not if `Symbol.asyncIterator` is undefined. If `Symbol.asyncIterator` is undefined, that means your Node.js version does not support async iterators.

 
### Query.prototype[Symbol.toStringTag]()


##### Returns:


* «String»



Returns a string representation of this query.

 More about [`toString()` in JavaScript](https://masteringjs.io/tutorials/fundamentals/tostring).

 ####   [Example:](#example)

 
```
const q = Model.find();
console.log(q); // Prints "Query { find }"

```
 
### Query.use$geoWithin


##### Type:


* «property»


##### See:


* [geoWithin](https://www.mongodb.com/docs/manual/reference/operator/geoWithin/)



Flag to opt out of using `$geoWithin`.

 
```
mongoose.Query.use$geoWithin = false;

```
 MongoDB 2.4 deprecated the use of `$within`, replacing it with `$geoWithin`. Mongoose uses `$geoWithin` by default (which is 100% backward compatible with `$within`). If you are running an older version of MongoDB, set this flag to `false` so your `within()` queries continue to work.

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/query.html>

Aggregate
=========



### Aggregate()


##### Parameters:


* `[pipeline]` «Array» aggregation pipeline as an array of objects
* `[model]` «Model» the model to use with this aggregate.


##### See:


* [MongoDB](https://www.mongodb.com/docs/manual/applications/aggregation/)
* [driver](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#aggregate)



Aggregate constructor used for building aggregation pipelines. Do not instantiate this class directly, use [Model.aggregate()](model#Model.aggregate()) instead.

 ####   [Example:](#example)

 
```
const aggregate = Model.aggregate([
  { $project: { a: 1, b: 1 } },
  { $skip: 5 }
]);

Model.
  aggregate([{ $match: { age: { $gte: 21 }}}]).
  unwind('tags').
  exec();

```
 ####   [Note:](#note)

 * The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned).
* Mongoose does **not** cast pipeline stages. The below will **not** work unless `_id` is a string in the database

  new Aggregate([{ $match: { \_id: '00000000000000000000000a' } }]); // Do this instead to cast to an ObjectId new Aggregate([{ $match: { \_id: new mongoose.Types.ObjectId('00000000000000000000000a') } }]);

 
### Aggregate.prototype.addFields()


##### Parameters:


* `arg` «Object» field specification


##### Returns:


* «Aggregate»


##### See:


* [$addFields](https://www.mongodb.com/docs/manual/reference/operator/aggregation/addFields/)



Appends a new $addFields operator to this aggregate pipeline. Requires MongoDB v3.4+ to work

 ####   [Example:](#example)

 
```
// adding new fields based on existing fields
aggregate.addFields({
    newField: '$b.nested'
  , plusTen: { $add: ['$val', 10]}
  , sub: {
       name: '$a'
    }
})

// etc
aggregate.addFields({ salary\_k: { $divide: [ "$salary", 1000 ] } });

```
 
### Aggregate.prototype.allowDiskUse()


##### Parameters:


* `value` «Boolean» Should tell server it can use hard drive to store data during aggregation.


##### Returns:


* «Aggregate» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/command/aggregate/)



Sets the allowDiskUse option for the aggregation query

 ####   [Example:](#example)

 
```
await Model.aggregate([{ $match: { foo: 'bar' } }]).allowDiskUse(true);

```
 
### Aggregate.prototype.append()


##### Parameters:


* `...ops` «Object|Array[Object]» operator(s) to append. Can either be a spread of objects or a single parameter of a object array.


##### Returns:


* «Aggregate»



Appends new operators to this aggregate pipeline

 ####   [Example:](#example)

 
```
aggregate.append({ $project: { field: 1 }}, { $limit: 2 });

// or pass an array
const pipeline = [{ $match: { daw: 'Logic Audio X' }} ];
aggregate.append(pipeline);

```
 
### Aggregate.prototype.catch()


##### Parameters:


* `[reject]` «Function»


##### Returns:


* «Promise»



Executes the aggregation returning a `Promise` which will be resolved with either the doc(s) or rejected with the error. Like [`.then()`](query#Query.prototype.then), but only takes a rejection handler. Compatible with `await`.

 
### Aggregate.prototype.collation()


##### Parameters:


* `collation` «Object» options


##### Returns:


* «Aggregate» this


##### See:


* [mongodb](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/CollationOptions.html)



Adds a collation

 ####   [Example:](#example)

 
```
const res = await Model.aggregate(pipeline).collation({ locale: 'en\_US', strength: 1 });

```
 
### Aggregate.prototype.count()


##### Parameters:


* `fieldName` «String» The name of the output field which has the count as its value. It must be a non-empty string, must not start with $ and must not contain the . character.


##### Returns:


* «Aggregate»


##### See:


* [$count](https://www.mongodb.com/docs/manual/reference/operator/aggregation/count)



Appends a new $count operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
aggregate.count("userCount");

```
 
### Aggregate.prototype.cursor()


##### Parameters:


* `options` «Object»
+ `[options.batchSize]` «Number» set the cursor batch size
+ `[options.useMongooseAggCursor]` «Boolean» use experimental mongoose-specific aggregation cursor (for `eachAsync()` and other query cursor semantics)


##### Returns:


* «AggregationCursor» cursor representing this aggregation


##### See:


* [mongodb](https://mongodb.github.io/node-mongodb-native/4.9/classes/AggregationCursor.html)



Sets the `cursor` option and executes this aggregation, returning an aggregation cursor. Cursors are useful if you want to process the results of the aggregation one-at-a-time because the aggregation result is too big to fit into memory.

 ####   [Example:](#example)

 
```
const cursor = Model.aggregate(..).cursor({ batchSize: 1000 });
cursor.eachAsync(function(doc, i) {
  // use doc
});

```
 
### Aggregate.prototype.densify()


##### Parameters:


* `arg` «Object» $densify operator contents


##### Returns:


* «Aggregate»


##### See:


* [$densify](https://www.mongodb.com/docs/manual/reference/operator/aggregation/densify/)



Appends a new $densify operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
 aggregate.densify({
   field: 'timestamp',
   range: {
     step: 1,
     unit: 'hour',
     bounds: [new Date('2021-05-18T00:00:00.000Z'), new Date('2021-05-18T08:00:00.000Z')]
   }
 });

```
 
### Aggregate.prototype.exec()


##### Returns:


* «Promise»



Executes the aggregate pipeline on the currently bound Model.

 ####   [Example:](#example)

 
```
const result = await aggregate.exec();

```
 
### Aggregate.prototype.explain()


##### Parameters:


* `[verbosity]` «String»


##### Returns:


* «Promise»



Execute the aggregation with explain

 ####   [Example:](#example)

 
```
Model.aggregate(..).explain()

```
 
### Aggregate.prototype.facet()


##### Parameters:


* `facet` «Object» options


##### Returns:


* «Aggregate» this


##### See:


* [$facet](https://www.mongodb.com/docs/manual/reference/operator/aggregation/facet/)



Combines multiple aggregation pipelines.

 ####   [Example:](#example)

 
```
const res = await Model.aggregate().facet({
  books: [{ groupBy: '$author' }],
  price: [{ $bucketAuto: { groupBy: '$price', buckets: 2 } }]
});

// Output: { books: [...], price: [{...}, {...}] }

```
 
### Aggregate.prototype.fill()


##### Parameters:


* `arg` «Object» $fill operator contents


##### Returns:


* «Aggregate»


##### See:


* [$fill](https://www.mongodb.com/docs/manual/reference/operator/aggregation/fill/)



Appends a new $fill operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
 aggregate.fill({
   output: {
     bootsSold: { value: 0 },
     sandalsSold: { value: 0 },
     sneakersSold: { value: 0 }
   }
 });

```
 
### Aggregate.prototype.finally()


##### Parameters:


* `[onFinally]` «Function»


##### Returns:


* «Promise»



Executes the aggregate returning a `Promise` which will be resolved with `.finally()` chained.

 More about [Promise `finally()` in JavaScript](https://thecodebarbarian.com/using-promise-finally-in-node-js.html).

 
### Aggregate.prototype.graphLookup()


##### Parameters:


* `options` «Object» to $graphLookup as described in the above link


##### Returns:


* «Aggregate»


##### See:


* [$graphLookup](https://www.mongodb.com/docs/manual/reference/operator/aggregation/graphLookup/#pipe._S_graphLookup)



Appends new custom $graphLookup operator(s) to this aggregate pipeline, performing a recursive search on a collection.

 Note that graphLookup can only consume at most 100MB of memory, and does not allow disk use even if `{ allowDiskUse: true }` is specified.

 ####   [Example:](#example)

 
```
 // Suppose we have a collection of courses, where a document might look like `{ \_id: 0, name: 'Calculus', prerequisite: 'Trigonometry'}` and `{ \_id: 0, name: 'Trigonometry', prerequisite: 'Algebra' }`
 aggregate.graphLookup({ from: 'courses', startWith: '$prerequisite', connectFromField: 'prerequisite', connectToField: 'name', as: 'prerequisites', maxDepth: 3 }) // this will recursively search the 'courses' collection up to 3 prerequisites

```
 
### Aggregate.prototype.group()


##### Parameters:


* `arg` «Object» $group operator contents


##### Returns:


* «Aggregate»


##### See:


* [$group](https://www.mongodb.com/docs/manual/reference/aggregation/group/)



Appends a new custom $group operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
aggregate.group({ \_id: "$department" });

```
 
### Aggregate.prototype.hint()


##### Parameters:


* `value` «Object|String» a hint object or the index name


##### Returns:


* «Aggregate» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/command/aggregate/)



Sets the hint option for the aggregation query

 ####   [Example:](#example)

 
```
Model.aggregate(..).hint({ qty: 1, category: 1 }).exec();

```
 
### Aggregate.prototype.limit()


##### Parameters:


* `num` «Number» maximum number of records to pass to the next stage


##### Returns:


* «Aggregate»


##### See:


* [$limit](https://www.mongodb.com/docs/manual/reference/aggregation/limit/)



Appends a new $limit operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
aggregate.limit(10);

```
 
### Aggregate.prototype.lookup()


##### Parameters:


* `options` «Object» to $lookup as described in the above link


##### Returns:


* «Aggregate»


##### See:


* [$lookup](https://www.mongodb.com/docs/manual/reference/operator/aggregation/lookup/#pipe._S_lookup)



Appends new custom $lookup operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
aggregate.lookup({ from: 'users', localField: 'userId', foreignField: '\_id', as: 'users' });

```
 
### Aggregate.prototype.match()


##### Parameters:


* `arg` «Object» $match operator contents


##### Returns:


* «Aggregate»


##### See:


* [$match](https://www.mongodb.com/docs/manual/reference/aggregation/match/)



Appends a new custom $match operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
aggregate.match({ department: { $in: [ "sales", "engineering" ] } });

```
 
### Aggregate.prototype.model()


##### Parameters:


* `[model]` «Model» Set the model associated with this aggregate. If not provided, returns the already stored model.


##### Returns:


* «Model»



Get/set the model that this aggregation will execute on.

 ####   [Example:](#example)

 
```
const aggregate = MyModel.aggregate([{ $match: { answer: 42 } }]);
aggregate.model() === MyModel; // true

// Change the model. There's rarely any reason to do this.
aggregate.model(SomeOtherModel);
aggregate.model() === SomeOtherModel; // true

```
 
### Aggregate.prototype.near()


##### Parameters:


* `arg` «Object»


##### Returns:


* «Aggregate»


##### See:


* [$geoNear](https://www.mongodb.com/docs/manual/reference/aggregation/geoNear/)



Appends a new $geoNear operator to this aggregate pipeline.

 ####   [Note:](#note)

 **MUST** be used as the first operator in the pipeline.

 ####   [Example:](#example)

 
```
aggregate.near({
  near: { type: 'Point', coordinates: [40.724, -73.997] },
  distanceField: "dist.calculated", // required
  maxDistance: 0.008,
  query: { type: "public" },
  includeLocs: "dist.location",
  spherical: true,
});

```
 
### Aggregate.prototype.option()


##### Parameters:


* `options` «Object» keys to merge into current options
+ `[options.maxTimeMS]` «Number» number limits the time this aggregation will run, see [MongoDB docs on `maxTimeMS`](https://www.mongodb.com/docs/manual/reference/operator/meta/maxTimeMS/)
+ `[options.allowDiskUse]` «Boolean» boolean if true, the MongoDB server will use the hard drive to store data during this aggregation
+ `[options.collation]` «Object» object see [`Aggregate.prototype.collation()`](#Aggregate.prototype.collation())
+ `[options.session]` «ClientSession» ClientSession see [`Aggregate.prototype.session()`](#Aggregate.prototype.session())


##### Returns:


* «Aggregate» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/command/aggregate/)



Lets you set arbitrary options, for middleware or plugins.

 ####   [Example:](#example)

 
```
const agg = Model.aggregate(..).option({ allowDiskUse: true }); // Set the `allowDiskUse` option
agg.options; // `{ allowDiskUse: true }`

```
 
### Aggregate.prototype.options


##### Type:


* «property»



Contains options passed down to the [aggregate command](https://www.mongodb.com/docs/manual/reference/command/aggregate/). Supported options are:

 * [`allowDiskUse`](#Aggregate.prototype.allowDiskUse())
* `bypassDocumentValidation`
* [`collation`](#Aggregate.prototype.collation())
* `comment`
* [`cursor`](#Aggregate.prototype.cursor())
* [`explain`](#Aggregate.prototype.explain())
* `fieldsAsRaw`
* [`hint`](#Aggregate.prototype.hint())
* `let`
* `maxTimeMS`
* `raw`
* [`readConcern`](#Aggregate.prototype.readConcern())
* `readPreference`
* [`session`](#Aggregate.prototype.session())
* `writeConcern`

 
### Aggregate.prototype.pipeline()


##### Returns:


* «Array» The current pipeline similar to the operation that will be executed



Returns the current pipeline

 ####   [Example:](#example)

 
```
MyModel.aggregate().match({ test: 1 }).pipeline(); // [{ $match: { test: 1 } }]

```
 
### Aggregate.prototype.project()


##### Parameters:


* `arg` «Object|String» field specification


##### Returns:


* «Aggregate»


##### See:


* [projection](https://www.mongodb.com/docs/manual/reference/aggregation/project/)



Appends a new $project operator to this aggregate pipeline.

 Mongoose query [selection syntax](query#Query.prototype.select()) is also supported.

 ####   [Example:](#example)

 
```
// include a, include b, exclude \_id
aggregate.project("a b -\_id");

// or you may use object notation, useful when
// you have keys already prefixed with a "-"
aggregate.project({a: 1, b: 1, \_id: 0});

// reshaping documents
aggregate.project({
    newField: '$b.nested'
  , plusTen: { $add: ['$val', 10]}
  , sub: {
       name: '$a'
    }
})

// etc
aggregate.project({ salary\_k: { $divide: [ "$salary", 1000 ] } });

```
 
### Aggregate.prototype.read()


##### Parameters:


* `pref` «String|ReadPreference» one of the listed preference options or their aliases
* `[tags]` «Array» optional tags for this query. DEPRECATED


##### Returns:


* «Aggregate» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/applications/replication/#read-preference)



Sets the readPreference option for the aggregation query.

 ####   [Example:](#example)

 
```
await Model.aggregate(pipeline).read('primaryPreferred');

```
 
### Aggregate.prototype.readConcern()


##### Parameters:


* `level` «String» one of the listed read concern level or their aliases


##### Returns:


* «Aggregate» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/read-concern/)



Sets the readConcern level for the aggregation query.

 ####   [Example:](#example)

 
```
await Model.aggregate(pipeline).readConcern('majority');

```
 
### Aggregate.prototype.redact()


##### Parameters:


* `expression` «Object» redact options or conditional expression
* `[thenExpr]` «String|Object» true case for the condition
* `[elseExpr]` «String|Object» false case for the condition


##### Returns:


* «Aggregate» this


##### See:


* [$redact](https://www.mongodb.com/docs/manual/reference/operator/aggregation/redact/)



Appends a new $redact operator to this aggregate pipeline.

 If 3 arguments are supplied, Mongoose will wrap them with if-then-else of $cond operator respectively If `thenExpr` or `elseExpr` is string, make sure it starts with $$, like `$$DESCEND`, `$$PRUNE` or `$$KEEP`.

 ####   [Example:](#example)

 
```
await Model.aggregate(pipeline).redact({
  $cond: {
    if: { $eq: [ '$level', 5 ] },
    then: '$$PRUNE',
    else: '$$DESCEND'
  }
});

// $redact often comes with $cond operator, you can also use the following syntax provided by mongoose
await Model.aggregate(pipeline).redact({ $eq: [ '$level', 5 ] }, '$$PRUNE', '$$DESCEND');

```
 
### Aggregate.prototype.replaceRoot()


##### Parameters:


* `newRoot` «String|Object» the field or document which will become the new root document


##### Returns:


* «Aggregate»


##### See:


* [$replaceRoot](https://www.mongodb.com/docs/manual/reference/operator/aggregation/replaceRoot)



Appends a new $replaceRoot operator to this aggregate pipeline.

 Note that the `$replaceRoot` operator requires field strings to start with '$'. If you are passing in a string Mongoose will prepend '$' if the specified field doesn't start '$'. If you are passing in an object the strings in your expression will not be altered.

 ####   [Example:](#example)

 
```
aggregate.replaceRoot("user");

aggregate.replaceRoot({ x: { $concat: ['$this', '$that'] } });

```
 
### Aggregate.prototype.sample()


##### Parameters:


* `size` «Number» number of random documents to pick


##### Returns:


* «Aggregate»


##### See:


* [$sample](https://www.mongodb.com/docs/manual/reference/operator/aggregation/sample/#pipe._S_sample)



Appends new custom $sample operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
aggregate.sample(3); // Add a pipeline that picks 3 random documents

```
 
### Aggregate.prototype.search()


##### Parameters:


* `$search` «Object» options


##### Returns:


* «Aggregate» this


##### See:


* [$search](https://www.mongodb.com/docs/atlas/atlas-search/tutorial/)



Helper for [Atlas Text Search](https://www.mongodb.com/docs/atlas/atlas-search/tutorial/)'s `$search` stage.

 ####   [Example:](#example)

 
```
const res = await Model.aggregate().
 search({
   text: {
     query: 'baseball',
     path: 'plot'
   }
 });

// Output: [{ plot: '...', title: '...' }]

```
 
### Aggregate.prototype.session()


##### Parameters:


* `session` «ClientSession»


##### Returns:


* «Aggregate» this


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/command/aggregate/)



Sets the session for this aggregation. Useful for [transactions](../transactions).

 ####   [Example:](#example)

 
```
const session = await Model.startSession();
await Model.aggregate(..).session(session);

```
 
### Aggregate.prototype.skip()


##### Parameters:


* `num` «Number» number of records to skip before next stage


##### Returns:


* «Aggregate»


##### See:


* [$skip](https://www.mongodb.com/docs/manual/reference/aggregation/skip/)



Appends a new $skip operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
aggregate.skip(10);

```
 
### Aggregate.prototype.sort()


##### Parameters:


* `arg` «Object|String»


##### Returns:


* «Aggregate» this


##### See:


* [$sort](https://www.mongodb.com/docs/manual/reference/aggregation/sort/)



Appends a new $sort operator to this aggregate pipeline.

 If an object is passed, values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.

 If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending.

 ####   [Example:](#example)

 
```
// these are equivalent
aggregate.sort({ field: 'asc', test: -1 });
aggregate.sort('field -test');

```
 
### Aggregate.prototype.sortByCount()


##### Parameters:


* `arg` «Object|String»


##### Returns:


* «Aggregate» this


##### See:


* [$sortByCount](https://www.mongodb.com/docs/manual/reference/operator/aggregation/sortByCount/)



Appends a new $sortByCount operator to this aggregate pipeline. Accepts either a string field name or a pipeline object.

 Note that the `$sortByCount` operator requires the new root to start with '$'. Mongoose will prepend '$' if the specified field name doesn't start with '$'.

 ####   [Example:](#example)

 
```
aggregate.sortByCount('users');
aggregate.sortByCount({ $mergeObjects: [ "$employee", "$business" ] })

```
 
### Aggregate.prototype.then()


##### Parameters:


* `[resolve]` «Function» successCallback
* `[reject]` «Function» errorCallback


##### Returns:


* «Promise»



Provides a Promise-like `then` function, which will call `.exec` without a callback Compatible with `await`.

 ####   [Example:](#example)

 
```
Model.aggregate(..).then(successCallback, errorCallback);

```
 
### Aggregate.prototype.unionWith()


##### Parameters:


* `options` «Object» to $unionWith query as described in the above link


##### Returns:


* «Aggregate»


##### See:


* [$unionWith](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unionWith)



Appends new $unionWith operator to this aggregate pipeline.

 ####   [Example:](#example)

 
```
aggregate.unionWith({ coll: 'users', pipeline: [ { $match: { \_id: 1 } } ] });

```
 
### Aggregate.prototype.unwind()


##### Parameters:


* `fields` «String|Object|Array[String]|Array[Object]» the field(s) to unwind, either as field names or as [objects with options](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind/#document-operand-with-options). If passing a string, prefixing the field name with '$' is optional. If passing an object, `path` must start with '$'.


##### Returns:


* «Aggregate»


##### See:


* [$unwind](https://www.mongodb.com/docs/manual/reference/aggregation/unwind/)



Appends new custom $unwind operator(s) to this aggregate pipeline.

 Note that the `$unwind` operator requires the path name to start with '$'. Mongoose will prepend '$' if the specified field doesn't start '$'.

 ####   [Example:](#example)

 
```
aggregate.unwind("tags");
aggregate.unwind("a", "b", "c");
aggregate.unwind({ path: '$tags', preserveNullAndEmptyArrays: true });

```
 
### Aggregate.prototype[Symbol.asyncIterator]()



Returns an asyncIterator for use with [`for/await/of` loops](https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js) You do not need to call this function explicitly, the JavaScript runtime will call it for you.

 ####   [Example:](#example)

 
```
const agg = Model.aggregate([{ $match: { age: { $gte: 25 } } }]);
for await (const doc of agg) {
  console.log(doc.name);
}

```
 Node.js 10.x supports async iterators natively without any flags. You can enable async iterators in Node.js 8.x using the [`--harmony_async_iteration` flag](https://github.com/tc39/proposal-async-iteration/issues/117#issuecomment-346695187).

 **Note:** This function is not set if `Symbol.asyncIterator` is undefined. If `Symbol.asyncIterator` is undefined, that means your Node.js version does not support async iterators.

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/aggregate.html>

Populate
=========

 MongoDB has the join-like [$lookup](https://www.mongodb.com/docs/manual/reference/operator/aggregation/lookup/) aggregation operator in versions >= 3.2. Mongoose has a more powerful alternative called `populate()`, which lets you reference documents in other collections.

 Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). We may populate a single document, multiple documents, a plain object, multiple plain objects, or all objects returned from a query. Let's look at some examples.

 
```
const mongoose = require('mongoose');
const { Schema } = mongoose;

const personSchema = Schema({
  \_id: Schema.Types.ObjectId,
  name: String,
  age: Number,
  stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

const storySchema = Schema({
  author: { type: Schema.Types.ObjectId, ref: 'Person' },
  title: String,
  fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});

const Story = mongoose.model('Story', storySchema);
const Person = mongoose.model('Person', personSchema);

```
 So far we've created two [Models](models). Our `Person` model has its `stories` field set to an array of `ObjectId`s. The `ref` option is what tells Mongoose which model to use during population, in our case the `Story` model. All `_id`s we store here must be document `_id`s from the `Story` model.

 Saving refs
-----------

 Saving refs to other documents works the same way you normally save properties, just assign the `_id` value:

 
```
const author = new Person({
  \_id: new mongoose.Types.ObjectId(),
  name: 'Ian Fleming',
  age: 50
});

await author.save();

const story1 = new Story({
  title: 'Casino Royale',
  author: author.\_id // assign the \_id from the person
});

await story1.save();
// that's it!

```
 You can set the `ref` option on `ObjectId`, `Number`, `String`, and `Buffer` paths. `populate()` works with ObjectIds, numbers, strings, and buffers. 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
----------

 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 `author` using the query builder:

 
```
const story = await Story.
  findOne({ title: 'Casino Royale' }).
  populate('author').
  exec();
// prints "The author is Ian Fleming"
console.log('The author is %s', story.author.name);

```
 Populated paths are no longer set to their original `_id` , their value is replaced with the mongoose document returned from the database by performing a separate query before returning the results.

 Arrays of refs work the same way. Just call the [populate](api/query#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
------------------------

 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.

 
```
const story = await Story.findOne({ title: 'Casino Royale' });
story.author = author;
console.log(story.author.name); // prints "Ian Fleming"

```
 Checking Whether a Field is 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), you can assume the field is populated.

 
```
story.populated('author'); // truthy

story.depopulate('author'); // Make `author` not populated anymore
story.populated('author'); // undefined

```
 A common reason for checking whether a path is populated is getting the `author` id. However, for your convenience, Mongoose adds a [`_id` getter to ObjectId instances](api/mongoose#mongoose_Mongoose-set) so you can use `story.author._id` regardless of whether `author` is populated.

 
```
story.populated('author'); // truthy
story.author.\_id; // ObjectId

story.depopulate('author'); // Make `author` not populated anymore
story.populated('author'); // undefined

story.author instanceof ObjectId; // true
story.author.\_id; // ObjectId, because Mongoose adds a special getter

```
 What If There's No Foreign Document?
------------------------------------

 Mongoose populate doesn't behave like conventional [SQL joins](https://www.w3schools.com/sql/sql_join.asp). When there's no document, `story.author` will be `null`. This is analogous to a [left join](https://www.w3schools.com/sql/sql_join_left.asp) in SQL.

 
```
await Person.deleteMany({ name: 'Ian Fleming' });

const story = await Story.findOne({ title: 'Casino Royale' }).populate('author');
story.author; // `null`

```
 If you have an array of `authors` in your `storySchema`, `populate()` will give you an empty array instead.

 
```
const storySchema = Schema({
  authors: [{ type: Schema.Types.ObjectId, ref: 'Person' }],
  title: String
});

// Later

const story = await Story.findOne({ title: 'Casino Royale' }).populate('authors');
story.authors; // `[]`

```
 Field Selection
---------------

 What if we only want a few specific fields returned for the populated documents? This can be accomplished by passing the usual [field name syntax](api/query#query_Query-select) as the second argument to the populate method:

 
```
const story = await Story.
  findOne({ title: /casino royale/i }).
  populate('author', 'name').
  exec(); // only return the Persons name
// prints "The author is Ian Fleming"
console.log('The author is %s', story.author.name);
// prints "The authors age is null"
console.log('The authors age is %s', story.author.age);

```
 Populating Multiple Paths
-------------------------

 What if we wanted to populate multiple paths at the same time?

 
```
await Story.
  find({ /\* ... \*/ }).
  populate('fans').
  populate('author').
  exec();

```
 If you call `populate()` multiple times with the same path, only the last one will take effect.

 
```
// The 2nd `populate()` call below overwrites the first because they
// both populate 'fans'.
await Story.
  find().
  populate({ path: 'fans', select: 'name' }).
  populate({ path: 'fans', select: 'email' });
// The above is equivalent to:
await Story.find().populate({ path: 'fans', select: 'email' });

```
 Query conditions and other options
----------------------------------

 What if we wanted to populate our fans array based on their age and select just their names?

 
```
await Story.
  find().
  populate({
    path: 'fans',
    match: { age: { $gte: 21 } },
    // Explicitly exclude `\_id`, see http://bit.ly/2aEfTdB
    select: 'name -\_id'
  }).
  exec();

```
 The `match` option doesn't filter out `Story` documents. If there are no documents that satisfy `match`, you'll get a `Story` document with an empty `fans` array.

 For example, suppose you `populate()` a story's `author` and the `author` doesn't satisfy `match`. Then the story's `author` will be `null`.

 
```
const story = await Story.
  findOne({ title: 'Casino Royale' }).
  populate({ path: 'author', name: { $ne: 'Ian Fleming' } }).
  exec();
story.author; // `null`

```
 In general, there is no way to make `populate()` filter stories based on properties of the story's `author`. For example, the below query won't return any results, even though `author` is populated.

 
```
const story = await Story.
  findOne({ 'author.name': 'Ian Fleming' }).
  populate('author').
  exec();
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`
-------------------------------

 Populate does support a `limit` option, however, it currently does **not** limit on a per-document basis for backwards compatibility. For example, suppose you have 2 stories:

 
```
await Story.create([
  { title: 'Casino Royale', fans: [1, 2, 3, 4, 5, 6, 7, 8] },
  { title: 'Live and Let Die', fans: [9, 10] }
]);

```
 If you were to `populate()` using the `limit` option, you would find that the 2nd story has 0 fans:

 
```
const stories = await Story.find().populate({
  path: 'fans',
  options: { limit: 2 }
});

stories[0].name; // 'Casino Royale'
stories[0].fans.length; // 2

// 2nd story has 0 fans!
stories[1].name; // 'Live and Let Die'
stories[1].fans.length; // 0

```
 That's because, in order to avoid executing a separate query for each document, Mongoose instead queries for fans using `numDocuments * limit` as the limit. If you need the correct `limit`, you should use the `perDocumentLimit` option (new in Mongoose 5.9.0). Just keep in mind that `populate()` will execute a separate query for each story, which may cause `populate()` to be slower.

 
```
const stories = await Story.find().populate({
  path: 'fans',
  // Special option that tells Mongoose to execute a separate query
  // for each `story` to make sure we get 2 fans for each story.
  perDocumentLimit: 2
});

stories[0].name; // 'Casino Royale'
stories[0].fans.length; // 2

stories[1].name; // 'Live and Let Die'
stories[1].fans.length; // 2

```
 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' onto `author.stories`.

 There are two perspectives here. First, you may want the `author` to know which stories are theirs. Usually, your schema should resolve one-to-many relationships by having a parent pointer in the 'many' side. But, if you have a good reason to want an array of child pointers, you can `push()` documents onto the array as shown below.

 
```
await story1.save();

author.stories.push(story1);
await author.save();

```
 This allows us to perform a `find` and `populate` combo:

 
```
const person = await Person.
  findOne({ name: 'Ian Fleming' }).
  populate('stories').
  exec(); // only works if we pushed refs to children
console.log(person);

```
 It is debatable that we really want two sets of pointers as they may get out of sync. Instead we could skip populating and directly `find()` the stories we are interested in.

 
```
const stories = await Story.
  find({ author: author.\_id }).
  exec();
console.log('The stories are an array: ', stories);

```
 The documents returned from [query population](api/query#query_Query-populate) become fully functional, `remove`able, `save`able documents unless the [lean](api/query#query_Query-lean) option is specified. Do not confuse them with [sub docs](subdocs). Take caution when calling its remove method because you'll be removing it from the database, not just the array.

 Populating an existing document
-------------------------------

 If you have an existing mongoose document and want to populate some of its paths, you can use the [Document#populate()](api/document#document_Document-populate) method.

 
```
const person = await Person.findOne({ name: 'Ian Fleming' });

person.populated('stories'); // null

// Call the `populate()` method on a document to populate a path.
await person.populate('stories');

person.populated('stories'); // Array of ObjectIds
person.stories[0].name; // 'Casino Royale'

```
 The `Document#populate()` method does not support chaining. You need to call `populate()` multiple times, or with an array of paths, to populate multiple paths

 
```
await person.populate(['stories', 'fans']);
person.populated('fans'); // Array of ObjectIds

```
 Populating multiple existing documents
--------------------------------------

 If we have one or many mongoose documents or even plain objects (*like [mapReduce](api/model#model_Model-mapReduce) output*), we may populate them using the [Model.populate()](api/model#model_Model-populate) method. This is what `Document#populate()` and `Query#populate()` use to populate documents.

 Populating across multiple levels
---------------------------------

 Say you have a user schema which keeps track of the user's friends.

 
```
const userSchema = new Schema({
  name: String,
  friends: [{ type: ObjectId, ref: 'User' }]
});

```
 Populate lets you get a list of a user's friends, but what if you also wanted a user's friends of friends? Specify the `populate` option to tell mongoose to populate the `friends` array of all the user's friends:

 
```
await User.
  findOne({ name: 'Val' }).
  populate({
    path: 'friends',
    // Get friends of friends - populate the 'friends' array for every friend
    populate: { path: 'friends' }
  });

```
 Cross Database Populate
-----------------------

 Let's say you have a schema representing events, and a schema representing conversations. Each event has a corresponding conversation thread.

 
```
const db1 = mongoose.createConnection('mongodb://127.0.0.1:27000/db1');
const db2 = mongoose.createConnection('mongodb://127.0.0.1:27001/db2');

const conversationSchema = new Schema({ numMessages: Number });
const Conversation = db2.model('Conversation', conversationSchema);

const eventSchema = new Schema({
  name: String,
  conversation: {
    type: ObjectId,
    ref: Conversation // `ref` is a \*\*Model class\*\*, not a string
  }
});
const Event = db1.model('Event', eventSchema);

```
 In the above example, events and conversations are stored in separate MongoDB databases. String `ref` will not work in this situation, because Mongoose assumes a string `ref` refers to a model name on the same connection. In the above example, the conversation model is registered on `db2`, not `db1`.

 
```
// Works
const events = await Event.
  find().
  populate('conversation');

```
 This is known as a "cross-database populate," because it enables you to populate across MongoDB databases and even across MongoDB instances.

 If you don't have access to the model instance when defining your `eventSchema`, you can also pass [the model instance as an option to `populate()`](api/model#model_Model-populate).

 
```
const events = await Event.
  find().
  // The `model` option specifies the model to use for populating.
  populate({ path: 'conversation', model: Conversation });

```
 Dynamic References via `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 storing comments. A user may comment on either a blog post or a product.

 
```
const commentSchema = new Schema({
  body: { type: String, required: true },
  doc: {
    type: Schema.Types.ObjectId,
    required: true,
    // Instead of a hardcoded model name in `ref`, `refPath` means Mongoose
    // will look at the `docModel` property to find the right model.
    refPath: 'docModel'
  },
  docModel: {
    type: String,
    required: true,
    enum: ['BlogPost', 'Product']
  }
});

const Product = mongoose.model('Product', new Schema({ name: String }));
const BlogPost = mongoose.model('BlogPost', new Schema({ title: String }));
const Comment = mongoose.model('Comment', commentSchema);

```
 The `refPath` option is a more sophisticated alternative to `ref`. If `ref` is a string, Mongoose will always query the same model to find the populated subdocs. With `refPath`, you can configure what model Mongoose uses for each document.

 
```
const book = await Product.create({ name: 'The Count of Monte Cristo' });
const post = await BlogPost.create({ title: 'Top 10 French Novels' });

const commentOnBook = await Comment.create({
  body: 'Great read',
  doc: book.\_id,
  docModel: 'Product'
});

const commentOnPost = await Comment.create({
  body: 'Very informative',
  doc: post.\_id,
  docModel: 'BlogPost'
});

// The below `populate()` works even though one comment references the
// 'Product' collection and the other references the 'BlogPost' collection.
const comments = await Comment.find().populate('doc').sort({ body: 1 });
comments[0].doc.name; // "The Count of Monte Cristo"
comments[1].doc.title; // "Top 10 French Novels"

```
 An alternative approach is to define separate `blogPost` and `product` properties on `commentSchema`, and then `populate()` on both properties.

 
```
const commentSchema = new Schema({
  body: { type: String, required: true },
  product: {
    type: Schema.Types.ObjectId,
    required: true,
    ref: 'Product'
  },
  blogPost: {
    type: Schema.Types.ObjectId,
    required: true,
    ref: 'BlogPost'
  }
});

// ...

// The below `populate()` is equivalent to the `refPath` approach, you
// just need to make sure you `populate()` both `product` and `blogPost`.
const comments = await Comment.find().
  populate('product').
  populate('blogPost').
  sort({ body: 1 });
comments[0].product.name; // "The Count of Monte Cristo"
comments[1].blogPost.title; // "Top 10 French Novels"

```
 Defining separate `blogPost` and `product` properties works for this simple example. But, if you decide to allow users to also comment on articles or other comments, you'll need to add more properties to your schema. You'll also need an extra `populate()` call for every property, unless you use [mongoose-autopopulate](https://www.npmjs.com/package/mongoose-autopopulate). Using `refPath` means you only need 2 schema paths and one `populate()` call regardless of how many models your `commentSchema` can point to.

 Populate Virtuals
-----------------

 So far you've only populated based on the `_id` field. However, that's sometimes not the right choice. For example, suppose you have 2 models: `Author` and `BlogPost`.

 
```
const AuthorSchema = new Schema({
  name: String,
  posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'BlogPost' }]
});

const BlogPostSchema = new Schema({
  title: String,
  comments: [{
    author: { type: mongoose.Schema.Types.ObjectId, ref: 'Author' },
    content: String
  }]
});

const Author = mongoose.model('Author', AuthorSchema, 'Author');
const BlogPost = mongoose.model('BlogPost', BlogPostSchema, 'BlogPost');

```
 The above is an example of **bad schema design**. Why? Suppose you have an extremely prolific author that writes over 10k blog posts. That `author` document will be huge, over 12kb, and large documents lead to performance issues on both server and client. The [Principle of Least Cardinality](https://dev.to/swyx/4-things-i-learned-from-mastering-mongoose-js-25e#4-principle-of-least-cardinality) states that one-to-many relationships, like author to blog post, should be stored on the "many" side. In other words, blog posts should store their `author`, authors should **not** store all their `posts`.

 
```
const AuthorSchema = new Schema({
  name: String
});

const BlogPostSchema = new Schema({
  title: String,
  author: { type: mongoose.Schema.Types.ObjectId, ref: 'Author' },
  comments: [{
    author: { type: mongoose.Schema.Types.ObjectId, ref: 'Author' },
    content: String
  }]
});

```
 Unfortunately, these two schemas, as written, don't support populating an author's list of blog posts. That's where *virtual populate* comes in. Virtual populate means calling `populate()` on a virtual property that has a `ref` option as shown below.

 
```
// Specifying a virtual with a `ref` property is how you enable virtual
// population
AuthorSchema.virtual('posts', {
  ref: 'BlogPost',
  localField: '\_id',
  foreignField: 'author'
});

const Author = mongoose.model('Author', AuthorSchema, 'Author');
const BlogPost = mongoose.model('BlogPost', BlogPostSchema, 'BlogPost');

```
 You can then `populate()` the author's `posts` as shown below.

 
```
const author = await Author.findOne().populate('posts');

author.posts[0].title; // Title of the first blog post

```
 Keep in mind that virtuals are *not* included in `toJSON()` and `toObject()` output by default. If you want populate virtuals to show up when using functions like Express' [`res.json()` function](https://masteringjs.io/tutorials/express/json) or `console.log()`, set the `virtuals: true` option on your schema's `toJSON` and `toObject()` options.

 
```
const authorSchema = new Schema({ name: String }, {
  toJSON: { virtuals: true }, // So `res.json()` and other `JSON.stringify()` functions include virtuals
  toObject: { virtuals: true } // So `console.log()` and other functions that use `toObject()` include virtuals
});

```
 If you're using populate projections, make sure `foreignField` is included in the projection.

 
```
let authors = await Author.
  find({}).
  // Won't work because the foreign field `author` is not selected
  populate({ path: 'posts', select: 'title' }).
  exec();

authors = await Author.
  find({}).
  // Works, foreign field `author` is selected
  populate({ path: 'posts', select: 'title author' }).
  exec();

```
 Populate Virtuals: The Count Option
-----------------------------------

 Populate virtuals also support counting the number of documents with matching `foreignField` as opposed to the documents themselves. Set the `count` option on your virtual:

 
```
const PersonSchema = new Schema({
  name: String,
  band: String
});

const BandSchema = new Schema({
  name: String
});
BandSchema.virtual('numMembers', {
  ref: 'Person', // The model to use
  localField: 'name', // Find people where `localField`
  foreignField: 'band', // is equal to `foreignField`
  count: true // And only get the number of docs
});

// Later
const doc = await Band.findOne({ name: 'Motley Crue' }).
  populate('numMembers');
doc.numMembers; // 2

```
 Populate Virtuals: The Match Option
-----------------------------------

 Another option for Populate virtuals is `match`. This option adds an extra filter condition to the query Mongoose uses to `populate()`:

 
```
// Same example as 'Populate Virtuals' section
AuthorSchema.virtual('posts', {
  ref: 'BlogPost',
  localField: '\_id',
  foreignField: 'author',
  match: { archived: false } // match option with basic query selector
});

const Author = mongoose.model('Author', AuthorSchema, 'Author');
const BlogPost = mongoose.model('BlogPost', BlogPostSchema, 'BlogPost');

// After population
const author = await Author.findOne().populate('posts');

author.posts; // Array of not `archived` posts

```
 You can also set the `match` option to a function. That allows configuring the `match` based on the document being populated. For example, suppose you only want to populate blog posts whose `tags` contain one of the author's `favoriteTags`.

 
```
AuthorSchema.virtual('posts', {
  ref: 'BlogPost',
  localField: '\_id',
  foreignField: 'author',
  // Add an additional filter `{ tags: author.favoriteTags }` to the populate query
  // Mongoose calls the `match` function with the document being populated as the
  // first argument.
  match: author => ({ tags: author.favoriteTags })
});

```
 You can overwrite the `match` option when calling `populate()` as follows.

 
```
// Overwrite the `match` option specified in `AuthorSchema.virtual()` for this
// single `populate()` call.
await Author.findOne().populate({ path: posts, match: {} });

```
 You can also set the `match` option to a function in your `populate()` call. If you want to merge your `populate()` match option, rather than overwriting, use the following.

 
```
await Author.findOne().populate({
  path: posts,
  // Add `isDeleted: false` to the virtual's default `match`, so the `match`
  // option would be `{ tags: author.favoriteTags, isDeleted: false }`
  match: (author, virtual) => ({
    ...virtual.options.match(author),
    isDeleted: false
  })
});

```
 Populating Maps
---------------

 [Maps](schematypes#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.

 
```
const BandSchema = new Schema({
  name: String,
  members: {
    type: Map,
    of: {
      type: 'ObjectId',
      ref: 'Person'
    }
  }
});
const Band = mongoose.model('Band', bandSchema);

```
 This map has a `ref`, which means you can use `populate()` to populate all the ObjectIds in the map. Suppose you have the below `band` document:

 
```
const person1 = new Person({ name: 'Vince Neil' });
const person2 = new Person({ name: 'Mick Mars' });

const band = new Band({
  name: 'Motley Crue',
  members: {
    singer: person1.\_id,
    guitarist: person2.\_id
  }
});

```
 You can `populate()` every element in the map by populating the special path `members.$*`. `$*` is a special syntax that tells Mongoose to look at every key in the map.

 
```
const band = await Band.findOne({ name: 'Motley Crue' }).populate('members.$\*');

band.members.get('singer'); // { \_id: ..., name: 'Vince Neil' }

```
 You can also populate paths in maps of subdocuments using `$*`. For example, suppose you have the below `librarySchema`:

 
```
const librarySchema = new Schema({
  name: String,
  books: {
    type: Map,
    of: new Schema({
      title: String,
      author: {
        type: 'ObjectId',
        ref: 'Person'
      }
    })
  }
});
const Library = mongoose.model('Library', librarySchema);

```
 You can `populate()` every book's author by populating `books.$*.author`:

 
```
const libraries = await Library.find().populate('books.$\*.author');

```
 Populate in 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).

 
```
// Always attach `populate()` to `find()` calls
MySchema.pre('find', function() {
  this.populate('user');
});

```
 
```
// Always `populate()` after `find()` calls. Useful if you want to selectively populate
// based on the docs found.
MySchema.post('find', async function(docs) {
  for (const doc of docs) {
    if (doc.isPublic) {
      await doc.populate('user');
    }
  }
});

```
 
```
// `populate()` after saving. Useful for sending populated data back to the client in an
// update API endpoint
MySchema.post('save', function(doc, next) {
  doc.populate('user').then(function() {
    next();
  });
});

```
 Populating Multiple Paths in 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:

 
```
const userSchema = new Schema({
  email: String,
  password: String,
  followers: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
  following: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }]
});

userSchema.pre('find', function(next) {
  this.populate('followers following');
  next();
});

const User = mongoose.model('User', userSchema);

```
 However, this will not work. By default, passing multiple paths to `populate()` in the middleware will trigger an infinite recursion, which means that it will basically trigger the same middleware for all of the paths provided to the `populate()` method - For example, `this.populate('followers following')` will trigger the same middleware for both `followers` and `following` fields and the request will just be left hanging in an infinite loop.

 To avoid this, we have to add the `_recursed` option, so that our middleware will avoid populating recursively. The example below will make it work as expected.

 
```
userSchema.pre('find', function(next) {
  if (this.options.\_recursed) {
    return next();
  }
  this.populate({ path: 'followers following', options: { \_recursed: true } });
  next();
});

```
 Alternatively, you can check out the [mongoose-autopopulate plugin](http://npmjs.com/package/mongoose-autopopulate).

 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. This gives you more control over the result of the `populate()` execution. It is especially useful when you're populating multiple documents.

 The [original motivation](https://github.com/Automattic/mongoose/issues/3775) for the `transform` option was to give the ability to leave the unpopulated `_id` if no document was found, instead of setting the value to `null`:

 
```
// With `transform`
doc = await Parent.findById(doc).populate([
  {
    path: 'child',
    // If `doc` is null, use the original id instead
    transform: (doc, id) => doc == null ? id : doc
  }
]);

doc.child; // 634d1a5744efe65ae09142f9
doc.children; // [ 634d1a67ac15090a0ca6c0ea, { \_id: 634d1a4ddb804d17d95d1c7f, name: 'Luke', \_\_v: 0 } ]

```
 You can return any value from `transform()`. For example, you can use `transform()` to "flatten" populated documents as follows.

 
```
let doc = await Parent.create({ children: [{ name: 'Luke' }, { name: 'Leia' }] });

doc = await Parent.findById(doc).populate([{
  path: 'children',
  transform: doc => doc == null ? null : doc.name
}]);

doc.children; // ['Luke', 'Leia']

```
 Another use case for `transform()` is setting `$locals` values on populated documents to pass parameters to getters and virtuals. For example, suppose you want to set a language code on your document for internationalization purposes as follows.

 
```
const internationalizedStringSchema = new Schema({
  en: String,
  es: String
});

const ingredientSchema = new Schema({
  // Instead of setting `name` to just a string, set `name` to a map
  // of language codes to strings.
  name: {
    type: internationalizedStringSchema,
    // When you access `name`, pull the document's locale
    get: function(value) {
      return value[this.$locals.language || 'en'];
    }
  }
});

const recipeSchema = new Schema({
  ingredients: [{ type: mongoose.ObjectId, ref: 'Ingredient' }]
});

const Ingredient = mongoose.model('Ingredient', ingredientSchema);
const Recipe = mongoose.model('Recipe', recipeSchema);

```
 You can set the language code on all populated exercises as follows:

 
```
// Create some sample data
const { _id } = await Ingredient.create({
  name: {
    en: 'Eggs',
    es: 'Huevos'
  }
});
await Recipe.create({ ingredients: [_id] });

// Populate with setting `$locals.language` for internationalization
const language = 'es';
const recipes = await Recipe.find().populate({
  path: 'ingredients',
  transform: function(doc) {
    doc.$locals.language = language;
    return doc;
  }
});

// Gets the ingredient's name in Spanish `name.es`
recipes[0].ingredients[0].name; // 'Huevos'

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/populate.html>

Query Casting
==============

 The first parameter to [`Model.find()`](../api/model#model_Model-find), [`Query#find()`](../api/query#query_Query-find), [`Model.findOne()`](../api/model#model_Model-findOne), etc. is called `filter`. In older content this parameter is sometimes called `query` or `conditions`. For example:

 
```
const query = Character.find({ name: 'Jean-Luc Picard' });
query.getFilter(); // `{ name: 'Jean-Luc Picard' }`

// Subsequent chained calls merge new properties into the filter
query.find({ age: { $gt: 50 } });
query.getFilter(); // `{ name: 'Jean-Luc Picard', age: { $gt: 50 } }`

```
 When you execute the query using [`Query#exec()`](../api/query#query_Query-exec) or [`Query#then()`](../api/query#query_Query-then), Mongoose *casts* the filter to match your schema.

 
```
// Note that `\_id` and `age` are strings. Mongoose will cast `\_id` to
// a MongoDB ObjectId and `age.$gt` to a number.
const query = Character.findOne({
  \_id: '5cdc267dd56b5662b7b7cc0c',
  age: { $gt: '50' }
});

// `{ \_id: '5cdc267dd56b5662b7b7cc0c', age: { $gt: '50' } }`
// Query hasn't been executed yet, so Mongoose hasn't casted the filter.
query.getFilter();

const doc = await query.exec();
doc.name; // "Jean-Luc Picard"

// Mongoose casted the filter, so `\_id` became an ObjectId and `age.$gt`
// became a number.
query.getFilter().\_id instanceof mongoose.Types.ObjectId; // true
typeof query.getFilter().age.$gt === 'number'; // true

```
 If Mongoose fails to cast the filter to your schema, your query will throw a `CastError`.

 
```
const query = Character.findOne({ age: { $lt: 'not a number' } });

const err = await query.exec().then(() => null, err => err);
err instanceof mongoose.CastError; // true
// Cast to number failed for value "not a number" at path "age" for
// model "Character"
err.message;

```
  The `strictQuery` Option
-------------------------

 By default, Mongoose does **not** cast filter properties that aren't in your schema.

 
```
const query = Character.findOne({ notInSchema: { $lt: 'not a number' } });

// No error because `notInSchema` is not defined in the schema
await query.exec();

```
 You can configure this behavior using the [`strictQuery` option for schemas](../guide#strictQuery). This option is analogous to the [`strict` option](../guide#strict). Setting `strictQuery` to `true` removes non-schema properties from the filter:

 
```
mongoose.deleteModel('Character');
const schema = new mongoose.Schema({ name: String, age: Number }, {
  strictQuery: true
});
Character = mongoose.model('Character', schema);

const query = Character.findOne({ notInSchema: { $lt: 'not a number' } });

await query.exec();
query.getFilter(); // Empty object `{}`, Mongoose removes `notInSchema`

```
 To make Mongoose throw an error if your `filter` has a property that isn't in the schema, set `strictQuery` to `'throw'`:

 
```
mongoose.deleteModel('Character');
const schema = new mongoose.Schema({ name: String, age: Number }, {
  strictQuery: 'throw'
});
Character = mongoose.model('Character', schema);

const query = Character.findOne({ notInSchema: { $lt: 'not a number' } });

const err = await query.exec().then(() => null, err => err);
err.name; // 'StrictModeError'
// Path "notInSchema" is not in schema and strictQuery is 'throw'.
err.message;

```
  Implicit `$in`
---------------

 Because of schemas, Mongoose knows what types fields should be, so it can provide some neat syntactic sugar. For example, if you forget to put [`$in`](https://www.mongodb.com/docs/manual/reference/operator/query/in/) on a non-array field, Mongoose will add `$in` for you.

 
```
// Normally wouldn't find anything because `name` is a string, but
// Mongoose automatically inserts `$in`
const query = Character.findOne({ name: ['Jean-Luc Picard', 'Will Riker'] });

const doc = await query.exec();
doc.name; // "Jean-Luc Picard"

// `{ name: { $in: ['Jean-Luc Picard', 'Will Riker'] } }`
query.getFilter();

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/tutorials/query_casting.html>

Validation
===========

 Before we get into the specifics of validation syntax, please keep the following rules in mind:

 * Validation is defined in the [SchemaType](schematypes)
* Validation is <middleware>. Mongoose registers validation as a `pre('save')` hook on every schema by default.
* Validation always runs as the **first** `pre('save')` hook. This means that validation doesn't run on any changes you make in `pre('save')` hooks.
* You can disable automatic validation before save by setting the [validateBeforeSave](guide#validateBeforeSave) option
* You can manually run validation using `doc.validate()` or `doc.validateSync()`
* You can manually mark a field as invalid (causing validation to fail) by using [`doc.invalidate(...)`](api/document#document_Document-invalidate)
* Validators are not run on undefined values. The only exception is the [`required` validator](api/schematype#schematype_SchemaType-required).
* When you call [Model#save](api/model#model_Model-save), Mongoose also runs subdocument validation. If an error occurs, your [Model#save](api/model#model_Model-save) promise rejects
* Validation is customizable

 
```
const schema = new Schema({
  name: {
    type: String,
    required: true
  }
});
const Cat = db.model('Cat', schema);

// This cat has no name :(
const cat = new Cat();

let error;
try {
  await cat.save();
} catch (err) {
  error = err;
}

assert.equal(error.errors['name'].message,
  'Path `name` is required.');

error = cat.validateSync();
assert.equal(error.errors['name'].message,
  'Path `name` is required.');

```
 * [Built-in Validators](#built-in-validators)
* [Custom Error Messages](#custom-error-messages)
* [The `unique` Option is Not a Validator](#the-unique-option-is-not-a-validator)
* [Custom Validators](#custom-validators)
* [Async Custom Validators](#async-custom-validators)
* [Validation Errors](#validation-errors)
* [Cast Errors](#cast-errors)
* [Global SchemaType Validation](#global-schematype-validation)
* [Required Validators On Nested Objects](#required-validators-on-nested-objects)
* [Update Validators](#update-validators)
* [Update Validators and `this`](#update-validators-and-this)
* [Update Validators Only Run On Updated Paths](#update-validators-only-run-on-updated-paths)
* [Update Validators Only Run For Some Operations](#update-validators-only-run-for-some-operations)

  Built-in Validators
--------------------

 Mongoose has several built-in validators.

 * All [SchemaTypes](schematypes) have the built-in [required](api/schematype#schematype_SchemaType-required) validator. The required validator uses the [SchemaType's `checkRequired()` function](api/schematype#schematype_SchemaType-checkRequired) to determine if the value satisfies the required validator.
* [Numbers](schematypes#numbers) have [`min` and `max`](schematypes#number-validators) validators.
* [Strings](schematypes#strings) have [`enum`, `match`, `minLength`, and `maxLength`](schematypes#string-validators) validators.

 Each of the validator links above provide more information about how to enable them and customize their error messages.

 
```
const breakfastSchema = new Schema({
  eggs: {
    type: Number,
    min: [6, 'Too few eggs'],
    max: 12
  },
  bacon: {
    type: Number,
    required: [true, 'Why no bacon?']
  },
  drink: {
    type: String,
    enum: ['Coffee', 'Tea'],
    required: function() {
      return this.bacon > 3;
    }
  }
});
const Breakfast = db.model('Breakfast', breakfastSchema);

const badBreakfast = new Breakfast({
  eggs: 2,
  bacon: 0,
  drink: 'Milk'
});
let error = badBreakfast.validateSync();
assert.equal(error.errors['eggs'].message,
  'Too few eggs');
assert.ok(!error.errors['bacon']);
assert.equal(error.errors['drink'].message,
  '`Milk` is not a valid enum value for path `drink`.');

badBreakfast.bacon = 5;
badBreakfast.drink = null;

error = badBreakfast.validateSync();
assert.equal(error.errors['drink'].message, 'Path `drink` is required.');

badBreakfast.bacon = null;
error = badBreakfast.validateSync();
assert.equal(error.errors['bacon'].message, 'Why no bacon?');

```
  Custom Error Messages
----------------------

 You can configure the error message for individual validators in your schema. There are two equivalent ways to set the validator error message:

 * Array syntax: `min: [6, 'Must be at least 6, got {VALUE}']`
* Object syntax: `enum: { values: ['Coffee', 'Tea'], message: '{VALUE} is not supported' }`

 Mongoose also supports rudimentary templating for error messages. Mongoose replaces `{VALUE}` with the value being validated.

 
```
const breakfastSchema = new Schema({
  eggs: {
    type: Number,
    min: [6, 'Must be at least 6, got {VALUE}'],
    max: 12
  },
  drink: {
    type: String,
    enum: {
      values: ['Coffee', 'Tea'],
      message: '{VALUE} is not supported'
    }
  }
});
const Breakfast = db.model('Breakfast', breakfastSchema);

const badBreakfast = new Breakfast({
  eggs: 2,
  drink: 'Milk'
});
const error = badBreakfast.validateSync();
assert.equal(error.errors['eggs'].message,
  'Must be at least 6, got 2');
assert.equal(error.errors['drink'].message, 'Milk is not supported');

```
  The `unique` Option is Not a Validator
---------------------------------------

 A common gotcha for beginners is that the `unique` option for schemas is *not* a validator. It's a convenient helper for building [MongoDB unique indexes](https://www.mongodb.com/docs/manual/core/index-unique/). See the [FAQ](https://mongoosejs.com/docs/faq.html) for more information.

 
```
const uniqueUsernameSchema = new Schema({
  username: {
    type: String,
    unique: true
  }
});
const U1 = db.model('U1', uniqueUsernameSchema);
const U2 = db.model('U2', uniqueUsernameSchema);

const dup = [{ username: 'Val' }, { username: 'Val' }];
// Race condition! This may save successfully, depending on whether
// MongoDB built the index before writing the 2 docs.
U1.create(dup).
  then(() => {
  }).
  catch(err => {
  });

// You need to wait for Mongoose to finish building the `unique`
// index before writing. You only need to build indexes once for
// a given collection, so you normally don't need to do this
// in production. But, if you drop the database between tests,
// you will need to use `init()` to wait for the index build to finish.
U2.init().
  then(() => U2.create(dup)).
  catch(error => {
    // `U2.create()` will error, but will \*not\* be a mongoose validation error, it will be
    // a duplicate key error.
    // See: https://masteringjs.io/tutorials/mongoose/e11000-duplicate-key
    assert.ok(error);
    assert.ok(!error.errors);
    assert.ok(error.message.indexOf('duplicate key error') !== -1);
  });

```
  Custom Validators
------------------

 If the built-in validators aren't enough, you can define custom validators to suit your needs.

 Custom validation is declared by passing a validation function. You can find detailed instructions on how to do this in the [`SchemaType#validate()` API docs](api/schematype#schematype_SchemaType-validate).

 
```
const userSchema = new Schema({
  phone: {
    type: String,
    validate: {
      validator: function(v) {
        return /\d{3}-\d{3}-\d{4}/.test(v);
      },
      message: props => `${props.value} is not a valid phone number!`
    },
    required: [true, 'User phone number required']
  }
});

const User = db.model('user', userSchema);
const user = new User();
let error;

user.phone = '555.0123';
error = user.validateSync();
assert.equal(error.errors['phone'].message,
  '555.0123 is not a valid phone number!');

user.phone = '';
error = user.validateSync();
assert.equal(error.errors['phone'].message,
  'User phone number required');

user.phone = '201-555-0123';
// Validation succeeds! Phone number is defined
// and fits `DDD-DDD-DDDD`
error = user.validateSync();
assert.equal(error, null);

```
  Async Custom Validators
------------------------

 Custom validators can also be asynchronous. If your validator function returns a promise (like an `async` function), mongoose will wait for that promise to settle. If the returned promise rejects, or fulfills with the value `false`, Mongoose will consider that a validation error.

 
```
const userSchema = new Schema({
  name: {
    type: String,
    // You can also make a validator async by returning a promise.
    validate: () => Promise.reject(new Error('Oops!'))
  },
  email: {
    type: String,
    // There are two ways for an promise-based async validator to fail:
    // 1) If the promise rejects, Mongoose assumes the validator failed with the given error.
    // 2) If the promise resolves to `false`, Mongoose assumes the validator failed and creates an error with the given `message`.
    validate: {
      validator: () => Promise.resolve(false),
      message: 'Email validation failed'
    }
  }
});

const User = db.model('User', userSchema);
const user = new User();

user.email = 'test@test.co';
user.name = 'test';

let error;
try {
  await user.validate();
} catch (err) {
  error = err;
}
assert.ok(error);
assert.equal(error.errors['name'].message, 'Oops!');
assert.equal(error.errors['email'].message, 'Email validation failed');

```
  Validation Errors
------------------

 Errors returned after failed validation contain an `errors` object whose values are `ValidatorError` objects. Each [ValidatorError](api/error#error_Error-ValidatorError) has `kind`, `path`, `value`, and `message` properties. A ValidatorError also may have a `reason` property. If an error was thrown in the validator, this property will contain the error that was thrown.

 
```
const toySchema = new Schema({
  color: String,
  name: String
});

const validator = function(value) {
  return /red|white|gold/i.test(value);
};
toySchema.path('color').validate(validator,
  'Color `{VALUE}` not valid', 'Invalid color');
toySchema.path('name').validate(function(v) {
  if (v !== 'Turbo Man') {
    throw new Error('Need to get a Turbo Man for Christmas');
  }
  return true;
}, 'Name `{VALUE}` is not valid');

const Toy = db.model('Toy', toySchema);

const toy = new Toy({ color: 'Green', name: 'Power Ranger' });

let error;
try {
  await toy.save();
} catch (err) {
  error = err;
}

// `error` is a ValidationError object
// `error.errors.color` is a ValidatorError object
assert.equal(error.errors.color.message, 'Color `Green` not valid');
assert.equal(error.errors.color.kind, 'Invalid color');
assert.equal(error.errors.color.path, 'color');
assert.equal(error.errors.color.value, 'Green');

// If your validator throws an exception, mongoose will use the error
// message. If your validator returns `false`,
// mongoose will use the 'Name `Power Ranger` is not valid' message.
assert.equal(error.errors.name.message,
  'Need to get a Turbo Man for Christmas');
assert.equal(error.errors.name.value, 'Power Ranger');
// If your validator threw an error, the `reason` property will contain
// the original error thrown, including the original stack trace.
assert.equal(error.errors.name.reason.message,
  'Need to get a Turbo Man for Christmas');

assert.equal(error.name, 'ValidationError');

```
  Cast Errors
------------

 Before running validators, Mongoose attempts to coerce values to the correct type. This process is called *casting* the document. If casting fails for a given path, the `error.errors` object will contain a `CastError` object.

 Casting runs before validation, and validation does not run if casting fails. That means your custom validators may assume `v` is `null`, `undefined`, or an instance of the type specified in your schema.

 
```
const vehicleSchema = new mongoose.Schema({
  numWheels: { type: Number, max: 18 }
});
const Vehicle = db.model('Vehicle', vehicleSchema);

const doc = new Vehicle({ numWheels: 'not a number' });
const err = doc.validateSync();

err.errors['numWheels'].name; // 'CastError'
// 'Cast to Number failed for value "not a number" at path "numWheels"'
err.errors['numWheels'].message;

```
 By default, Mongoose cast error messages look like `Cast to Number failed for value "pie" at path "numWheels"`. You can overwrite Mongoose's default cast error message by the `cast` option on your SchemaType to a string as follows.

 
```
const vehicleSchema = new mongoose.Schema({
  numWheels: {
    type: Number,
    cast: '{VALUE} is not a number'
  }
});
const Vehicle = db.model('Vehicle', vehicleSchema);

const doc = new Vehicle({ numWheels: 'pie' });
const err = doc.validateSync();

err.errors['numWheels'].name; // 'CastError'
// "pie" is not a number
err.errors['numWheels'].message;

```
 Mongoose's cast error message templating supports the following parameters:

 * `{PATH}`: the path that failed to cast
* `{VALUE}`: a string representation of the value that failed to cast
* `{KIND}`: the type that Mongoose attempted to cast to, like `'String'` or `'Number'`

 You can also define a function that Mongoose will call to get the cast error message as follows.

 
```
const vehicleSchema = new mongoose.Schema({
  numWheels: {
    type: Number,
    cast: [null, (value, path, model, kind) => `"${value}" is not a number`]
  }
});
const Vehicle = db.model('Vehicle', vehicleSchema);

const doc = new Vehicle({ numWheels: 'pie' });
const err = doc.validateSync();

err.errors['numWheels'].name; // 'CastError'
// "pie" is not a number
err.errors['numWheels'].message;

```
  Global SchemaType Validation
-----------------------------

 In addition to defining custom validators on individual schema paths, you can also configure a custom validator to run on every instance of a given `SchemaType`. For example, the following code demonstrates how to make empty string `''` an invalid value for *all* string paths.

 
```
// Add a custom validator to all strings
mongoose.Schema.Types.String.set('validate', v => v == null || v > 0);

const userSchema = new Schema({
  name: String,
  email: String
});
const User = db.model('User', userSchema);

const user = new User({ name: '', email: '' });

const err = await user.validate().then(() => null, err => err);
err.errors['name']; // ValidatorError
err.errors['email']; // ValidatorError

```
  Required Validators On Nested Objects
--------------------------------------

 Defining validators on nested objects in mongoose is tricky, because nested objects are not fully fledged paths.

 
```
let personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
});

assert.throws(function() {
  // This throws an error, because 'name' isn't a full fledged path
  personSchema.path('name').required(true);
}, /Cannot.\*'required'/);

// To make a nested object required, use a single nested schema
const nameSchema = new Schema({
  first: String,
  last: String
});

personSchema = new Schema({
  name: {
    type: nameSchema,
    required: true
  }
});

const Person = db.model('Person', personSchema);

const person = new Person();
const error = person.validateSync();
assert.ok(error.errors['name']);

```
  Update Validators
------------------

 In the above examples, you learned about document validation. Mongoose also supports validation for [`update()`](api/query#query_Query-update), [`updateOne()`](api/query#query_Query-updateOne), [`updateMany()`](api/query#query_Query-updateMany), and [`findOneAndUpdate()`](api/query#query_Query-findOneAndUpdate) operations. Update validators are off by default - you need to specify the `runValidators` option.

 To turn on update validators, set the `runValidators` option for `update()`, `updateOne()`, `updateMany()`, or `findOneAndUpdate()`. Be careful: update validators are off by default because they have several caveats.

 
```
const toySchema = new Schema({
  color: String,
  name: String
});

const Toy = db.model('Toys', toySchema);

Toy.schema.path('color').validate(function(value) {
  return /red|green|blue/i.test(value);
}, 'Invalid color');

const opts = { runValidators: true };

let error;
try {
  await Toy.updateOne({}, { color: 'not a color' }, opts);
} catch (err) {
  error = err;
}

assert.equal(error.errors.color.message, 'Invalid color');

```
  Update Validators and `this`
-----------------------------

 There are a couple of key differences between update validators and document validators. In the color validation function below, `this` refers to the document being validated when using document validation. However, when running update validators, `this` refers to the query object instead of the document. Because queries have a neat `.get()` function, you can get the updated value of the property you want.

 
```
const toySchema = new Schema({
  color: String,
  name: String
});

toySchema.path('color').validate(function(value) {
  // When running in `validate()` or `validateSync()`, the
  // validator can access the document using `this`.
  // When running with update validators, `this` is the Query,
  // \*\*not\*\* the document being updated!
  // Queries have a `get()` method that lets you get the
  // updated value.
  if (this.get('name') && this.get('name').toLowerCase().indexOf('red') !== -1) {
    return value === 'red';
  }
  return true;
});

const Toy = db.model('ActionFigure', toySchema);

const toy = new Toy({ color: 'green', name: 'Red Power Ranger' });
// Validation failed: color: Validator failed for path `color` with value `green`
let error = toy.validateSync();
assert.ok(error.errors['color']);

const update = { color: 'green', name: 'Red Power Ranger' };
const opts = { runValidators: true };

error = null;
try {
  await Toy.updateOne({}, update, opts);
} catch (err) {
  error = err;
}
// Validation failed: color: Validator failed for path `color` with value `green`
assert.ok(error);

```
  Update Validators Only Run On Updated Paths
--------------------------------------------

 The other key difference is that update validators only run on the paths specified in the update. For instance, in the below example, because 'name' is not specified in the update operation, update validation will succeed.

 When using update validators, `required` validators **only** fail when you try to explicitly `$unset` the key.

 
```
const kittenSchema = new Schema({
  name: { type: String, required: true },
  age: Number
});

const Kitten = db.model('Kitten', kittenSchema);

const update = { color: 'blue' };
const opts = { runValidators: true };
// Operation succeeds despite the fact that 'name' is not specified
await Kitten.updateOne({}, update, opts);

const unset = { $unset: { name: 1 } };
// Operation fails because 'name' is required
const err = await Kitten.updateOne({}, unset, opts).then(() => null, err => err);
assert.ok(err);
assert.ok(err.errors['name']);

```
  Update Validators Only Run For Some Operations
-----------------------------------------------

 One final detail worth noting: update validators **only** run on the following update operators:

 * `$set`
* `$unset`
* `$push`
* `$addToSet`
* `$pull`
* `$pullAll`

 For instance, the below update will succeed, regardless of the value of `number`, because update validators ignore `$inc`.

 Also, `$push`, `$addToSet`, `$pull`, and `$pullAll` validation does **not** run any validation on the array itself, only individual elements of the array.

 
```
const testSchema = new Schema({
  number: { type: Number, max: 0 },
  arr: [{ message: { type: String, maxlength: 10 } }]
});

// Update validators won't check this, so you can still `$push` 2 elements
// onto the array, so long as they don't have a `message` that's too long.
testSchema.path('arr').validate(function(v) {
  return v.length < 2;
});

const Test = db.model('Test', testSchema);

let update = { $inc: { number: 1 } };
const opts = { runValidators: true };

// There will never be a validation error here
await Test.updateOne({}, update, opts);

// This will never error either even though the array will have at
// least 2 elements.
update = { $push: [{ message: 'hello' }, { message: 'world' }] };
await Test.updateOne({}, update, opts);

```
  Next Up
--------

 Now that we've covered `Validation`, let's take a look at [Middleware](middleware).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/validation.html>

Schema
======



### Schema()


##### Parameters:


* `[definition]` «Object|Schema|Array» Can be one of: object describing schema paths, or schema to copy, or array of objects and schemas
* `[options]` «Object»


##### Inherits:


* [«NodeJS EventEmitter»](https://nodejs.org/api/events.html#class-eventemitter)



Schema constructor.

 ####   [Example:](#example)

 
```
const child = new Schema({ name: String });
const schema = new Schema({ name: String, age: Number, children: [child] });
const Tree = mongoose.model('Tree', schema);

// setting schema options
new Schema({ name: String }, { \_id: false, autoIndex: false })

```
 ####   [Options:](#options)

 * [autoIndex](../guide#autoIndex): bool - defaults to null (which means use the connection's autoIndex option)
* [autoCreate](../guide#autoCreate): bool - defaults to null (which means use the connection's autoCreate option)
* [bufferCommands](../guide#bufferCommands): bool - defaults to true
* [bufferTimeoutMS](../guide#bufferTimeoutMS): number - defaults to 10000 (10 seconds). If `bufferCommands` is enabled, the amount of time Mongoose will wait for connectivity to be restablished before erroring out.
* [capped](../guide#capped): bool | number | object - defaults to false
* [collection](../guide#collection): string - no default
* [discriminatorKey](../guide#discriminatorKey): string - defaults to `__t`
* [id](../guide#id): bool - defaults to true
* [\_id](../guide#_id): bool - defaults to true
* [minimize](../guide#minimize): bool - controls [document#toObject](document#Document.prototype.toObject()) behavior when called manually - defaults to true
* [read](../guide#read): string
* [writeConcern](../guide#writeConcern): object - defaults to null, use to override [the MongoDB server's default write concern settings](https://www.mongodb.com/docs/manual/reference/write-concern/)
* [shardKey](../guide#shardKey): object - defaults to `null`
* [strict](../guide#strict): bool - defaults to true
* [strictQuery](../guide#strictQuery): bool - defaults to false
* [toJSON](../guide#toJSON) - object - no default
* [toObject](../guide#toObject) - object - no default
* [typeKey](../guide#typeKey) - string - defaults to 'type'
* [validateBeforeSave](../guide#validateBeforeSave) - bool - defaults to `true`
* [validateModifiedOnly](document#Document.prototype.validate()) - bool - defaults to `false`
* [versionKey](../guide#versionKey): string or object - defaults to "\_\_v"
* [optimisticConcurrency](../guide#optimisticConcurrency): bool - defaults to false. Set to true to enable [optimistic concurrency](https://thecodebarbarian.com/whats-new-in-mongoose-5-10-optimistic-concurrency.html).
* [collation](../guide#collation): object - defaults to null (which means use no collation)
* [timeseries](../guide#timeseries): object - defaults to null (which means this schema's collection won't be a timeseries collection)
* [selectPopulatedPaths](../guide#selectPopulatedPaths): boolean - defaults to `true`
* [skipVersioning](../guide#skipVersioning): object - paths to exclude from versioning
* [timestamps](../guide#timestamps): object or boolean - defaults to `false`. If true, Mongoose adds `createdAt` and `updatedAt` properties to your schema and manages those properties for you.
* [pluginTags](../guide#pluginTags): array of strings - defaults to `undefined`. If set and plugin called with `tags` option, will only apply that plugin to schemas with a matching tag.
* [virtuals](../tutorials/virtuals#virtuals-via-schema-options): object - virtuals to define, alias for [`.virtual`](#Schema.prototype.virtual())
* [collectionOptions]: object with options passed to [`createCollection()`](https://www.mongodb.com/docs/manual/reference/method/db.createCollection/) when calling `Model.createCollection()` or `autoCreate` set to true.

 ####   [Options for Nested Schemas:](#options-for-nested-schemas)

 * `excludeIndexes`: bool - defaults to `false`. If `true`, skip building indexes on this schema's paths.

 ####   [Note:](#note)

 *When nesting schemas, (`children` in the example above), always declare the child schema first before passing it into its parent.*

 
### Schema.Types


##### Type:


* «property»



The various built-in Mongoose Schema Types.

 ####   [Example:](#example)

 
```
const mongoose = require('mongoose');
const ObjectId = mongoose.Schema.Types.ObjectId;

```
 ####   [Types:](#types)

 * [String](../schematypes#strings)
* [Number](../schematypes#numbers)
* [Boolean](../schematypes#booleans) | Bool
* [Array](../schematypes#arrays)
* [Buffer](../schematypes#buffers)
* [Date](../schematypes#dates)
* [ObjectId](../schematypes#objectids) | Oid
* [Mixed](../schematypes#mixed)
* [UUID](../schematypes#uuid)
* [BigInt](../schematypes#bigint)

 Using this exposed access to the `Mixed` SchemaType, we can use them in our schema.

 
```
const Mixed = mongoose.Schema.Types.Mixed;
new mongoose.Schema({ \_user: Mixed })

```
 
### Schema.indexTypes


##### Type:


* «property»



The allowed index types

 
### Schema.prototype.add()


##### Parameters:


* `obj` «Object|Schema» plain object with paths to add, or another schema
* `[prefix]` «String» path to prefix the newly added paths with


##### Returns:


* «Schema» the Schema instance



Adds key path / schema type pairs to this schema.

 ####   [Example:](#example)

 
```
const ToySchema = new Schema();
ToySchema.add({ name: 'string', color: 'string', price: 'number' });

const TurboManSchema = new Schema();
// You can also `add()` another schema and copy over all paths, virtuals,
// getters, setters, indexes, methods, and statics.
TurboManSchema.add(ToySchema).add({ year: Number });

```
 
### Schema.prototype.alias()


##### Parameters:


* `path` «String» real path to alias
* `alias` «String|Array[String]» the path(s) to use as an alias for `path`


##### Returns:


* «Schema» the Schema instance



Add an alias for `path`. This means getting or setting the `alias` is equivalent to getting or setting the `path`.

 ####   [Example:](#example)

 
```
const toySchema = new Schema({ n: String });

// Make 'name' an alias for 'n'
toySchema.alias('n', 'name');

const Toy = mongoose.model('Toy', toySchema);
const turboMan = new Toy({ n: 'Turbo Man' });

turboMan.name; // 'Turbo Man'
turboMan.n; // 'Turbo Man'

turboMan.name = 'Turbo Man Action Figure';
turboMan.n; // 'Turbo Man Action Figure'

await turboMan.save(); // Saves { \_id: ..., n: 'Turbo Man Action Figure' }

```
 
### Schema.prototype.childSchemas


##### Type:


* «property»



Array of child schemas (from document arrays and single nested subdocs) and their corresponding compiled models. Each element of the array is an object with 2 properties: `schema` and `model`.

 This property is typically only useful for plugin authors and advanced users. You do not need to interact with this property at all to use mongoose.

 
### Schema.prototype.clearIndexes()


##### Returns:


* «Schema» the Schema instance



Remove all indexes from this schema.

 clearIndexes only removes indexes from your schema object. Does **not** affect the indexes in MongoDB.

 ####   [Example:](#example)

 
```
const ToySchema = new Schema({ name: String, color: String, price: Number });
ToySchema.index({ name: 1 });
ToySchema.index({ color: 1 });

// Remove all indexes on this schema
ToySchema.clearIndexes();

ToySchema.indexes(); // []

```
 
### Schema.prototype.clone()


##### Returns:


* «Schema» the cloned schema



Returns a deep copy of the schema

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: String });
const clone = schema.clone();
clone === schema; // false
clone.path('name'); // SchemaString { ... }

```
 
### Schema.prototype.discriminator()


##### Parameters:


* `name` «String» the name of the discriminator
* `schema` «Schema» the discriminated Schema


##### Returns:


* «Schema» the Schema instance



Inherit a Schema by applying a discriminator on an existing Schema.

 ####   [Example:](#example)

 
```
const eventSchema = new mongoose.Schema({ timestamp: Date }, { discriminatorKey: 'kind' });

const clickedEventSchema = new mongoose.Schema({ element: String }, { discriminatorKey: 'kind' });
const ClickedModel = eventSchema.discriminator('clicked', clickedEventSchema);

const Event = mongoose.model('Event', eventSchema);

Event.discriminators['clicked']; // Model { clicked }

const doc = await Event.create({ kind: 'clicked', element: '#hero' });
doc.element; // '#hero'
doc instanceof ClickedModel; // true

```
 
### Schema.prototype.eachPath()


##### Parameters:


* `fn` «Function» callback function


##### Returns:


* «Schema» this



Iterates the schemas paths similar to Array#forEach.

 The callback is passed the pathname and the schemaType instance.

 ####   [Example:](#example)

 
```
const userSchema = new Schema({ name: String, registeredAt: Date });
userSchema.eachPath((pathname, schematype) => {
  // Prints twice:
  // name SchemaString { ... }
  // registeredAt SchemaDate { ... }
  console.log(pathname, schematype);
});

```
 
### Schema.prototype.get()


##### Parameters:


* `key` «String» The name of the Option to get the current value for


##### Returns:


* «Any» the option's value



Gets a schema option.

 ####   [Example:](#example)

 
```
schema.get('strict'); // true
schema.set('strict', false);
schema.get('strict'); // false

```
 
### Schema.prototype.index()


##### Parameters:


* `fields` «Object» The Fields to index, with the order, available values: `1 | -1 | '2d' | '2dsphere' | 'geoHaystack' | 'hashed' | 'text'`
* `[options]` «Object» Options to pass to [MongoDB driver's `createIndex()` function](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#createIndex)
+ `[options.expires=null]` «String|number» Mongoose-specific syntactic sugar, uses [ms](https://www.npmjs.com/package/ms) to convert `expires` option into seconds for the `expireAfterSeconds` in the above link.
+ `[options.language_override=null]` «String» Tells mongodb to use the specified field instead of `language` for parsing text indexes.



Defines an index (most likely compound) for this schema.

 ####   [Example:](#example)

 
```
schema.index({ first: 1, last: -1 })

```
 
### Schema.prototype.indexes()


##### Returns:


* «Array» list of indexes defined in the schema



Returns a list of indexes that this schema declares, via `schema.index()` or by `index: true` in a path's options. Indexes are expressed as an array `[spec, options]`.

 ####   [Example:](#example)

 
```
const userSchema = new Schema({
  email: { type: String, required: true, unique: true },
  registeredAt: { type: Date, index: true }
});

// [ [ { email: 1 }, { unique: true, background: true } ],
// [ { registeredAt: 1 }, { background: true } ] ]
userSchema.indexes();

```
 [Plugins](../plugins) can use the return value of this function to modify a schema's indexes. For example, the below plugin makes every index unique by default.

 
```
function myPlugin(schema) {
  for (const index of schema.indexes()) {
    if (index[1].unique === undefined) {
      index[1].unique = true;
    }
  }
}

```
 
### Schema.prototype.loadClass()


##### Parameters:


* `model` «Function» The Class to load
* `[virtualsOnly]` «Boolean» if truthy, only pulls virtuals from the class, not methods or statics



Loads an ES6 class into a schema. Maps [setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) + [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get), [static methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static), and [instance methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Class_body_and_method_definitions) to schema [virtuals](../guide#virtuals), [statics](../guide#statics), and [methods](../guide#methods).

 ####   [Example:](#example)

 
```
const md5 = require('md5');
const userSchema = new Schema({ email: String });
class UserClass {
  // `gravatarImage` becomes a virtual
  get gravatarImage() {
    const hash = md5(this.email.toLowerCase());
    return `https://www.gravatar.com/avatar/${hash}`;
  }

  // `getProfileUrl()` becomes a document method
  getProfileUrl() {
    return `https://mysite.com/${this.email}`;
  }

  // `findByEmail()` becomes a static
  static findByEmail(email) {
    return this.findOne({ email });
  }
}

// `schema` will now have a `gravatarImage` virtual, a `getProfileUrl()` method,
// and a `findByEmail()` static
userSchema.loadClass(UserClass);

```
 
### Schema.prototype.method()


##### Parameters:


* `name` «String|Object» The Method Name for a single function, or a Object of "string-function" pairs.
* `[fn]` «Function» The Function in a single-function definition.



Adds an instance method to documents constructed from Models compiled from this schema.

 ####   [Example:](#example)

 
```
const schema = kittySchema = new Schema(..);

schema.method('meow', function () {
  console.log('meeeeeoooooooooooow');
})

const Kitty = mongoose.model('Kitty', schema);

const fizz = new Kitty;
fizz.meow(); // meeeeeooooooooooooow

```
 If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as methods.

 
```
schema.method({
    purr: function () {}
  , scratch: function () {}
});

// later
const fizz = new Kitty;
fizz.purr();
fizz.scratch();

```
 NOTE: `Schema.method()` adds instance methods to the `Schema.methods` object. You can also add instance methods directly to the `Schema.methods` object as seen in the [guide](../guide#methods)

 
### Schema.prototype.obj


##### Type:


* «property»



The original object passed to the schema constructor

 ####   [Example:](#example)

 
```
const schema = new Schema({ a: String }).add({ b: String });
schema.obj; // { a: String }

```
 
### Schema.prototype.omit()


##### Parameters:


* `paths` «Array[String]» List of Paths to omit for the new Schema
* `[options]` «Object» Options to pass to the new Schema Constructor (same as `new Schema(.., Options)`). Defaults to `this.options` if not set.


##### Returns:


* «Schema»



Returns a new schema that has the `paths` from the original schema, minus the omitted ones.

 This method is analagous to [Lodash's `omit()` function](https://lodash.com/docs/#omit) for Mongoose schemas.

 ####   [Example:](#example)

 
```
const schema = Schema({ name: String, age: Number });
// Creates a new schema omitting the `age` path
const newSchema = schema.omit(['age']);

newSchema.path('name'); // SchemaString { ... }
newSchema.path('age'); // undefined

```
 
### Schema.prototype.path()


##### Parameters:


* `path` «String» The name of the Path to get / set
* `[obj]` «Object» The Type to set the path to, if provided the path will be SET, otherwise the path will be GET



Gets/sets schema paths.

 Sets a path (if arity 2) Gets a path (if arity 1)

 ####   [Example:](#example)

 
```
schema.path('name') // returns a SchemaType
schema.path('name', Number) // changes the schemaType of `name` to Number

```
 
### Schema.prototype.pathType()


##### Parameters:


* `path` «String»


##### Returns:


* «String»



Returns the pathType of `path` for this schema.

 Given a path, returns whether it is a real, virtual, nested, or ad-hoc/undefined path.

 ####   [Example:](#example)

 
```
const s = new Schema({ name: String, nested: { foo: String } });
s.virtual('foo').get(() => 42);
s.pathType('name'); // "real"
s.pathType('nested'); // "nested"
s.pathType('foo'); // "virtual"
s.pathType('fail'); // "adhocOrUndefined"

```
 
### Schema.prototype.paths


##### Type:


* «property»



The paths defined on this schema. The keys are the top-level paths in this schema, and the values are instances of the SchemaType class.

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: String }, { \_id: false });
schema.paths; // { name: SchemaString { ... } }

schema.add({ age: Number });
schema.paths; // { name: SchemaString { ... }, age: SchemaNumber { ... } }

```
 
### Schema.prototype.pick()


##### Parameters:


* `paths` «Array[String]» List of Paths to pick for the new Schema
* `[options]` «Object» Options to pass to the new Schema Constructor (same as `new Schema(.., Options)`). Defaults to `this.options` if not set.


##### Returns:


* «Schema»



Returns a new schema that has the picked `paths` from this schema.

 This method is analagous to [Lodash's `pick()` function](https://lodash.com/docs/4.17.15#pick) for Mongoose schemas.

 ####   [Example:](#example)

 
```
const schema = Schema({ name: String, age: Number });
// Creates a new schema with the same `name` path as `schema`,
// but no `age` path.
const newSchema = schema.pick(['name']);

newSchema.path('name'); // SchemaString { ... }
newSchema.path('age'); // undefined

```
 
### Schema.prototype.plugin()


##### Parameters:


* `plugin` «Function» The Plugin's callback
* `[opts]` «Object» Options to pass to the plugin
+ `[opts.deduplicate=false]` «Boolean» If true, ignore duplicate plugins (same `fn` argument using `===`)


##### See:


* [plugins](../plugins)



Registers a plugin for this schema.

 ####   [Example:](#example)

 
```
const s = new Schema({ name: String });
s.plugin(schema => console.log(schema.path('name').path));
mongoose.model('Test', s); // Prints 'name'

```
 Or with Options:

 
```
const s = new Schema({ name: String });
s.plugin((schema, opts) => console.log(opts.text, schema.path('name').path), { text: "Schema Path Name:" });
mongoose.model('Test', s); // Prints 'Schema Path Name: name'

```
 
### Schema.prototype.post()


##### Parameters:


* `methodName` «String|RegExp|Array[String]» The method name or regular expression to match method name
* `[options]` «Object»
+ `[options.document]` «Boolean» If `name` is a hook for both document and query middleware, set to `true` to run on document middleware.
+ `[options.query]` «Boolean» If `name` is a hook for both document and query middleware, set to `true` to run on query middleware.

* `fn` «Function» callback


##### See:


* [middleware](../middleware)
* [kareem](https://npmjs.org/package/kareem)



Defines a post hook for the document

 
```
const schema = new Schema(..);
schema.post('save', function (doc) {
  console.log('this fired after a document was saved');
});

schema.post('find', function(docs) {
  console.log('this fired after you ran a find query');
});

schema.post(/Many$/, function(res) {
  console.log('this fired after you ran `updateMany()` or `deleteMany()`');
});

const Model = mongoose.model('Model', schema);

const m = new Model(..);
m.save(function(err) {
  console.log('this fires after the `post` hook');
});

m.find(function(err, docs) {
  console.log('this fires after the post find hook');
});

```
 
### Schema.prototype.pre()


##### Parameters:


* `methodName` «String|RegExp|Array[String]» The method name or regular expression to match method name
* `[options]` «Object»
+ `[options.document]` «Boolean» If `name` is a hook for both document and query middleware, set to `true` to run on document middleware. For example, set `options.document` to `true` to apply this hook to `Document#deleteOne()` rather than `Query#deleteOne()`.
+ `[options.query]` «Boolean» If `name` is a hook for both document and query middleware, set to `true` to run on query middleware.

* `callback` «Function»



Defines a pre hook for the model.

 ####   [Example:](#example)

 
```
const toySchema = new Schema({ name: String, created: Date });

toySchema.pre('save', function(next) {
  if (!this.created) this.created = new Date;
  next();
});

toySchema.pre('validate', function(next) {
  if (this.name !== 'Woody') this.name = 'Woody';
  next();
});

// Equivalent to calling `pre()` on `find`, `findOne`, `findOneAndUpdate`.
toySchema.pre(/^find/, function(next) {
  console.log(this.getFilter());
});

// Equivalent to calling `pre()` on `updateOne`, `findOneAndUpdate`.
toySchema.pre(['updateOne', 'findOneAndUpdate'], function(next) {
  console.log(this.getFilter());
});

toySchema.pre('deleteOne', function() {
  // Runs when you call `Toy.deleteOne()`
});

toySchema.pre('deleteOne', { document: true }, function() {
  // Runs when you call `doc.deleteOne()`
});

```
 
### Schema.prototype.queue()


##### Parameters:


* `name` «String» name of the document method to call later
* `args` «Array» arguments to pass to the method



Adds a method call to the queue.

 ####   [Example:](#example)

 
```
schema.methods.print = function() { console.log(this); };
schema.queue('print', []); // Print the doc every one is instantiated

const Model = mongoose.model('Test', schema);
new Model({ name: 'test' }); // Prints '{"\_id": ..., "name": "test" }'

```
 
### Schema.prototype.remove()


##### Parameters:


* `path` «String|Array» The Path(s) to remove


##### Returns:


* «Schema» the Schema instance



Removes the given `path` (or [`paths`]).

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: String, age: Number });
schema.remove('name');
schema.path('name'); // Undefined
schema.path('age'); // SchemaNumber { ... }

```
 Or as a Array:

 
```
schema.remove(['name', 'age']);
schema.path('name'); // Undefined
schema.path('age'); // Undefined

```
 
### Schema.prototype.removeIndex()


##### Parameters:


* `index` «Object|string» name or index specification


##### Returns:


* «Schema» the Schema instance



Remove an index by name or index specification.

 removeIndex only removes indexes from your schema object. Does **not** affect the indexes in MongoDB.

 ####   [Example:](#example)

 
```
const ToySchema = new Schema({ name: String, color: String, price: Number });

// Add a new index on { name, color }
ToySchema.index({ name: 1, color: 1 });

// Remove index on { name, color }
// Keep in mind that order matters! `removeIndex({ color: 1, name: 1 })` won't remove the index
ToySchema.removeIndex({ name: 1, color: 1 });

// Add an index with a custom name
ToySchema.index({ color: 1 }, { name: 'my custom index name' });
// Remove index by name
ToySchema.removeIndex('my custom index name');

```
 
### Schema.prototype.removeVirtual()


##### Parameters:


* `path` «String|Array» The virutal path(s) to remove.



Removes the given virtual or virtuals from the schema.

 
### Schema.prototype.requiredPaths()


##### Parameters:


* `invalidate` «Boolean» Refresh the cache


##### Returns:


* «Array»



Returns an Array of path strings that are required by this schema.

 ####   [Example:](#example)

 
```
const s = new Schema({
  name: { type: String, required: true },
  age: { type: String, required: true },
  notes: String
});
s.requiredPaths(); // [ 'age', 'name' ]

```
 
### Schema.prototype.set()


##### Parameters:


* `key` «String» The name of the option to set the value to
* `[value]` «Object» The value to set the option to, if not passed, the option will be reset to default
* `[tags]` «Array<string>» tags to add to read preference if key === 'read'


##### See:


* [Schema](#Schema())



Sets a schema option.

 ####   [Example:](#example)

 
```
schema.set('strict'); // 'true' by default
schema.set('strict', false); // Sets 'strict' to false
schema.set('strict'); // 'false'

```
 
### Schema.prototype.static()


##### Parameters:


* `name` «String|Object» The Method Name for a single function, or a Object of "string-function" pairs.
* `[fn]` «Function» The Function in a single-function definition.


##### See:


* [Statics](../guide#statics)



Adds static "class" methods to Models compiled from this schema.

 ####   [Example:](#example)

 
```
const schema = new Schema(..);
// Equivalent to `schema.statics.findByName = function(name) {}`;
schema.static('findByName', function(name) {
  return this.find({ name: name });
});

const Drink = mongoose.model('Drink', schema);
await Drink.findByName('LaCroix');

```
 If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as methods.

 
```
schema.static({
    findByName: function () {..}
  , findByCost: function () {..}
});

const Drink = mongoose.model('Drink', schema);
await Drink.findByName('LaCroix');
await Drink.findByCost(3);

```
 If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as statics.

 
### Schema.prototype.virtual()


##### Parameters:


* `name` «String» The name of the Virtual
* `[options]` «Object»
+ `[options.ref]` «String|Model» model name or model instance. Marks this as a [populate virtual](../populate#populate-virtuals).
+ `[options.localField]` «String|Function» Required for populate virtuals. See [populate virtual docs](../populate#populate-virtuals) for more information.
+ `[options.foreignField]` «String|Function» Required for populate virtuals. See [populate virtual docs](../populate#populate-virtuals) for more information.
+ `[options.justOne=false]` «Boolean|Function» Only works with populate virtuals. If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), will be a single doc or `null`. Otherwise, the populate virtual will be an array.
+ `[options.count=false]` «Boolean» Only works with populate virtuals. If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), this populate virtual will contain the number of documents rather than the documents themselves when you `populate()`.
+ `[options.get=null]` «Function|null» Adds a [getter](../tutorials/getters-setters) to this virtual to transform the populated doc.
+ `[options.match=null]` «Object|Function» Apply a default [`match` option to populate](../populate#match), adding an additional filter to the populate query.


##### Returns:


* «VirtualType»



Creates a virtual type with the given name.

 
### Schema.prototype.virtualpath()


##### Parameters:


* `name` «String» The name of the Virtual to get


##### Returns:


* «VirtualType,null»



Returns the virtual type with the given `name`.

 
### Schema.prototype.virtuals


##### Type:


* «property»



Object containing all virtuals defined on this schema. The objects' keys are the virtual paths and values are instances of `VirtualType`.

 This property is typically only useful for plugin authors and advanced users. You do not need to interact with this property at all to use mongoose.

 ####   [Example:](#example)

 
```
const schema = new Schema({});
schema.virtual('answer').get(() => 42);

console.log(schema.virtuals); // { answer: VirtualType { path: 'answer', ... } }
console.log(schema.virtuals['answer'].getters[0].call()); // 42

```
 
### Schema.reserved


##### Type:


* «property»



Reserved document keys.

 Keys in this object are names that are warned in schema declarations because they have the potential to break Mongoose/ Mongoose plugins functionality. If you create a schema using `new Schema()` with one of these property names, Mongoose will log a warning.

 * \_posts
* \_pres
* collection
* emit
* errors
* get
* init
* isModified
* isNew
* listeners
* modelName
* on
* once
* populated
* prototype
* remove
* removeListener
* save
* schema
* toObject
* validate

 *NOTE:* Use of these terms as method names is permitted, but play at your own risk, as they may be existing mongoose document methods you are stomping on.

 
```
 const schema = new Schema(..);
 schema.methods.init = function () {} // potentially breaking

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schema.html>

Connection
==========



### Connection()


##### Parameters:


* `base` «Mongoose» a mongoose instance


##### Inherits:


* [«NodeJS EventEmitter»](https://nodejs.org/api/events.html#class-eventemitter)



Connection constructor

 For practical reasons, a Connection equals a Db.

 
### Connection.prototype.asPromise()


##### Returns:


* «Promise»



Returns a promise that resolves when this connection successfully connects to MongoDB, or rejects if this connection failed to connect.

 ####   [Example:](#example)

 
```
const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/test').
  asPromise();
conn.readyState; // 1, means Mongoose is connected

```
 
### Connection.prototype.client


##### Type:


* «property»



The MongoClient instance this connection uses to talk to MongoDB. Mongoose automatically sets this property when the connection is opened.

 
### Connection.prototype.close()


##### Parameters:


* `[force]` «Boolean» optional


##### Returns:


* «Promise»



Closes the connection

 
### Connection.prototype.collection()


##### Parameters:


* `name` «String» of the collection
* `[options]` «Object» optional collection options


##### Returns:


* «Collection» collection instance



Retrieves a raw collection instance, creating it if not cached. This method returns a thin wrapper around a [MongoDB Node.js driver collection]([MongoDB Node.js driver collection](https://mongodb.github.io/node-mongodb-native/Next/classes/Collection.html)). Using a Collection bypasses Mongoose middleware, validation, and casting, letting you use [MongoDB Node.js driver](https://mongodb.github.io/node-mongodb-native/) functionality directly.

 
### Connection.prototype.collections


##### Type:


* «property»



A hash of the collections associated with this connection

 
### Connection.prototype.config


##### Type:


* «property»



A hash of the global options that are associated with this connection

 
### Connection.prototype.createCollection()


##### Parameters:


* `collection` «string» The collection to create
* `[options]` «Object» see [MongoDB driver docs](https://mongodb.github.io/node-mongodb-native/4.9/classes/Db.html#createCollection)


##### Returns:


* «Promise»



Helper for `createCollection()`. Will explicitly create the given collection with specified options. Used to create [capped collections](https://www.mongodb.com/docs/manual/core/capped-collections/) and [views](https://www.mongodb.com/docs/manual/core/views/) from mongoose.

 Options are passed down without modification to the [MongoDB driver's `createCollection()` function](https://mongodb.github.io/node-mongodb-native/4.9/classes/Db.html#createCollection)

 
### Connection.prototype.createCollections()


##### Parameters:


* `continueOnError` «Boolean» When true, will continue to create collections and create a new error class for the collections that errored.



Calls `createCollection()` on a models in a series.

 
### Connection.prototype.db


##### Type:


* «property»



The mongodb.Db instance, set when the connection is opened

 
### Connection.prototype.deleteModel()


##### Parameters:


* `name` «String|RegExp» if string, the name of the model to remove. If regexp, removes all models whose name matches the regexp.


##### Returns:


* «Connection» this



Removes the model named `name` from this connection, if it exists. You can use this function to clean up any models you created in your tests to prevent OverwriteModelErrors.

 ####   [Example:](#example)

 
```
conn.model('User', new Schema({ name: String }));
console.log(conn.model('User')); // Model object
conn.deleteModel('User');
console.log(conn.model('User')); // undefined

// Usually useful in a Mocha `afterEach()` hook
afterEach(function() {
  conn.deleteModel(/.+/); // Delete every model
});

```
 
### Connection.prototype.destroy()


##### Parameters:


* `[force]` «Boolean»



Destroy the connection. Similar to [`.close`](#Connection.prototype.close()), but also removes the connection from Mongoose's `connections` list and prevents the connection from ever being re-opened.

 
### Connection.prototype.dropCollection()


##### Parameters:


* `collection` «string» The collection to delete


##### Returns:


* «Promise»



Helper for `dropCollection()`. Will delete the given collection, including all documents and indexes.

 
### Connection.prototype.dropDatabase()


##### Returns:


* «Promise»



Helper for `dropDatabase()`. Deletes the given database, including all collections, documents, and indexes.

 ####   [Example:](#example)

 
```
const conn = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb');
// Deletes the entire 'mydb' database
await conn.dropDatabase();

```
 
### Connection.prototype.get()


##### Parameters:


* `key` «String»



Gets the value of the option `key`. Equivalent to `conn.options[key]`

 ####   [Example:](#example)

 
```
conn.get('test'); // returns the 'test' value

```
 
### Connection.prototype.getClient()


##### Returns:


* «MongoClient»



Returns the [MongoDB driver `MongoClient`](https://mongodb.github.io/node-mongodb-native/4.9/classes/MongoClient.html) instance that this connection uses to talk to MongoDB.

 ####   [Example:](#example)

 
```
const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/test').
  asPromise();

conn.getClient(); // MongoClient { ... }

```
 
### Connection.prototype.host


##### Type:


* «property»



The host name portion of the URI. If multiple hosts, such as a replica set, this will contain the first host name in the URI

 ####   [Example:](#example)

 
```
mongoose.createConnection('mongodb://127.0.0.1:27017/mydb').host; // "127.0.0.1"

```
 
### Connection.prototype.id


##### Type:


* «property»



A number identifier for this connection. Used for debugging when you have [multiple connections](../connections#multiple_connections).

 ####   [Example:](#example)

 
```
// The default connection has `id = 0`
mongoose.connection.id; // 0

// If you create a new connection, Mongoose increments id
const conn = mongoose.createConnection();
conn.id; // 1

```
 
### Connection.prototype.model()


##### Parameters:


* `name` «String|Function» the model name or class extending Model
* `[schema]` «Schema» a schema. necessary when defining a model
* `[collection]` «String» name of mongodb collection (optional) if not given it will be induced from model name
* `[options]` «Object»
+ `[options.overwriteModels=false]` «Boolean» If true, overwrite existing models with the same name to avoid `OverwriteModelError`


##### Returns:


* «Model» The compiled model


##### See:


* [Mongoose#model](mongoose#Mongoose.prototype.model())



Defines or retrieves a model.

 
```
const mongoose = require('mongoose');
const db = mongoose.createConnection(..);
db.model('Venue', new Schema(..));
const Ticket = db.model('Ticket', new Schema(..));
const Venue = db.model('Venue');

```
 *When no `collection` argument is passed, Mongoose produces a collection name by passing the model `name` to the `utils.toCollectionName` method. This method pluralizes the name. If you don't like this behavior, either pass a collection name or set your schemas collection name option.*

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: String }, { collection: 'actor' });

// or

schema.set('collection', 'actor');

// or

const collectionName = 'actor'
const M = conn.model('Actor', schema, collectionName)

```
 
### Connection.prototype.modelNames()


##### Returns:


* «Array[String]»



Returns an array of model names created on this connection.

 
### Connection.prototype.models


##### Type:


* «property»



A [POJO](https://masteringjs.io/tutorials/fundamentals/pojo) containing a map from model names to models. Contains all models that have been added to this connection using [`Connection#model()`](#Connection.prototype.model()).

 ####   [Example:](#example)

 
```
const conn = mongoose.createConnection();
const Test = conn.model('Test', mongoose.Schema({ name: String }));

Object.keys(conn.models).length; // 1
conn.models.Test === Test; // true

```
 
### Connection.prototype.name


##### Type:


* «property»



The name of the database this connection points to.

 ####   [Example:](#example)

 
```
mongoose.createConnection('mongodb://127.0.0.1:27017/mydb').name; // "mydb"

```
 
### Connection.prototype.openUri()


##### Parameters:


* `uri` «String» The URI to connect with.
* `[options]` «Object» Passed on to [`MongoClient.connect`](https://mongodb.github.io/node-mongodb-native/4.9/classes/MongoClient.html#connect-1)
+ `[options.bufferCommands=true]` «Boolean» Mongoose specific option. Set to false to [disable buffering](https://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
+ `[options.bufferTimeoutMS=10000]` «Number» Mongoose specific option. If `bufferCommands` is true, Mongoose will throw an error after `bufferTimeoutMS` if the operation is still buffered.
+ `[options.dbName]` «String» The name of the database we want to use. If not provided, use database name from connection string.
+ `[options.user]` «String» username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
+ `[options.pass]` «String» password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
+ `[options.maxPoolSize=100]` «Number» The maximum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
+ `[options.minPoolSize=0]` «Number» The minimum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
+ `[options.serverSelectionTimeoutMS]` «Number» If `useUnifiedTopology = true`, the MongoDB driver will try to find a server to send any given operation to, and keep retrying for `serverSelectionTimeoutMS` milliseconds before erroring out. If not set, the MongoDB driver defaults to using `30000` (30 seconds).
+ `[options.heartbeatFrequencyMS]` «Number» If `useUnifiedTopology = true`, 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.
+ `[options.autoIndex=true]` «Boolean» Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
+ `[options.promiseLibrary]` «Class» Sets the [underlying driver's promise library](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html#promiseLibrary).
+ `[options.socketTimeoutMS=0]` «Number» How long the MongoDB driver will wait before killing a socket due to inactivity *after initial connection*. A socket may be inactive because of either no activity or a long-running operation. `socketTimeoutMS` defaults to 0, which means Node.js will not time out the socket due to inactivity. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
+ `[options.family=0]` «Number» Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0,` 4`, or` 6`.` 4`means use IPv4 only,`6`means use IPv6 only,`0` means try both.
+ `[options.autoCreate=false]` «Boolean» Set to `true` to make Mongoose automatically call `createCollection()` on every model created on this connection.



Opens the connection with a URI using `MongoClient.connect()`.

 
### Connection.prototype.pass


##### Type:


* «property»



The password specified in the URI

 ####   [Example:](#example)

 
```
mongoose.createConnection('mongodb://val:psw@127.0.0.1:27017/mydb').pass; // "psw"

```
 
### Connection.prototype.plugin()


##### Parameters:


* `fn` «Function» plugin callback
* `[opts]` «Object» optional options


##### Returns:


* «Connection» this


##### See:


* [plugins](../plugins)



Declares a plugin executed on all schemas you pass to `conn.model()`

 Equivalent to calling `.plugin(fn)` on each schema you create.

 ####   [Example:](#example)

 
```
const db = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb');
db.plugin(() => console.log('Applied'));
db.plugins.length; // 1

db.model('Test', new Schema({})); // Prints "Applied"

```
 
### Connection.prototype.plugins


##### Type:


* «property»



The plugins that will be applied to all models created on this connection.

 ####   [Example:](#example)

 
```
const db = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb');
db.plugin(() => console.log('Applied'));
db.plugins.length; // 1

db.model('Test', new Schema({})); // Prints "Applied"

```
 
### Connection.prototype.port


##### Type:


* «property»



The port portion of the URI. If multiple hosts, such as a replica set, this will contain the port from the first host name in the URI.

 ####   [Example:](#example)

 
```
mongoose.createConnection('mongodb://127.0.0.1:27017/mydb').port; // 27017

```
 
### Connection.prototype.readyState


##### Type:


* «property»



Connection ready state

 * 0 = disconnected
* 1 = connected
* 2 = connecting
* 3 = disconnecting

 Each state change emits its associated event name.

 ####   [Example:](#example)

 
```
conn.on('connected', callback);
conn.on('disconnected', callback);

```
 
### Connection.prototype.removeDb()


##### Parameters:


* `name` «String» The database name


##### Returns:


* «Connection» this



Removes the database connection with the given name created with with `useDb()`.

 Throws an error if the database connection was not found.

 ####   [Example:](#example)

 
```
// Connect to `initialdb` first
const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/initialdb').asPromise();

// Creates an un-cached connection to `mydb`
const db = conn.useDb('mydb');

// Closes `db`, and removes `db` from `conn.relatedDbs` and `conn.otherDbs`
await conn.removeDb('mydb');

```
 
### Connection.prototype.set()


##### Parameters:


* `key` «String»
* `val` «Any»



Sets the value of the option `key`. Equivalent to `conn.options[key] = val`

 Supported options include:

 * `maxTimeMS`: Set [`maxTimeMS`](query#Query.prototype.maxTimeMS()) for all queries on this connection.
* 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arugments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.

 ####   [Example:](#example)

 
```
conn.set('test', 'foo');
conn.get('test'); // 'foo'
conn.options.test; // 'foo'

```
 
### Connection.prototype.setClient()


##### Parameters:


* `client` «MongClient» The Client to set to be used.


##### Returns:


* «Connection» this



Set the [MongoDB driver `MongoClient`](https://mongodb.github.io/node-mongodb-native/4.9/classes/MongoClient.html) instance that this connection uses to talk to MongoDB. This is useful if you already have a MongoClient instance, and want to reuse it.

 ####   [Example:](#example)

 
```
const client = await mongodb.MongoClient.connect('mongodb://127.0.0.1:27017/test');

const conn = mongoose.createConnection().setClient(client);

conn.getClient(); // MongoClient { ... }
conn.readyState; // 1, means 'CONNECTED'

```
 
### Connection.prototype.startSession()


##### Parameters:


* `[options]` «Object» see the [mongodb driver options](https://mongodb.github.io/node-mongodb-native/4.9/classes/MongoClient.html#startSession)
+ `[options.causalConsistency=true]` «Boolean» set to false to disable causal consistency


##### Returns:


* «Promise<ClientSession>» promise that resolves to a MongoDB driver `ClientSession`



*Requires MongoDB >= 3.6.0.* Starts a [MongoDB session](https://www.mongodb.com/docs/manual/release-notes/3.6/#client-sessions) for benefits like causal consistency, [retryable writes](https://www.mongodb.com/docs/manual/core/retryable-writes/), and [transactions](https://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html).

 ####   [Example:](#example)

 
```
const session = await conn.startSession();
let doc = await Person.findOne({ name: 'Ned Stark' }, null, { session });
await doc.remove();
// `doc` will always be null, even if reading from a replica set
// secondary. Without causal consistency, it is possible to
// get a doc back from the below query if the query reads from a
// secondary that is experiencing replication lag.
doc = await Person.findOne({ name: 'Ned Stark' }, null, { session, readPreference: 'secondary' });

```
 
### Connection.prototype.syncIndexes()


##### Parameters:


* `[options]` «Object»
+ `[options.continueOnError]` «Boolean» `false` by default. If set to `true`, mongoose will not throw an error if one model syncing failed, and will return an object where the keys are the names of the models, and the values are the results/errors for each model.


##### Returns:


* «Promise<Object>» Returns a Promise, when the Promise resolves the value is a list of the dropped indexes.



Syncs all the indexes for the models registered with this connection.

 
### Connection.prototype.transaction()


##### Parameters:


* `fn` «Function» Function to execute in a transaction
* `[options]` «[object Object]» Optional settings for the transaction


##### Returns:


* «Promise<Any>» promise that is fulfilled if Mongoose successfully committed the transaction, or rejects if the transaction was aborted or if Mongoose failed to commit the transaction. If fulfilled, the promise resolves to a MongoDB command result.



*Requires MongoDB >= 3.6.0.* Executes the wrapped async function in a transaction. Mongoose will commit the transaction if the async function executes successfully and attempt to retry if there was a retriable error.

 Calls the MongoDB driver's [`session.withTransaction()`](https://mongodb.github.io/node-mongodb-native/4.9/classes/ClientSession.html#withTransaction), but also handles resetting Mongoose document state as shown below.

 ####   [Example:](#example)

 
```
const doc = new Person({ name: 'Will Riker' });
await db.transaction(async function setRank(session) {
  doc.rank = 'Captain';
  await doc.save({ session });
  doc.isNew; // false

  // Throw an error to abort the transaction
  throw new Error('Oops!');
},{ readPreference: 'primary' }).catch(() => {});

// true, `transaction()` reset the document's state because the
// transaction was aborted.
doc.isNew;

```
 
### Connection.prototype.useDb()


##### Parameters:


* `name` «String» The database name
* `[options]` «Object»
+ `[options.useCache=false]` «Boolean» If true, cache results so calling `useDb()` multiple times with the same name only creates 1 connection object.
+ `[options.noListener=false]` «Boolean» If true, the connection object will not make the db listen to events on the original connection. See [issue #9961](https://github.com/Automattic/mongoose/issues/9961).


##### Returns:


* «Connection» New Connection Object



Switches to a different database using the same [connection pool](connectionshtml#connection_pools).

 Returns a new connection object, with the new db.

 ####   [Example:](#example)

 
```
// Connect to `initialdb` first
const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/initialdb').asPromise();

// Creates an un-cached connection to `mydb`
const db = conn.useDb('mydb');
// Creates a cached connection to `mydb2`. All calls to `conn.useDb('mydb2', { useCache: true })` will return the same
// connection instance as opposed to creating a new connection instance
const db2 = conn.useDb('mydb2', { useCache: true });

```
 
### Connection.prototype.user


##### Type:


* «property»



The username specified in the URI

 ####   [Example:](#example)

 
```
mongoose.createConnection('mongodb://val:psw@127.0.0.1:27017/mydb').user; // "val"

```
 
### Connection.prototype.watch()


##### Parameters:


* `[pipeline]` «Array»
* `[options]` «Object» passed without changes to [the MongoDB driver's `Db#watch()` function](https://mongodb.github.io/node-mongodb-native/4.9/classes/Db.html#watch)


##### Returns:


* «ChangeStream» mongoose-specific change stream wrapper, inherits from EventEmitter



Watches the entire underlying database for changes. Similar to [`Model.watch()`](model#Model.watch()).

 This function does **not** trigger any middleware. In particular, it does **not** trigger aggregate middleware.

 The ChangeStream object is an event emitter that emits the following events:

 * 'change': A change occurred, see below example
* 'error': An unrecoverable error occurred. In particular, change streams currently error out if they lose connection to the replica set primary. Follow [this GitHub issue](https://github.com/Automattic/mongoose/issues/6799) for updates.
* 'end': Emitted if the underlying stream is closed
* 'close': Emitted if the underlying stream is closed

 ####   [Example:](#example)

 
```
const User = conn.model('User', new Schema({ name: String }));

const changeStream = conn.watch().on('change', data => console.log(data));

// Triggers a 'change' event on the change stream.
await User.create({ name: 'test' });

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/connection.html>

Document
========



### Document.prototype.$assertPopulated()


##### Parameters:


* `path` «String|Array[String]» path or array of paths to check. `$assertPopulated` throws if any of the given paths is not populated.
* `[values]` «Object» optional values to `$set()`. Convenient if you want to manually populate a path and assert that the path was populated in 1 call.


##### Returns:


* «Document» this



Throws an error if a given path is not populated

 ####   [Example:](#example)

 
```
const doc = await Model.findOne().populate('author');

doc.$assertPopulated('author'); // does not throw
doc.$assertPopulated('other path'); // throws an error

// Manually populate and assert in one call. The following does
// `doc.$set({ likes })` before asserting.
doc.$assertPopulated('likes', { likes });

```
 
### Document.prototype.$clone()


##### Returns:


* «Document» a copy of this document



Returns a copy of this document with a deep clone of `_doc` and `$__`.

 
### Document.prototype.$errors


##### Type:


* «property»



Hash containing current validation $errors.

 
### Document.prototype.$getAllSubdocs()


##### Returns:


* «Array»



Get all subdocs (by bfs)

 
### Document.prototype.$getPopulatedDocs()


##### Returns:


* «Array[Document]» array of populated documents. Empty array if there are no populated documents associated with this document.



Gets all populated documents associated with this document.

 
### Document.prototype.$ignore()


##### Parameters:


* `path` «String» the path to ignore



Don't run validation on this path or persist changes to this path.

 ####   [Example:](#example)

 
```
doc.foo = null;
doc.$ignore('foo');
doc.save(); // changes to foo will not be persisted and validators won't be run

```
 
### Document.prototype.$inc()


##### Parameters:


* `path` «String|Array» path or paths to update
* `val` «Number» increment `path` by this value


##### Returns:


* «Document» this



Increments the numeric value at `path` by the given `val`. When you call `save()` on this document, Mongoose will send a [`$inc`](https://www.mongodb.com/docs/manual/reference/operator/update/inc/) as opposed to a `$set`.

 ####   [Example:](#example)

 
```
const schema = new Schema({ counter: Number });
const Test = db.model('Test', schema);

const doc = await Test.create({ counter: 0 });
doc.$inc('counter', 2);
await doc.save(); // Sends a `{ $inc: { counter: 2 } }` to MongoDB
doc.counter; // 2

doc.counter += 2;
await doc.save(); // Sends a `{ $set: { counter: 2 } }` to MongoDB

```
 
### Document.prototype.$init()



Alias for [`.init`](#Document.prototype.init())

 
### Document.prototype.$isDefault()


##### Parameters:


* `[path]` «String»


##### Returns:


* «Boolean»



Checks if a path is set to its default.

 ####   [Example:](#example)

 
```
MyModel = mongoose.model('test', { name: { type: String, default: 'Val '} });
const m = new MyModel();
m.$isDefault('name'); // true

```
 
### Document.prototype.$isDeleted()


##### Parameters:


* `[val]` «Boolean» optional, overrides whether mongoose thinks the doc is deleted


##### Returns:


* «Boolean,Document» whether mongoose thinks this doc is deleted.



Getter/setter, determines whether the document was removed or not.

 ####   [Example:](#example)

 
```
const product = await product.remove();
product.$isDeleted(); // true
product.remove(); // no-op, doesn't send anything to the db

product.$isDeleted(false);
product.$isDeleted(); // false
product.remove(); // will execute a remove against the db

```
 
### Document.prototype.$isEmpty()


##### Parameters:


* `[path]` «String»


##### Returns:


* «Boolean»



Returns true if the given path is nullish or only contains empty objects. Useful for determining whether this subdoc will get stripped out by the [minimize option](../guide#minimize).

 ####   [Example:](#example)

 
```
const schema = new Schema({ nested: { foo: String } });
const Model = mongoose.model('Test', schema);
const doc = new Model({});
doc.$isEmpty('nested'); // true
doc.nested.$isEmpty(); // true

doc.nested.foo = 'bar';
doc.$isEmpty('nested'); // false
doc.nested.$isEmpty(); // false

```
 
### Document.prototype.$isModified()



Alias of [`.isModified`](#Document.prototype.isModified())

 
### Document.prototype.$isNew


##### Type:


* «property»



Boolean flag specifying if the document is new. If you create a document using `new`, this document will be considered "new". `$isNew` is how Mongoose determines whether `save()` should use `insertOne()` to create a new document or `updateOne()` to update an existing document.

 ####   [Example:](#example)

 
```
const user = new User({ name: 'John Smith' });
user.$isNew; // true

await user.save(); // Sends an `insertOne` to MongoDB

```
 On the other hand, if you load an existing document from the database using `findOne()` or another [query operation](../queries), `$isNew` will be false.

 ####   [Example:](#example-1)

 
```
const user = await User.findOne({ name: 'John Smith' });
user.$isNew; // false

```
 Mongoose sets `$isNew` to `false` immediately after `save()` succeeds. That means Mongoose sets `$isNew` to false **before** `post('save')` hooks run. In `post('save')` hooks, `$isNew` will be `false` if `save()` succeeded.

 ####   [Example:](#example-2)

 
```
userSchema.post('save', function() {
  this.$isNew; // false
});
await User.create({ name: 'John Smith' });

```
 For subdocuments, `$isNew` is true if either the parent has `$isNew` set, or if you create a new subdocument.

 ####   [Example:](#example-3)

 
```
// Assume `Group` has a document array `users`
const group = await Group.findOne();
group.users[0].$isNew; // false

group.users.push({ name: 'John Smith' });
group.users[1].$isNew; // true

```
 
### Document.prototype.$locals


##### Type:


* «property»



Empty object that you can use for storing properties on the document. This is handy for passing data to middleware without conflicting with Mongoose internals.

 ####   [Example:](#example)

 
```
schema.pre('save', function() {
  // Mongoose will set `isNew` to `false` if `save()` succeeds
  this.$locals.wasNew = this.isNew;
});

schema.post('save', function() {
  // Prints true if `isNew` was set before `save()`
  console.log(this.$locals.wasNew);
});

```
 
### Document.prototype.$markValid()


##### Parameters:


* `path` «String» the field to mark as valid



Marks a path as valid, removing existing validation errors.

 
### Document.prototype.$op


##### Type:


* «property»



A string containing the current operation that Mongoose is executing on this document. May be `null`, `'save'`, `'validate'`, or `'remove'`.

 ####   [Example:](#example)

 
```
const doc = new Model({ name: 'test' });
doc.$op; // null

const promise = doc.save();
doc.$op; // 'save'

await promise;
doc.$op; // null

```
 
### Document.prototype.$parent()


##### Returns:


* «Document»



Alias for [`parent()`](#Document.prototype.parent()). If this document is a subdocument or populated document, returns the document's parent. Returns `undefined` otherwise.

 
### Document.prototype.$populated()



Alias of [`.populated`](#Document.prototype.populated()).

 
### Document.prototype.$session()


##### Parameters:


* `[session]` «ClientSession» overwrite the current session


##### Returns:


* «ClientSession»



Getter/setter around the session associated with this document. Used to automatically set `session` if you `save()` a doc that you got from a query with an associated session.

 ####   [Example:](#example)

 
```
const session = MyModel.startSession();
const doc = await MyModel.findOne().session(session);
doc.$session() === session; // true
doc.$session(null);
doc.$session() === null; // true

```
 If this is a top-level document, setting the session propagates to all child docs.

 
### Document.prototype.$set()


##### Parameters:


* `path` «String|Object» path or object of key/vals to set
* `val` «Any» the value to set
* `[type]` «Schema|String|Number|Buffer|[object Object]» optionally specify a type for "on-the-fly" attributes
* `[options]` «Object» optionally specify options that modify the behavior of the set
+ `[options.merge=false]` «Boolean» if true, setting a [nested path](../subdocs#subdocuments-versus-nested-paths) will merge existing values rather than overwrite the whole object. So `doc.set('nested', { a: 1, b: 2 })` becomes `doc.set('nested.a', 1); doc.set('nested.b', 2);`


##### Returns:


* «Document» this



Alias for `set()`, used internally to avoid conflicts

 
### Document.prototype.$timestamps()


##### Parameters:


* `[value]` «Boolean» overwrite the current session


##### Returns:


* «Document,boolean,undefined,void» When used as a getter (no argument), a boolean will be returned indicating the timestamps option state or if unset "undefined" will be used, otherwise will return "this"



Getter/setter around whether this document will apply timestamps by default when using `save()` and `bulkSave()`.

 ####   [Example:](#example)

 
```
const TestModel = mongoose.model('Test', new Schema({ name: String }, { timestamps: true }));
const doc = new TestModel({ name: 'John Smith' });

doc.$timestamps(); // true

doc.$timestamps(false);
await doc.save(); // Does \*\*not\*\* apply timestamps

```
 
### Document.prototype.$validate()



Alias of [`.validate`](#Document.prototype.validate())

 
### Document.prototype.$where


##### Type:


* «property»



Set this property to add additional query filters when Mongoose saves this document and `isNew` is false.

 ####   [Example:](#example)

 
```
// Make sure `save()` never updates a soft deleted document.
schema.pre('save', function() {
  this.$where = { isDeleted: false };
});

```
 
### Document.prototype.depopulate()


##### Parameters:


* `[path]` «String|Array[String]» Specific Path to depopulate. If unset, will depopulate all paths on the Document. Or multiple space-delimited paths.


##### Returns:


* «Document» this


##### See:


* [Document.populate](#Document.prototype.populate())



Takes a populated field and returns it to its unpopulated state.

 ####   [Example:](#example)

 
```
Model.findOne().populate('author').exec(function (err, doc) {
  console.log(doc.author.name); // Dr.Seuss
  console.log(doc.depopulate('author'));
  console.log(doc.author); // '5144cf8050f071d979c118a7'
})

```
 If the path was not provided, then all populated fields are returned to their unpopulated state.

 
### Document.prototype.directModifiedPaths()


##### Returns:


* «Array[String]»



Returns the list of paths that have been directly modified. A direct modified path is a path that you explicitly set, whether via `doc.foo = 'bar'`, `Object.assign(doc, { foo: 'bar' })`, or `doc.set('foo', 'bar')`.

 A path `a` may be in `modifiedPaths()` but not in `directModifiedPaths()` because a child of `a` was directly modified.

 ####   [Example:](#example)

 
```
const schema = new Schema({ foo: String, nested: { bar: String } });
const Model = mongoose.model('Test', schema);
await Model.create({ foo: 'original', nested: { bar: 'original' } });

const doc = await Model.findOne();
doc.nested.bar = 'modified';
doc.directModifiedPaths(); // ['nested.bar']
doc.modifiedPaths(); // ['nested', 'nested.bar']

```
 
### Document.prototype.equals()


##### Parameters:


* `[doc]` «Document» a document to compare. If falsy, will always return "false".


##### Returns:


* «Boolean»



Returns true if this document is equal to another document.

 Documents are considered equal when they have matching `_id`s, unless neither document has an `_id`, in which case this function falls back to using `deepEqual()`.

 
### Document.prototype.errors


##### Type:


* «property»



Hash containing current validation errors.

 
### Document.prototype.get()


##### Parameters:


* `path` «String»
* `[type]` «Schema|String|Number|Buffer|[object Object]» optionally specify a type for on-the-fly attributes
* `[options]` «Object»
+ `[options.virtuals=false]` «Boolean» Apply virtuals before getting this path
+ `[options.getters=true]` «Boolean» If false, skip applying getters and just get the raw value


##### Returns:


* «Any»



Returns the value of a path.

 ####   [Example:](#example)

 
```
// path
doc.get('age') // 47

// dynamic casting to a string
doc.get('age', String) // "47"

```
 
### Document.prototype.getChanges()


##### Returns:


* «Object»



Returns the changes that happened to the document in the format that will be sent to MongoDB.

 ####   [Example:](#example)

 
```
const userSchema = new Schema({
  name: String,
  age: Number,
  country: String
});
const User = mongoose.model('User', userSchema);
const user = await User.create({
  name: 'Hafez',
  age: 25,
  country: 'Egypt'
});

// returns an empty object, no changes happened yet
user.getChanges(); // { }

user.country = undefined;
user.age = 26;

user.getChanges(); // { $set: { age: 26 }, { $unset: { country: 1 } } }

await user.save();

user.getChanges(); // { }

```
 Modifying the object that `getChanges()` returns does not affect the document's change tracking state. Even if you `delete user.getChanges().$set`, Mongoose will still send a `$set` to the server.

 
### Document.prototype.id


##### Type:


* «property»


##### See:


* [Schema options](../guide#options)



The string version of this documents \_id.

 ####   [Note:](#note)

 This getter exists on all documents by default. The getter can be disabled by setting the `id` [option](../guide#id) of its `Schema` to false at construction time.

 
```
new Schema({ name: String }, { id: false });

```
 
### Document.prototype.init()


##### Parameters:


* `doc` «Object» document returned by mongo
* `[opts]` «Object»
* `[fn]` «Function»



Initializes the document without setters or marking anything modified.

 Called internally after a document is returned from mongodb. Normally, you do **not** need to call this function on your own.

 This function triggers `init` [middleware](../middleware). Note that `init` hooks are [synchronous](../middleware#synchronous).

 
### Document.prototype.inspect()


##### Returns:


* «String»



Helper for console.log

 
### Document.prototype.invalidate()


##### Parameters:


* `path` «String» the field to invalidate. For array elements, use the `array.i.field` syntax, where `i` is the 0-based index in the array.
* `err` «String|Error» the error which states the reason `path` was invalid
* `val` «Object|String|Number|any» optional invalid value
* `[kind]` «String» optional `kind` property for the error


##### Returns:


* «ValidationError» the current ValidationError, with all currently invalidated paths



Marks a path as invalid, causing validation to fail.

 The `errorMsg` argument will become the message of the `ValidationError`.

 The `value` argument (if passed) will be available through the `ValidationError.value` property.

 
```
doc.invalidate('size', 'must be less than 20', 14);

doc.validate(function (err) {
  console.log(err)
  // prints
  { message: 'Validation failed',
    name: 'ValidationError',
    errors:
     { size:
        { message: 'must be less than 20',
          name: 'ValidatorError',
          path: 'size',
          type: 'user defined',
          value: 14 } } }
})

```
 
### Document.prototype.isDirectModified()


##### Parameters:


* `[path]` «String|Array[String]»


##### Returns:


* «Boolean»



Returns true if `path` was directly set and modified, else false.

 ####   [Example:](#example)

 
```
doc.set('documents.0.title', 'changed');
doc.isDirectModified('documents.0.title') // true
doc.isDirectModified('documents') // false

```
 
### Document.prototype.isDirectSelected()


##### Parameters:


* `path` «String»


##### Returns:


* «Boolean»



Checks if `path` was explicitly selected. If no projection, always returns true.

 ####   [Example:](#example)

 
```
Thing.findOne().select('nested.name').exec(function (err, doc) {
   doc.isDirectSelected('nested.name') // true
   doc.isDirectSelected('nested.otherName') // false
   doc.isDirectSelected('nested')  // false
})

```
 
### Document.prototype.isInit()


##### Parameters:


* `[path]` «String»


##### Returns:


* «Boolean»



Checks if `path` is in the `init` state, that is, it was set by `Document#init()` and not modified since.

 
### Document.prototype.isModified()


##### Parameters:


* `[path]` «String» optional


##### Returns:


* «Boolean»



Returns true if any of the given paths is modified, else false. If no arguments, returns `true` if any path in this document is modified.

 If `path` is given, checks if a path or any full path containing `path` as part of its path chain has been modified.

 ####   [Example:](#example)

 
```
doc.set('documents.0.title', 'changed');
doc.isModified()                      // true
doc.isModified('documents')           // true
doc.isModified('documents.0.title')   // true
doc.isModified('documents otherProp') // true
doc.isDirectModified('documents')     // false

```
 
### Document.prototype.isNew


##### Type:


* «property»


##### See:


* [$isNew](#Document.prototype.$isNew)



Legacy alias for `$isNew`.

 
### Document.prototype.isSelected()


##### Parameters:


* `path` «String|Array[String]»


##### Returns:


* «Boolean»



Checks if `path` was selected in the source query which initialized this document.

 ####   [Example:](#example)

 
```
const doc = await Thing.findOne().select('name');
doc.isSelected('name') // true
doc.isSelected('age')  // false

```
 
### Document.prototype.markModified()


##### Parameters:


* `path` «String» the path to mark modified
* `[scope]` «Document» the scope to run validators with



Marks the path as having pending changes to write to the db.

 *Very helpful when using [Mixed](../schematypes#mixed) types.*

 ####   [Example:](#example)

 
```
doc.mixed.type = 'changed';
doc.markModified('mixed.type');
doc.save() // changes to mixed.type are now persisted

```
 
### Document.prototype.modifiedPaths()


##### Parameters:


* `[options]` «Object»
+ `[options.includeChildren=false]` «Boolean» if true, returns children of modified paths as well. For example, if false, the list of modified paths for `doc.colors = { primary: 'blue' };` will **not** contain `colors.primary`. If true, `modifiedPaths()` will return an array that contains `colors.primary`.


##### Returns:


* «Array[String]»



Returns the list of paths that have been modified.

 
### Document.prototype.overwrite()


##### Parameters:


* `obj` «Object» the object to overwrite this document with


##### Returns:


* «Document» this



Overwrite all values in this document with the values of `obj`, except for immutable properties. Behaves similarly to `set()`, except for it unsets all properties that aren't in `obj`.

 
### Document.prototype.parent()


##### Returns:


* «Document»



If this document is a subdocument or populated document, returns the document's parent. Returns the original document if there is no parent.

 
### Document.prototype.populate()


##### Parameters:


* `path` «String|Object|Array» either the path to populate or an object specifying all parameters, or either an array of those
* `[select]` «Object|String» Field selection for the population query
* `[model]` «Model» The model you wish to use for population. If not specified, populate will look up the model by the name in the Schema's `ref` field.
* `[match]` «Object» Conditions for the population query
* `[options]` «Object» Options for the population query (sort, etc)
+ `[options.path=null]` «String» The path to populate.
+ `[options.populate=null]` «string|PopulateOptions» Recursively populate paths in the populated documents. See [deep populate docs](../populate#deep-populate).
+ `[options.retainNullValues=false]` «boolean» by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
+ `[options.getters=false]` «boolean» if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](../schematypes#schematype-options).
+ `[options.clone=false]` «boolean» When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
+ `[options.match=null]` «Object|Function» Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/), or a function that returns a filter object.
+ `[options.transform=null]` «Function» Function that Mongoose will call on every populated document that allows you to transform the populated document.
+ `[options.options=null]` «Object» Additional options like `limit` and `lean`.

* `[callback]` «Function» Callback


##### Returns:


* «Promise,null» Returns a Promise if no `callback` is given.


##### See:


* [population](../populate)
* [Query#select](query#Query.prototype.select())
* [Model.populate](model#Model.populate())



Populates paths on an existing document.

 ####   [Example:](#example)

 
```
// Given a document, `populate()` lets you pull in referenced docs
await doc.populate([
  'stories',
  { path: 'fans', sort: { name: -1 } }
]);
doc.populated('stories'); // Array of ObjectIds
doc.stories[0].title; // 'Casino Royale'
doc.populated('fans'); // Array of ObjectIds

// If the referenced doc has been deleted, `populate()` will
// remove that entry from the array.
await Story.delete({ title: 'Casino Royale' });
await doc.populate('stories'); // Empty array

// You can also pass additional query options to `populate()`,
// like projections:
await doc.populate('fans', '-email');
doc.fans[0].email // undefined because of 2nd param `select`

```
 
### Document.prototype.populated()


##### Parameters:


* `path` «String»
* `[val]` «Any»
* `[options]` «Object»


##### Returns:


* «Array,ObjectId,Number,Buffer,String,undefined,void»



Gets \_id(s) used during population of the given `path`.

 ####   [Example:](#example)

 
```
const doc = await Model.findOne().populate('author');

console.log(doc.author.name); // Dr.Seuss
console.log(doc.populated('author')); // '5144cf8050f071d979c118a7'

```
 If the path was not populated, returns `undefined`.

 
### Document.prototype.replaceOne()


##### Parameters:


* `doc` «Object»
* `[options]` «Object»
* `[callback]` «Function»


##### Returns:


* «Query»


##### See:


* [Model.replaceOne](model#Model.replaceOne())



Sends a replaceOne command with this document `_id` as the query selector.

 ####   [Valid options:](#valid-options)

 * same as in [Model.replaceOne](model#Model.replaceOne())

 
### Document.prototype.save()


##### Parameters:


* `[options]` «Object» options optional options
+ `[options.session=null]` «Session» the [session](https://www.mongodb.com/docs/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](#Document.prototype.$session()).
+ `[options.safe]` «Object» (DEPRECATED) overrides [schema's safe option](../guide#safe). Use the `w` option instead.
+ `[options.validateBeforeSave]` «Boolean» set to false to save without validating.
+ `[options.validateModifiedOnly=false]` «Boolean» If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
+ `[options.w]` «Number|String» set the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/#w-option). Overrides the [schema-level `writeConcern` option](../guide#writeConcern)
+ `[options.j]` «Boolean» set to true for MongoDB to wait until this `save()` has been [journaled before resolving the returned promise](https://www.mongodb.com/docs/manual/reference/write-concern/#j-option). Overrides the [schema-level `writeConcern` option](../guide#writeConcern)
+ `[options.wtimeout]` «Number» sets a [timeout for the write concern](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](../guide#writeConcern).
+ `[options.checkKeys=true]` «Boolean» the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://www.mongodb.com/docs/manual/reference/limits/#Restrictions-on-Field-Names)
+ `[options.timestamps=true]` «Boolean» if `false` and [timestamps](../guide#timestamps) are enabled, skip timestamps for this `save()`.

* `[fn]` «Function» optional callback


##### Returns:


* «Promise,undefined,void» Returns undefined if used with callback or a Promise otherwise.


##### See:


* [middleware](../middleware)



Saves this document by inserting a new document into the database if [document.isNew](#Document.prototype.isNew()) is `true`, or sends an [updateOne](#Document.prototype.updateOne()) operation **only** with the modifications to the database, it does not replace the whole document in the latter case.

 ####   [Example:](#example)

 
```
product.sold = Date.now();
product = await product.save();

```
 If save is successful, the returned promise will fulfill with the document saved.

 ####   [Example:](#example-1)

 
```
const newProduct = await product.save();
newProduct === product; // true

```
 
### Document.prototype.schema


##### Type:


* «property»



The document's schema.

 
### Document.prototype.set()


##### Parameters:


* `path` «String|Object» path or object of key/vals to set
* `val` «Any» the value to set
* `[type]` «Schema|String|Number|Buffer|[object Object]» optionally specify a type for "on-the-fly" attributes
* `[options]` «Object» optionally specify options that modify the behavior of the set


##### Returns:


* «Document» this



Sets the value of a path, or many paths. Alias for [`.$set`](#Document.prototype.$set()).

 ####   [Example:](#example)

 
```
// path, value
doc.set(path, value)

// object
doc.set({
    path  : value
  , path2 : {
       path  : value
    }
})

// on-the-fly cast to number
doc.set(path, value, Number)

// on-the-fly cast to string
doc.set(path, value, String)

// changing strict mode behavior
doc.set(path, value, { strict: false });

```
 
### Document.prototype.toJSON()


##### Parameters:


* `options` «Object»
+ `[options.flattenMaps=true]` «Boolean» if true, convert Maps to [POJOs](https://masteringjs.io/tutorials/fundamentals/pojo). Useful if you want to `JSON.stringify()` the result.
+ `[options.flattenObjectIds=false]` «Boolean» if true, convert any ObjectIds in the result to 24 character hex strings.


##### Returns:


* «Object»


##### See:


* [Document#toObject](#Document.prototype.toObject())
* [JSON.stringify() in JavaScript](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html)



The return value of this method is used in calls to [`JSON.stringify(doc)`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript#the-tojson-function).

 This method accepts the same options as [Document#toObject](#Document.prototype.toObject()). To apply the options to every document of your schema by default, set your [schemas](schema#Schema()) `toJSON` option to the same argument.

 
```
schema.set('toJSON', { virtuals: true });

```
 There is one difference between `toJSON()` and `toObject()` options. When you call `toJSON()`, the [`flattenMaps` option](#Document.prototype.toObject()) defaults to `true`, because `JSON.stringify()` doesn't convert maps to objects by default. When you call `toObject()`, the `flattenMaps` option is `false` by default.

 See [schema options](../guide#toJSON) for more information on setting `toJSON` option defaults.

 
### Document.prototype.toObject()


##### Parameters:


* `[options]` «Object»
+ `[options.getters=false]` «Boolean» if true, apply all getters, including virtuals
+ `[options.virtuals=false]` «Boolean» if true, apply virtuals, including aliases. Use `{ getters: true, virtuals: false }` to just apply getters, not virtuals
+ `[options.aliases=true]` «Boolean» if `options.virtuals = true`, you can set `options.aliases = false` to skip applying aliases. This option is a no-op if `options.virtuals = false`.
+ `[options.minimize=true]` «Boolean» if true, omit any empty objects from the output
+ `[options.transform=null]` «Function|null» if set, mongoose will call this function to allow you to transform the returned object
+ `[options.depopulate=false]` «Boolean» if true, replace any conventionally populated paths with the original id in the output. Has no affect on virtual populated paths.
+ `[options.versionKey=true]` «Boolean» if false, exclude the version key (`__v` by default) from the output
+ `[options.flattenMaps=false]` «Boolean» if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`.
+ `[options.flattenObjectIds=false]` «Boolean» if true, convert any ObjectIds in the result to 24 character hex strings.
+ `[options.useProjection=false]` «Boolean»
	- If true, omits fields that are excluded in this document's projection. Unless you specified a projection, this will omit any field that has `select: false` in the schema.


##### Returns:


* «Object» js object (not a POJO)


##### See:


* [mongodb.Binary](https://mongodb.github.io/node-mongodb-native/4.9/classes/Binary.html)



Converts this document into a plain-old JavaScript object ([POJO](https://masteringjs.io/tutorials/fundamentals/pojo)).

 Buffers are converted to instances of [mongodb.Binary](https://mongodb.github.io/node-mongodb-native/4.9/classes/Binary.html) for proper storage.

 ####   [Getters/Virtuals](#gettersvirtuals)

 Example of only applying path getters

 
```
doc.toObject({ getters: true, virtuals: false })

```
 Example of only applying virtual getters

 
```
doc.toObject({ virtuals: true })

```
 Example of applying both path and virtual getters

 
```
doc.toObject({ getters: true })

```
 To apply these options to every document of your schema by default, set your [schemas](schema#Schema()) `toObject` option to the same argument.

 
```
schema.set('toObject', { virtuals: true })

```
 ####   [Transform:](#transform)

 We may need to perform a transformation of the resulting object based on some criteria, say to remove some sensitive information or return a custom object. In this case we set the optional `transform` function.

 Transform functions receive three arguments

 
```
function (doc, ret, options) {}

```
 * `doc` The mongoose document which is being converted
* `ret` The plain object representation which has been converted
* `options` The options in use (either schema options or the options passed inline)

 ####   [Example:](#example)

 
```
// specify the transform schema option
if (!schema.options.toObject) schema.options.toObject = {};
schema.options.toObject.transform = function (doc, ret, options) {
  // remove the \_id of every document before returning the result
  delete ret.\_id;
  return ret;
}

// without the transformation in the schema
doc.toObject(); // { \_id: 'anId', name: 'Wreck-it Ralph' }

// with the transformation
doc.toObject(); // { name: 'Wreck-it Ralph' }

```
 With transformations we can do a lot more than remove properties. We can even return completely new customized objects:

 
```
if (!schema.options.toObject) schema.options.toObject = {};
schema.options.toObject.transform = function (doc, ret, options) {
  return { movie: ret.name }
}

// without the transformation in the schema
doc.toObject(); // { \_id: 'anId', name: 'Wreck-it Ralph' }

// with the transformation
doc.toObject(); // { movie: 'Wreck-it Ralph' }

```
 *Note: if a transform function returns `undefined`, the return value will be ignored.*

 Transformations may also be applied inline, overridding any transform set in the options:

 
```
function xform (doc, ret, options) {
  return { inline: ret.name, custom: true }
}

// pass the transform as an inline option
doc.toObject({ transform: xform }); // { inline: 'Wreck-it Ralph', custom: true }

```
 If you want to skip transformations, use `transform: false`:

 
```
schema.options.toObject.hide = '\_id';
schema.options.toObject.transform = function (doc, ret, options) {
  if (options.hide) {
    options.hide.split(' ').forEach(function (prop) {
      delete ret[prop];
    });
  }
  return ret;
}

const doc = new Doc({ \_id: 'anId', secret: 47, name: 'Wreck-it Ralph' });
doc.toObject();                                        // { secret: 47, name: 'Wreck-it Ralph' }
doc.toObject({ hide: 'secret \_id', transform: false });// { \_id: 'anId', secret: 47, name: 'Wreck-it Ralph' }
doc.toObject({ hide: 'secret \_id', transform: true }); // { name: 'Wreck-it Ralph' }

```
 If you pass a transform in `toObject()` options, Mongoose will apply the transform to [subdocuments](../subdocs) in addition to the top-level document. Similarly, `transform: false` skips transforms for all subdocuments. Note that this behavior is different for transforms defined in the schema: if you define a transform in `schema.options.toObject.transform`, that transform will **not** apply to subdocuments.

 
```
const memberSchema = new Schema({ name: String, email: String });
const groupSchema = new Schema({ members: [memberSchema], name: String, email });
const Group = mongoose.model('Group', groupSchema);

const doc = new Group({
  name: 'Engineering',
  email: 'dev@mongoosejs.io',
  members: [{ name: 'Val', email: 'val@mongoosejs.io' }]
});

// Removes `email` from both top-level document \*\*and\*\* array elements
// { name: 'Engineering', members: [{ name: 'Val' }] }
doc.toObject({ transform: (doc, ret) => { delete ret.email; return ret; } });

```
 Transforms, like all of these options, are also available for `toJSON`. See [this guide to `JSON.stringify()`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html) to learn why `toJSON()` and `toObject()` are separate functions.

 See [schema options](../guide#toObject) for some more details.

 *During save, no custom options are applied to the document before being sent to the database.*

 
### Document.prototype.toString()


##### Returns:


* «String»



Helper for console.log

 
### Document.prototype.unmarkModified()


##### Parameters:


* `path` «String» the path to unmark modified



Clears the modified state on the specified path.

 ####   [Example:](#example)

 
```
doc.foo = 'bar';
doc.unmarkModified('foo');
doc.save(); // changes to foo will not be persisted

```
 
### Document.prototype.updateOne()


##### Parameters:


* `doc` «Object»
* `[options]` «Object» optional see [`Query.prototype.setOptions()`](query#Query.prototype.setOptions())
+ `[options.lean]` «Object» if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](query#Query.prototype.lean()) and the [Mongoose lean tutorial](../tutorials/lean).
+ `[options.strict]` «Boolean|String» overwrites the schema's [strict mode option](../guide#strict)
+ `[options.timestamps=null]` «Boolean» If set to `false` and [schema-level timestamps](../guide#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.

* `[callback]` «Function»


##### Returns:


* «Query»


##### See:


* [Model.updateOne](model#Model.updateOne)



Sends an updateOne command with this document `_id` as the query selector.

 ####   [Example:](#example)

 
```
weirdCar.updateOne({$inc: {wheels:1}}, { w: 1 }, callback);

```
 ####   [Valid options:](#valid-options)

 * same as in [Model.updateOne](model#Model.updateOne)

 
### Document.prototype.validate()


##### Parameters:


* `[pathsToValidate]` «Array|String» list of paths to validate. If set, Mongoose will validate only the modified paths that are in the given list.
* `[options]` «Object» internal options
+ `[options.validateModifiedOnly=false]` «Boolean» if `true` mongoose validates only modified paths.
+ `[options.pathsToSkip]` «Array|string» list of paths to skip. If set, Mongoose will validate every modified path that is not in this list.


##### Returns:


* «Promise» Returns a Promise.



Executes registered validation rules for this document.

 ####   [Note:](#note)

 This method is called `pre` save and if a validation rule is violated, [save](model#Model.prototype.save()) is aborted and the error is thrown.

 ####   [Example:](#example)

 
```
await doc.validate({ validateModifiedOnly: false, pathsToSkip: ['name', 'email']});

```
 
### Document.prototype.validateSync()


##### Parameters:


* `[pathsToValidate]` «Array|string» only validate the given paths
* `[options]` «Object» options for validation
+ `[options.validateModifiedOnly=false]` «Boolean» If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
+ `[options.pathsToSkip]` «Array|string» list of paths to skip. If set, Mongoose will validate every modified path that is not in this list.


##### Returns:


* «ValidationError,undefined,void» ValidationError if there are errors during validation, or undefined if there is no error.



Executes registered validation rules (skipping asynchronous validators) for this document.

 ####   [Note:](#note)

 This method is useful if you need synchronous validation.

 ####   [Example:](#example)

 
```
const err = doc.validateSync();
if (err) {
  handleError(err);
} else {
  // validation passed
}

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/document.html>

QueryCursor
===========



### QueryCursor()


##### Parameters:


* `query` «Query»
* `options` «Object» query options passed to `.find()`


##### Inherits:


* [«Readable»](https://nodejs.org/api/stream.html#class-streamreadable)



A QueryCursor is a concurrency primitive for processing query results one document at a time. A QueryCursor fulfills the Node.js streams3 API, in addition to several other mechanisms for loading documents from MongoDB one at a time.

 QueryCursors execute the model's pre `find` hooks before loading any documents from MongoDB, and the model's post `find` hooks after loading each document.

 Unless you're an advanced user, do **not** instantiate this class directly. Use [`Query#cursor()`](query#Query.prototype.cursor()) instead.

 
### QueryCursor.prototype.addCursorFlag()


##### Parameters:


* `flag` «String»
* `value` «Boolean»


##### Returns:


* «AggregationCursor» this



Adds a [cursor flag](https://mongodb.github.io/node-mongodb-native/4.9/classes/FindCursor.html#addCursorFlag). Useful for setting the `noCursorTimeout` and `tailable` flags.

 
### QueryCursor.prototype.close()


##### Returns:


* «Promise»


##### See:


* [AggregationCursor.close](https://mongodb.github.io/node-mongodb-native/4.9/classes/AggregationCursor.html#close)



Marks this cursor as closed. Will stop streaming and subsequent calls to `next()` will error.

 
### QueryCursor.prototype.eachAsync()


##### Parameters:


* `fn` «Function»
* `[options]` «Object»
+ `[options.parallel]` «Number» the number of promises to execute in parallel. Defaults to 1.
+ `[options.batchSize]` «Number» if set, will call `fn()` with arrays of documents with length at most `batchSize`
+ `[options.continueOnError=false]` «Boolean» if true, `eachAsync()` iterates through all docs even if `fn` throws an error. If false, `eachAsync()` throws an error immediately if the given function `fn()` throws an error.

* `[callback]` «Function» executed when all docs have been processed


##### Returns:


* «Promise»



Execute `fn` for every document in the cursor. If `fn` returns a promise, will wait for the promise to resolve before iterating on to the next one. Returns a promise that resolves when done.

 ####   [Example:](#example)

 
```
// Iterate over documents asynchronously
Thing.
  find({ name: /^hello/ }).
  cursor().
  eachAsync(async function (doc, i) {
    doc.foo = doc.bar + i;
    await doc.save();
  })

```
 
### QueryCursor.prototype.map()


##### Parameters:


* `fn` «Function»


##### Returns:


* «QueryCursor»



Registers a transform function which subsequently maps documents retrieved via the streams interface or `.next()`

 ####   [Example:](#example)

 
```
// Map documents returned by `data` events
Thing.
  find({ name: /^hello/ }).
  cursor().
  map(function (doc) {
   doc.foo = "bar";
   return doc;
  })
  on('data', function(doc) { console.log(doc.foo); });

// Or map documents returned by `.next()`
const cursor = Thing.find({ name: /^hello/ }).
  cursor().
  map(function (doc) {
    doc.foo = "bar";
    return doc;
  });
cursor.next(function(error, doc) {
  console.log(doc.foo);
});

```
 
### QueryCursor.prototype.next()


##### Returns:


* «Promise»



Get the next document from this cursor. Will return `null` when there are no documents left.

 
### QueryCursor.prototype.options


##### Type:


* «property»



The `options` passed in to the `QueryCursor` constructor.

 
### QueryCursor.prototype.rewind()


##### Returns:


* «AggregationCursor» this



Rewind this cursor to its uninitialized state. Any options that are present on the cursor will remain in effect. Iterating this cursor will cause new queries to be sent to the server, even if the resultant data has already been retrieved by this cursor.

 
### QueryCursor.prototype[Symbol.asyncIterator]()



Returns an asyncIterator for use with [`for/await/of` loops](https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js). You do not need to call this function explicitly, the JavaScript runtime will call it for you.

 ####   [Example:](#example)

 
```
// Works without using `cursor()`
for await (const doc of Model.find([{ $sort: { name: 1 } }])) {
  console.log(doc.name);
}

// Can also use `cursor()`
for await (const doc of Model.find([{ $sort: { name: 1 } }]).cursor()) {
  console.log(doc.name);
}

```
 Node.js 10.x supports async iterators natively without any flags. You can enable async iterators in Node.js 8.x using the [`--harmony_async_iteration` flag](https://github.com/tc39/proposal-async-iteration/issues/117#issuecomment-346695187).

 **Note:** This function is not if `Symbol.asyncIterator` is undefined. If `Symbol.asyncIterator` is undefined, that means your Node.js version does not support async iterators.

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/querycursor.html>

AggregationCursor
=================



### AggregationCursor()


##### Parameters:


* `agg` «Aggregate»


##### Inherits:


* [«Readable»](https://nodejs.org/api/stream.html#class-streamreadable)



An AggregationCursor is a concurrency primitive for processing aggregation results one document at a time. It is analogous to QueryCursor.

 An AggregationCursor fulfills the Node.js streams3 API, in addition to several other mechanisms for loading documents from MongoDB one at a time.

 Creating an AggregationCursor executes the model's pre aggregate hooks, but **not** the model's post aggregate hooks.

 Unless you're an advanced user, do **not** instantiate this class directly. Use [`Aggregate#cursor()`](aggregate#Aggregate.prototype.cursor()) instead.

 
### AggregationCursor.prototype.addCursorFlag()


##### Parameters:


* `flag` «String»
* `value` «Boolean»


##### Returns:


* «AggregationCursor» this



Adds a [cursor flag](https://mongodb.github.io/node-mongodb-native/4.9/classes/AggregationCursor.html#addCursorFlag). Useful for setting the `noCursorTimeout` and `tailable` flags.

 
### AggregationCursor.prototype.close()


##### Parameters:


* `callback` «Function»


##### Returns:


* «Promise»


##### See:


* [AggregationCursor.close](https://mongodb.github.io/node-mongodb-native/4.9/classes/AggregationCursor.html#close)



Marks this cursor as closed. Will stop streaming and subsequent calls to `next()` will error.

 
### AggregationCursor.prototype.eachAsync()


##### Parameters:


* `fn` «Function»
* `[options]` «Object»
+ `[options.parallel]` «Number» the number of promises to execute in parallel. Defaults to 1.

* `[callback]` «Function» executed when all docs have been processed


##### Returns:


* «Promise»



Execute `fn` for every document in the cursor. If `fn` returns a promise, will wait for the promise to resolve before iterating on to the next one. Returns a promise that resolves when done.

 
### AggregationCursor.prototype.map()


##### Parameters:


* `fn` «Function»


##### Returns:


* «AggregationCursor»



Registers a transform function which subsequently maps documents retrieved via the streams interface or `.next()`

 ####   [Example:](#example)

 
```
// Map documents returned by `data` events
Thing.
  find({ name: /^hello/ }).
  cursor().
  map(function (doc) {
   doc.foo = "bar";
   return doc;
  })
  on('data', function(doc) { console.log(doc.foo); });

// Or map documents returned by `.next()`
const cursor = Thing.find({ name: /^hello/ }).
  cursor().
  map(function (doc) {
    doc.foo = "bar";
    return doc;
  });
cursor.next(function(error, doc) {
  console.log(doc.foo);
});

```
 
### AggregationCursor.prototype.next()


##### Returns:


* «Promise»



Get the next document from this cursor. Will return `null` when there are no documents left.

 
### AggregationCursor.prototype[Symbol.asyncIterator]()



Returns an asyncIterator for use with [`for/await/of` loops](https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js) You do not need to call this function explicitly, the JavaScript runtime will call it for you.

 ####   [Example:](#example)

 
```
// Async iterator without explicitly calling `cursor()`. Mongoose still
// creates an AggregationCursor instance internally.
const agg = Model.aggregate([{ $match: { age: { $gte: 25 } } }]);
for await (const doc of agg) {
  console.log(doc.name);
}

// You can also use an AggregationCursor instance for async iteration
const cursor = Model.aggregate([{ $match: { age: { $gte: 25 } } }]).cursor();
for await (const doc of cursor) {
  console.log(doc.name);
}

```
 Node.js 10.x supports async iterators natively without any flags. You can enable async iterators in Node.js 8.x using the [`--harmony_async_iteration` flag](https://github.com/tc39/proposal-async-iteration/issues/117#issuecomment-346695187).

 **Note:** This function is not set if `Symbol.asyncIterator` is undefined. If `Symbol.asyncIterator` is undefined, that means your Node.js version does not support async iterators.

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/aggregationcursor.html>

Schematype
==========



### SchemaType()


##### Parameters:


* `path` «String»
* `[options]` «SchemaTypeOptions» See [SchemaTypeOptions docs](schematypeoptions)
* `[instance]` «String»



SchemaType constructor. Do **not** instantiate `SchemaType` directly. Mongoose converts your schema paths into SchemaTypes automatically.

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: String });
schema.path('name') instanceof SchemaType; // true

```
 
### SchemaType.cast()


##### Parameters:


* `caster` «Function|false» Function that casts arbitrary values to this type, or throws an error if casting failed


##### Returns:


* «Function»



Get/set the function used to cast arbitrary values to this type.

 ####   [Example:](#example)

 
```
// Disallow `null` for numbers, and don't try to cast any values to
// numbers, so even strings like '123' will cause a CastError.
mongoose.Number.cast(function(v) {
  assert.ok(v === undefined || typeof v === 'number');
  return v;
});

```
 
### SchemaType.checkRequired()


##### Parameters:


* `[fn]` «Function» If set, will overwrite the current set function


##### Returns:


* «Function» The input `fn` or the already set function



Set & Get the `checkRequired` function Override the function the required validator uses to check whether a value passes the `required` check. Override this on the individual SchemaType.

 ####   [Example:](#example)

 
```
// Use this to allow empty strings to pass the `required` validator
mongoose.Schema.Types.String.checkRequired(v => typeof v === 'string');

```
 
### SchemaType.get()


##### Parameters:


* `getter` «Function»


##### Returns:


* «this»



Attaches a getter for all instances of this schema type.

 ####   [Example:](#example)

 
```
// Make all numbers round down
mongoose.Number.get(function(v) { return Math.floor(v); });

```
 
### SchemaType.prototype.cast()


##### Parameters:


* `value` «Object» value to cast
* `doc` «Document» document that triggers the casting
* `init` «Boolean»



The function that Mongoose calls to cast arbitrary values to this SchemaType.

 
### SchemaType.prototype.castFunction()


##### Parameters:


* `caster` «Function|false» Function that casts arbitrary values to this type, or throws an error if casting failed


##### Returns:


* «Function»



Get/set the function used to cast arbitrary values to this particular schematype instance. Overrides `SchemaType.cast()`.

 ####   [Example:](#example)

 
```
// Disallow `null` for numbers, and don't try to cast any values to
// numbers, so even strings like '123' will cause a CastError.
const number = new mongoose.Number('mypath', {});
number.cast(function(v) {
  assert.ok(v === undefined || typeof v === 'number');
  return v;
});

```
 
### SchemaType.prototype.default()


##### Parameters:


* `val` «Function|any» The default value to set


##### Returns:


* «Any,undefined,void» Returns the set default value.



Sets a default value for this SchemaType.

 ####   [Example:](#example)

 
```
const schema = new Schema({ n: { type: Number, default: 10 })
const M = db.model('M', schema)
const m = new M;
console.log(m.n) // 10

```
 Defaults can be either `functions` which return the value to use as the default or the literal value itself. Either way, the value will be cast based on its schema type before being set during document creation.

 ####   [Example:](#example-1)

 
```
// values are cast:
const schema = new Schema({ aNumber: { type: Number, default: 4.815162342 }})
const M = db.model('M', schema)
const m = new M;
console.log(m.aNumber) // 4.815162342

// default unique objects for Mixed types:
const schema = new Schema({ mixed: Schema.Types.Mixed });
schema.path('mixed').default(function () {
  return {};
});

// if we don't use a function to return object literals for Mixed defaults,
// each document will receive a reference to the same object literal creating
// a "shared" object instance:
const schema = new Schema({ mixed: Schema.Types.Mixed });
schema.path('mixed').default({});
const M = db.model('M', schema);
const m1 = new M;
m1.mixed.added = 1;
console.log(m1.mixed); // { added: 1 }
const m2 = new M;
console.log(m2.mixed); // { added: 1 }

```
 
### SchemaType.prototype.doValidate()


##### Parameters:


* `value` «Any»
* `callback` «Function»
* `scope` «Object»
* `[options]` «Object»
+ `[options.path]` «String»


##### Returns:


* «Any» If no validators, returns the output from calling `fn`, otherwise no return



Performs a validation of `value` using the validators declared for this SchemaType.

 
### SchemaType.prototype.get()


##### Parameters:


* `fn` «Function»


##### Returns:


* «SchemaType» this



Adds a getter to this schematype.

 ####   [Example:](#example)

 
```
function dob (val) {
  if (!val) return val;
  return (val.getMonth() + 1) + "/" + val.getDate() + "/" + val.getFullYear();
}

// defining within the schema
const s = new Schema({ born: { type: Date, get: dob })

// or by retreiving its SchemaType
const s = new Schema({ born: Date })
s.path('born').get(dob)

```
 Getters allow you to transform the representation of the data as it travels from the raw mongodb document to the value that you see.

 Suppose you are storing credit card numbers and you want to hide everything except the last 4 digits to the mongoose user. You can do so by defining a getter in the following way:

 
```
function obfuscate (cc) {
  return '\*\*\*\*-\*\*\*\*-\*\*\*\*-' + cc.slice(cc.length-4, cc.length);
}

const AccountSchema = new Schema({
  creditCardNumber: { type: String, get: obfuscate }
});

const Account = db.model('Account', AccountSchema);

Account.findById(id, function (err, found) {
  console.log(found.creditCardNumber); // '\*\*\*\*-\*\*\*\*-\*\*\*\*-1234'
});

```
 Getters are also passed a second argument, the schematype on which the getter was defined. This allows for tailored behavior based on options passed in the schema.

 
```
function inspector (val, priorValue, schematype) {
  if (schematype.options.required) {
    return schematype.path + ' is required';
  } else {
    return schematype.path + ' is not';
  }
}

const VirusSchema = new Schema({
  name: { type: String, required: true, get: inspector },
  taxonomy: { type: String, get: inspector }
})

const Virus = db.model('Virus', VirusSchema);

Virus.findById(id, function (err, virus) {
  console.log(virus.name);     // name is required
  console.log(virus.taxonomy); // taxonomy is not
})

```
 
### SchemaType.prototype.immutable()


##### Parameters:


* `bool` «Boolean»


##### Returns:


* «SchemaType» this


##### See:


* [isNew](document#Document.prototype.isNew())



Defines this path as immutable. Mongoose prevents you from changing immutable paths unless the parent document has [`isNew: true`](document#Document.prototype.isNew()).

 ####   [Example:](#example)

 
```
const schema = new Schema({
  name: { type: String, immutable: true },
  age: Number
});
const Model = mongoose.model('Test', schema);

await Model.create({ name: 'test' });
const doc = await Model.findOne();

doc.isNew; // false
doc.name = 'new name';
doc.name; // 'test', because `name` is immutable

```
 Mongoose also prevents changing immutable properties using `updateOne()` and `updateMany()` based on [strict mode](../guide#strict).

 ####   [Example:](#example-1)

 
```
// Mongoose will strip out the `name` update, because `name` is immutable
Model.updateOne({}, { $set: { name: 'test2' }, $inc: { age: 1 } });

// If `strict` is set to 'throw', Mongoose will throw an error if you
// update `name`
const err = await Model.updateOne({}, { name: 'test2' }, { strict: 'throw' }).
  then(() => null, err => err);
err.name; // StrictModeError

// If `strict` is `false`, Mongoose allows updating `name` even though
// the property is immutable.
Model.updateOne({}, { name: 'test2' }, { strict: false });

```
 
### SchemaType.prototype.index()


##### Parameters:


* `options` «Object|Boolean|String|Number»


##### Returns:


* «SchemaType» this



Declares the index options for this schematype.

 ####   [Example:](#example)

 
```
const s = new Schema({ name: { type: String, index: true })
const s = new Schema({ name: { type: String, index: -1 })
const s = new Schema({ loc: { type: [Number], index: 'hashed' })
const s = new Schema({ loc: { type: [Number], index: '2d', sparse: true })
const s = new Schema({ loc: { type: [Number], index: { type: '2dsphere', sparse: true }})
const s = new Schema({ date: { type: Date, index: { unique: true, expires: '1d' }})
s.path('my.path').index(true);
s.path('my.date').index({ expires: 60 });
s.path('my.path').index({ unique: true, sparse: true });

```
 ####   [Note:](#note)

 *Indexes are created [in the background](https://www.mongodb.com/docs/manual/core/index-creation/#index-creation-background) by default. If `background` is set to `false`, MongoDB will not execute any read/write operations you send until the index build. Specify `background: false` to override Mongoose's default.*

 
### SchemaType.prototype.isRequired


##### Type:


* «property»



True if this SchemaType has a required validator. False otherwise.

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: { type: String, required: true } });
schema.path('name').isRequired; // true

schema.path('name').required(false);
schema.path('name').isRequired; // false

```
 
### SchemaType.prototype.path


##### Type:


* «property»



The path to this SchemaType in a Schema.

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: String });
schema.path('name').path; // 'name'

```
 
### SchemaType.prototype.ref()


##### Parameters:


* `ref` «String|Model|Function» either a model name, a [Model](../models), or a function that returns a model name or model.


##### Returns:


* «SchemaType» this



Set the model that this path refers to. This is the option that [populate](../populate) looks at to determine the foreign collection it should query.

 ####   [Example:](#example)

 
```
const userSchema = new Schema({ name: String });
const User = mongoose.model('User', userSchema);

const postSchema = new Schema({ user: mongoose.ObjectId });
postSchema.path('user').ref('User'); // Can set ref to a model name
postSchema.path('user').ref(User); // Or a model class
postSchema.path('user').ref(() => 'User'); // Or a function that returns the model name
postSchema.path('user').ref(() => User); // Or a function that returns the model class

// Or you can just declare the `ref` inline in your schema
const postSchema2 = new Schema({
  user: { type: mongoose.ObjectId, ref: User }
});

```
 
### SchemaType.prototype.required()


##### Parameters:


* `required` «Boolean|Function|Object» enable/disable the validator, or function that returns required boolean, or options object
+ `[options.isRequired]` «Boolean|Function» enable/disable the validator, or function that returns required boolean
+ `[options.ErrorConstructor]` «Function» custom error constructor. The constructor receives 1 parameter, an object containing the validator properties.

* `[message]` «String» optional custom error message


##### Returns:


* «SchemaType» this


##### See:


* [Customized Error Messages](error#Error.messages)
* [SchemaArray#checkRequired](schemaarray#SchemaArray.prototype.checkRequired())
* [SchemaBoolean#checkRequired](schemaboolean#SchemaBoolean.prototype.checkRequired())
* [SchemaBuffer#checkRequired](schemabuffer#SchemaBuffer.prototype.checkRequired())
* [SchemaNumber#checkRequired](schemanumber#SchemaNumber.prototype.checkRequired())
* [SchemaObjectId#checkRequired](schemaobjectid#ObjectId.prototype.checkRequired())
* [SchemaString#checkRequired](schemastring#SchemaString.prototype.checkRequired())



Adds a required validator to this SchemaType. The validator gets added to the front of this SchemaType's validators array using `unshift()`.

 ####   [Example:](#example)

 
```
const s = new Schema({ born: { type: Date, required: true })

// or with custom error message

const s = new Schema({ born: { type: Date, required: '{PATH} is required!' })

// or with a function

const s = new Schema({
  userId: ObjectId,
  username: {
    type: String,
    required: function() { return this.userId != null; }
  }
})

// or with a function and a custom message
const s = new Schema({
  userId: ObjectId,
  username: {
    type: String,
    required: [
      function() { return this.userId != null; },
      'username is required if id is specified'
    ]
  }
})

// or through the path API

s.path('name').required(true);

// with custom error messaging

s.path('name').required(true, 'grrr :( ');

// or make a path conditionally required based on a function
const isOver18 = function() { return this.age >= 18; };
s.path('voterRegistrationId').required(isOver18);

```
 The required validator uses the SchemaType's `checkRequired` function to determine whether a given value satisfies the required validator. By default, a value satisfies the required validator if `val != null` (that is, if the value is not null nor undefined). However, most built-in mongoose schema types override the default `checkRequired` function:

 
### SchemaType.prototype.select()


##### Parameters:


* `val` «Boolean»


##### Returns:


* «SchemaType» this



Sets default `select()` behavior for this path.

 Set to `true` if this path should always be included in the results, `false` if it should be excluded by default. This setting can be overridden at the query level.

 ####   [Example:](#example)

 
```
T = db.model('T', new Schema({ x: { type: String, select: true }}));
T.find(..); // field x will always be selected ..
// .. unless overridden;
T.find().select('-x').exec(callback);

```
 
### SchemaType.prototype.set()


##### Parameters:


* `fn` «Function»


##### Returns:


* «SchemaType» this



Adds a setter to this schematype.

 ####   [Example:](#example)

 
```
function capitalize (val) {
  if (typeof val !== 'string') val = '';
  return val.charAt(0).toUpperCase() + val.substring(1);
}

// defining within the schema
const s = new Schema({ name: { type: String, set: capitalize }});

// or with the SchemaType
const s = new Schema({ name: String })
s.path('name').set(capitalize);

```
 Setters allow you to transform the data before it gets to the raw mongodb document or query.

 Suppose you are implementing user registration for a website. Users provide an email and password, which gets saved to mongodb. The email is a string that you will want to normalize to lower case, in order to avoid one email having more than one account -- e.g., otherwise, [avenue@q.com](mailto:avenue@q.com) can be registered for 2 accounts via [avenue@q.com](mailto:avenue@q.com) and [AvEnUe@Q.CoM](mailto:AvEnUe@Q.CoM).

 You can set up email lower case normalization easily via a Mongoose setter.

 
```
function toLower(v) {
  return v.toLowerCase();
}

const UserSchema = new Schema({
  email: { type: String, set: toLower }
});

const User = db.model('User', UserSchema);

const user = new User({email: 'AVENUE@Q.COM'});
console.log(user.email); // 'avenue@q.com'

// or
const user = new User();
user.email = 'Avenue@Q.com';
console.log(user.email); // 'avenue@q.com'
User.updateOne({ \_id: _id }, { $set: { email: 'AVENUE@Q.COM' } }); // update to 'avenue@q.com'

```
 As you can see above, setters allow you to transform the data before it stored in MongoDB, or before executing a query.

 *NOTE: we could have also just used the built-in `lowercase: true` SchemaType option instead of defining our own function.*

 
```
new Schema({ email: { type: String, lowercase: true }})

```
 Setters are also passed a second argument, the schematype on which the setter was defined. This allows for tailored behavior based on options passed in the schema.

 
```
function inspector (val, priorValue, schematype) {
  if (schematype.options.required) {
    return schematype.path + ' is required';
  } else {
    return val;
  }
}

const VirusSchema = new Schema({
  name: { type: String, required: true, set: inspector },
  taxonomy: { type: String, set: inspector }
})

const Virus = db.model('Virus', VirusSchema);
const v = new Virus({ name: 'Parvoviridae', taxonomy: 'Parvovirinae' });

console.log(v.name);     // name is required
console.log(v.taxonomy); // Parvovirinae

```
 You can also use setters to modify other properties on the document. If you're setting a property `name` on a document, the setter will run with `this` as the document. Be careful, in mongoose 5 setters will also run when querying by `name` with `this` as the query.

 
```
const nameSchema = new Schema({ name: String, keywords: [String] });
nameSchema.path('name').set(function(v) {
  // Need to check if `this` is a document, because in mongoose 5
  // setters will also run on queries, in which case `this` will be a
  // mongoose query object.
  if (this instanceof Document && v != null) {
    this.keywords = v.split(' ');
  }
  return v;
});

```
 
### SchemaType.prototype.sparse()


##### Parameters:


* `bool` «Boolean»


##### Returns:


* «SchemaType» this



Declares a sparse index.

 ####   [Example:](#example)

 
```
const s = new Schema({ name: { type: String, sparse: true } });
s.path('name').index({ sparse: true });

```
 
### SchemaType.prototype.text()


##### Parameters:


* `bool` «Boolean»


##### Returns:


* «SchemaType» this



Declares a full text index.

 ###  Example:

 
```
 const s = new Schema({ name : { type: String, text : true } })
 s.path('name').index({ text : true });

```
 
### SchemaType.prototype.transform()


##### Parameters:


* `fn` «Function»


##### Returns:


* «SchemaType» this



Defines a custom function for transforming this path when converting a document to JSON.

 Mongoose calls this function with one parameter: the current `value` of the path. Mongoose then uses the return value in the JSON output.

 ####   [Example:](#example)

 
```
const schema = new Schema({
  date: { type: Date, transform: v => v.getFullYear() }
});
const Model = mongoose.model('Test', schema);

await Model.create({ date: new Date('2016-06-01') });
const doc = await Model.findOne();

doc.date instanceof Date; // true

doc.toJSON().date; // 2016 as a number
JSON.stringify(doc); // '{"\_id":...,"date":2016}'

```
 
### SchemaType.prototype.unique()


##### Parameters:


* `bool` «Boolean»


##### Returns:


* «SchemaType» this



Declares an unique index.

 ####   [Example:](#example)

 
```
const s = new Schema({ name: { type: String, unique: true } });
s.path('name').index({ unique: true });

```
 *NOTE: violating the constraint returns an `E11000` error from MongoDB when saving, not a Mongoose validation error.*

 
### SchemaType.prototype.validate()


##### Parameters:


* `obj` «RegExp|Function|Object» validator function, or hash describing options
+ `[obj.validator]` «Function» validator function. If the validator function returns `undefined` or a truthy value, validation succeeds. If it returns [falsy](https://masteringjs.io/tutorials/fundamentals/falsy) (except `undefined`) or throws an error, validation fails.
+ `[obj.message]` «String|Function» optional error message. If function, should return the error message as a string
+ `[obj.propsParameter=false]` «Boolean» If true, Mongoose will pass the validator properties object (with the `validator` function, `message`, etc.) as the 2nd arg to the validator function. This is disabled by default because many validators [rely on positional args](https://github.com/chriso/validator.js#validators), so turning this on may cause unpredictable behavior in external validators.

* `[errorMsg]` «String|Function» optional error message. If function, should return the error message as a string
* `[type]` «String» optional validator type


##### Returns:


* «SchemaType» this



Adds validator(s) for this document path.

 Validators always receive the value to validate as their first argument and must return `Boolean`. Returning `false` or throwing an error means validation failed.

 The error message argument is optional. If not passed, the [default generic error message template](error#Error.messages) will be used.

 ####   [Example:](#example)

 
```
// make sure every value is equal to "something"
function validator (val) {
  return val === 'something';
}
new Schema({ name: { type: String, validate: validator }});

// with a custom error message

const custom = [validator, 'Uh oh, {PATH} does not equal "something".']
new Schema({ name: { type: String, validate: custom }});

// adding many validators at a time

const many = [
    { validator: validator, message: 'uh oh' }
  , { validator: anotherValidator, message: 'failed' }
]
new Schema({ name: { type: String, validate: many }});

// or utilizing SchemaType methods directly:

const schema = new Schema({ name: 'string' });
schema.path('name').validate(validator, 'validation of `{PATH}` failed with value `{VALUE}`');

```
 ####   [Error message templates:](#error-message-templates)

 Below is a list of supported template keywords:

 * PATH: The schema path where the error is being triggered.
* VALUE: The value assigned to the PATH that is triggering the error.
* KIND: The validation property that triggered the error i.e. required.
* REASON: The error object that caused this error if there was one.

 If Mongoose's built-in error message templating isn't enough, Mongoose supports setting the `message` property to a function.

 
```
schema.path('name').validate({
  validator: function(v) { return v.length > 5; },
  // `errors['name']` will be "name must have length 5, got 'foo'"
  message: function(props) {
    return `${props.path} must have length 5, got '${props.value}'`;
  }
});

```
 To bypass Mongoose's error messages and just copy the error message that the validator throws, do this:

 
```
schema.path('name').validate({
  validator: function() { throw new Error('Oops!'); },
  // `errors['name']` will be "Oops!"
  message: function(props) { return props.reason.message; }
});

```
 ####   [Asynchronous validation:](#asynchronous-validation)

 Mongoose supports validators that return a promise. A validator that returns a promise is called an *async validator*. Async validators run in parallel, and `validate()` will wait until all async validators have settled.

 
```
schema.path('name').validate({
  validator: function (value) {
    return new Promise(function (resolve, reject) {
      resolve(false); // validation failed
    });
  }
});

```
 You might use asynchronous validators to retreive other documents from the database to validate against or to meet other I/O bound validation needs.

 Validation occurs `pre('save')` or whenever you manually execute [document#validate](document#Document.prototype.validate()).

 If validation fails during `pre('save')` and no callback was passed to receive the error, an `error` event will be emitted on your Models associated db [connection](connection#Connection()), passing the validation error object along.

 
```
const conn = mongoose.createConnection(..);
conn.on('error', handleError);

const Product = conn.model('Product', yourSchema);
const dvd = new Product(..);
dvd.save(); // emits error on the `conn` above

```
 If you want to handle these errors at the Model level, add an `error` listener to your Model as shown below.

 
```
// registering an error listener on the Model lets us handle errors more locally
Product.on('error', handleError);

```
 
### SchemaType.prototype.validators


##### Type:


* «property»



The validators that Mongoose should run to validate properties at this SchemaType's path.

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: { type: String, required: true } });
schema.path('name').validators.length; // 1, the `required` validator

```
 
### SchemaType.set()


##### Parameters:


* `option` «String» The name of the option you'd like to set (e.g. trim, lowercase, etc...)
* `value` «Any» The value of the option you'd like to set.


##### Returns:


* «void,void»



Sets a default option for this schema type.

 ####   [Example:](#example)

 
```
// Make all strings be trimmed by default
mongoose.SchemaTypes.String.set('trim', true);

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schematype.html>

Virtualtype
===========



### VirtualType()


##### Parameters:


* `options` «Object»
+ `[options.ref]` «String|Function» if `ref` is not nullish, this becomes a [populated virtual](../populate#populate-virtuals)
+ `[options.localField]` «String|Function» the local field to populate on if this is a populated virtual.
+ `[options.foreignField]` «String|Function» the foreign field to populate on if this is a populated virtual.
+ `[options.justOne=false]` «Boolean» by default, a populated virtual is an array. If you set `justOne`, the populated virtual will be a single doc or `null`.
+ `[options.getters=false]` «Boolean» if you set this to `true`, Mongoose will call any custom getters you defined on this virtual
+ `[options.count=false]` «Boolean» if you set this to `true`, `populate()` will set this virtual to the number of populated documents, as opposed to the documents themselves, using [`Query#countDocuments()`](query#Query.prototype.countDocuments())
+ `[options.match=null]` «Object|Function» add an extra match condition to `populate()`
+ `[options.limit=null]` «Number» add a default `limit` to the `populate()` query
+ `[options.skip=null]` «Number» add a default `skip` to the `populate()` query
+ `[options.perDocumentLimit=null]` «Number» For legacy reasons, `limit` with `populate()` may give incorrect results because it only executes a single query for every document being populated. If you set `perDocumentLimit`, Mongoose will ensure correct `limit` per document by executing a separate query for each document to `populate()`. For example, `.find().populate({ path: 'test', perDocumentLimit: 2 })` will execute 2 additional queries if `.find()` returns 2 documents.
+ `[options.options=null]` «Object» Additional options like `limit` and `lean`.

* `name` «String»



VirtualType constructor

 This is what mongoose uses to define virtual attributes via `Schema.prototype.virtual`.

 ####   [Example:](#example)

 
```
const fullname = schema.virtual('fullname');
fullname instanceof mongoose.VirtualType // true

```
 
### VirtualType.prototype.applyGetters()


##### Parameters:


* `value` «Object»
* `doc` «Document» The document this virtual is attached to


##### Returns:


* «Any» the value after applying all getters



Applies getters to `value`.

 
### VirtualType.prototype.applySetters()


##### Parameters:


* `value` «Object»
* `doc` «Document»


##### Returns:


* «Any» the value after applying all setters



Applies setters to `value`.

 
### VirtualType.prototype.get()


##### Parameters:


* `fn` «Function»


##### Returns:


* «VirtualType» this



Adds a custom getter to this virtual.

 Mongoose calls the getter function with the below 3 parameters.

 * `value`: the value returned by the previous getter. If there is only one getter, `value` will be `undefined`.
* `virtual`: the virtual object you called `.get()` on.
* `doc`: the document this virtual is attached to. Equivalent to `this`.

 ####   [Example:](#example)

 
```
const virtual = schema.virtual('fullname');
virtual.get(function(value, virtual, doc) {
  return this.name.first + ' ' + this.name.last;
});

```
 
### VirtualType.prototype.set()


##### Parameters:


* `fn` «Function»


##### Returns:


* «VirtualType» this



Adds a custom setter to this virtual.

 Mongoose calls the setter function with the below 3 parameters.

 * `value`: the value being set.
* `virtual`: the virtual object you're calling `.set()` on.
* `doc`: the document this virtual is attached to. Equivalent to `this`.

 ####   [Example:](#example)

 
```
const virtual = schema.virtual('fullname');
virtual.set(function(value, virtual, doc) {
  const parts = value.split(' ');
  this.name.first = parts[0];
  this.name.last = parts[1];
});

const Model = mongoose.model('Test', schema);
const doc = new Model();
// Calls the setter with `value = 'Jean-Luc Picard'`
doc.fullname = 'Jean-Luc Picard';
doc.name.first; // 'Jean-Luc'
doc.name.last; // 'Picard'

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/virtualtype.html>

SchemaNumber
============



### SchemaNumber()


##### Parameters:


* `key` «String»
* `options` «Object»


##### Inherits:


* [«SchemaType»](schematype)



Number SchemaType constructor.

 
### SchemaNumber.checkRequired()


##### Parameters:


* `fn` «Function»


##### Returns:


* «Function»


##### Type:


* «property»



Override the function the required validator uses to check whether a string passes the `required` check.

 
### SchemaNumber.get()


##### Parameters:


* `getter` «Function»


##### Returns:


* «this»


##### Type:


* «property»



Attaches a getter for all Number instances.

 ####   [Example:](#example)

 
```
// Make all numbers round down
mongoose.Number.get(function(v) { return Math.floor(v); });

const Model = mongoose.model('Test', new Schema({ test: Number }));
new Model({ test: 3.14 }).test; // 3

```
 
### SchemaNumber.get()


##### Parameters:


* `caster` «Function»


##### Returns:


* «Function»


##### Type:


* «property»



Get/set the function used to cast arbitrary values to numbers.

 ####   [Example:](#example)

 
```
// Make Mongoose cast empty strings '' to 0 for paths declared as numbers
const original = mongoose.Number.cast();
mongoose.Number.cast(v => {
  if (v === '') { return 0; }
  return original(v);
});

// Or disable casting entirely
mongoose.Number.cast(false);

```
 
### SchemaNumber.prototype.checkRequired()


##### Parameters:


* `value` «Any»
* `doc` «Document»


##### Returns:


* «Boolean»



Check if the given value satisfies a required validator.

 
### SchemaNumber.prototype.enum()


##### Parameters:


* `values` «Array» allowed values
* `[message]` «String» optional custom error message


##### Returns:


* «SchemaType» this


##### See:


* [Customized Error Messages](error#Error.messages)



Sets a enum validator

 ####   [Example:](#example)

 
```
const s = new Schema({ n: { type: Number, enum: [1, 2, 3] });
const M = db.model('M', s);

const m = new M({ n: 4 });
await m.save(); // throws validation error

m.n = 3;
await m.save(); // succeeds

```
 
### SchemaNumber.prototype.max()


##### Parameters:


* `maximum` «Number» number
* `[message]` «String» optional custom error message


##### Returns:


* «SchemaType» this


##### See:


* [Customized Error Messages](error#Error.messages)



Sets a maximum number validator.

 ####   [Example:](#example)

 
```
const s = new Schema({ n: { type: Number, max: 10 })
const M = db.model('M', s)
const m = new M({ n: 11 })
m.save(function (err) {
  console.error(err) // validator error
  m.n = 10;
  m.save() // success
})

// custom error messages
// We can also use the special {MAX} token which will be replaced with the invalid value
const max = [10, 'The value of path `{PATH}` ({VALUE}) exceeds the limit ({MAX}).'];
const schema = new Schema({ n: { type: Number, max: max })
const M = mongoose.model('Measurement', schema);
const s= new M({ n: 4 });
s.validate(function (err) {
  console.log(String(err)) // ValidationError: The value of path `n` (4) exceeds the limit (10).
})

```
 
### SchemaNumber.prototype.min()


##### Parameters:


* `value` «Number» minimum number
* `[message]` «String» optional custom error message


##### Returns:


* «SchemaType» this


##### See:


* [Customized Error Messages](error#Error.messages)



Sets a minimum number validator.

 ####   [Example:](#example)

 
```
const s = new Schema({ n: { type: Number, min: 10 })
const M = db.model('M', s)
const m = new M({ n: 9 })
m.save(function (err) {
  console.error(err) // validator error
  m.n = 10;
  m.save() // success
})

// custom error messages
// We can also use the special {MIN} token which will be replaced with the invalid value
const min = [10, 'The value of path `{PATH}` ({VALUE}) is beneath the limit ({MIN}).'];
const schema = new Schema({ n: { type: Number, min: min })
const M = mongoose.model('Measurement', schema);
const s= new M({ n: 4 });
s.validate(function (err) {
  console.log(String(err)) // ValidationError: The value of path `n` (4) is beneath the limit (10).
})

```
 
### SchemaNumber.schemaName


##### Type:


* «property»



This schema type's name, to defend against minifiers that mangle function names.

 
### SchemaNumber.set()


##### Parameters:


* `option` «String» The option you'd like to set the value for
* `value` «Any» value for option


##### Returns:


* «undefined,void»


##### Type:


* «property»



Sets a default option for all Number instances.

 ####   [Example:](#example)

 
```
// Make all numbers have option `min` equal to 0.
mongoose.Schema.Number.set('min', 0);

const Order = mongoose.model('Order', new Schema({ amount: Number }));
new Order({ amount: -10 }).validateSync().errors.amount.message; // Path `amount` must be larger than 0.

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schemanumber.html>

SchemaObjectid
==============



### ObjectId()


##### Parameters:


* `key` «String»
* `options` «Object»


##### Inherits:


* [«SchemaType»](schematype)



ObjectId SchemaType constructor.

 
### ObjectId.checkRequired()


##### Parameters:


* `fn` «Function»


##### Returns:


* «Function»


##### Type:


* «property»



Override the function the required validator uses to check whether a string passes the `required` check.

 ####   [Example:](#example)

 
```
// Allow empty strings to pass `required` check
mongoose.Schema.Types.String.checkRequired(v => v != null);

const M = mongoose.model({ str: { type: String, required: true } });
new M({ str: '' }).validateSync(); // `null`, validation passes!

```
 
### ObjectId.get()


##### Parameters:


* `getter` «Function»


##### Returns:


* «this»


##### Type:


* «property»



Attaches a getter for all ObjectId instances

 ####   [Example:](#example)

 
```
// Always convert to string when getting an ObjectId
mongoose.ObjectId.get(v => v.toString());

const Model = mongoose.model('Test', new Schema({}));
typeof (new Model({}).\_id); // 'string'

```
 
### ObjectId.get()


##### Parameters:


* `caster` «Function»


##### Returns:


* «Function»


##### Type:


* «property»



Get/set the function used to cast arbitrary values to objectids.

 ####   [Example:](#example)

 
```
// Make Mongoose only try to cast length 24 strings. By default, any 12
// char string is a valid ObjectId.
const original = mongoose.ObjectId.cast();
mongoose.ObjectId.cast(v => {
  assert.ok(typeof v !== 'string' || v.length === 24);
  return original(v);
});

// Or disable casting entirely
mongoose.ObjectId.cast(false);

```
 
### ObjectId.prototype.auto()


##### Parameters:


* `turnOn` «Boolean» auto generated ObjectId defaults


##### Returns:


* «SchemaType» this



Adds an auto-generated ObjectId default if turnOn is true.

 
### ObjectId.prototype.checkRequired()


##### Parameters:


* `value` «Any»
* `doc` «Document»


##### Returns:


* «Boolean»



Check if the given value satisfies a required validator.

 
### ObjectId.schemaName


##### Type:


* «property»



This schema type's name, to defend against minifiers that mangle function names.

 
### ObjectId.set()


##### Parameters:


* `option` «String» The option you'd like to set the value for
* `value` «Any» value for option


##### Returns:


* «undefined,void»


##### Type:


* «property»



Sets a default option for all ObjectId instances.

 ####   [Example:](#example)

 
```
// Make all object ids have option `required` equal to true.
mongoose.Schema.ObjectId.set('required', true);

const Order = mongoose.model('Order', new Schema({ userId: ObjectId }));
new Order({ }).validateSync().errors.userId.message; // Path `userId` is required.

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schemaobjectid.html>

SchemaString
============



### SchemaString()


##### Parameters:


* `key` «String»
* `options` «Object»


##### Inherits:


* [«SchemaType»](schematype)



String SchemaType constructor.

 
### SchemaString.checkRequired()


##### Parameters:


* `fn` «Function»


##### Returns:


* «Function»


##### Type:


* «property»



Override the function the required validator uses to check whether a string passes the `required` check.

 ####   [Example:](#example)

 
```
// Allow empty strings to pass `required` check
mongoose.Schema.Types.String.checkRequired(v => v != null);

const M = mongoose.model({ str: { type: String, required: true } });
new M({ str: '' }).validateSync(); // `null`, validation passes!

```
 
### SchemaString.get()


##### Parameters:


* `caster` «Function»


##### Returns:


* «Function»


##### Type:


* «property»



Get/set the function used to cast arbitrary values to strings.

 ####   [Example:](#example)

 
```
// Throw an error if you pass in an object. Normally, Mongoose allows
// objects with custom `toString()` functions.
const original = mongoose.Schema.Types.String.cast();
mongoose.Schema.Types.String.cast(v => {
  assert.ok(v == null || typeof v !== 'object');
  return original(v);
});

// Or disable casting entirely
mongoose.Schema.Types.String.cast(false);

```
 
### SchemaString.get()


##### Parameters:


* `getter` «Function»


##### Returns:


* «this»


##### Type:


* «property»



Attaches a getter for all String instances.

 ####   [Example:](#example)

 
```
// Make all numbers round down
mongoose.Schema.String.get(v => v.toLowerCase());

const Model = mongoose.model('Test', new Schema({ test: String }));
new Model({ test: 'FOO' }).test; // 'foo'

```
 
### SchemaString.prototype.checkRequired()


##### Parameters:


* `value` «Any»
* `doc` «Document»


##### Returns:


* «Boolean»



Check if the given value satisfies the `required` validator. The value is considered valid if it is a string (that is, not `null` or `undefined`) and has positive length. The `required` validator **will** fail for empty strings.

 
### SchemaString.prototype.enum()


##### Parameters:


* `[...args]` «String|Object» enumeration values


##### Returns:


* «SchemaType» this


##### See:


* [Customized Error Messages](error#Error.messages)
* [Enums in JavaScript](https://masteringjs.io/tutorials/fundamentals/enum)



Adds an enum validator

 ####   [Example:](#example)

 
```
const states = ['opening', 'open', 'closing', 'closed']
const s = new Schema({ state: { type: String, enum: states }})
const M = db.model('M', s)
const m = new M({ state: 'invalid' })
m.save(function (err) {
  console.error(String(err)) // ValidationError: `invalid` is not a valid enum value for path `state`.
  m.state = 'open'
  m.save(callback) // success
})

// or with custom error messages
const enum = {
  values: ['opening', 'open', 'closing', 'closed'],
  message: 'enum validator failed for path `{PATH}` with value `{VALUE}`'
}
const s = new Schema({ state: { type: String, enum: enum })
const M = db.model('M', s)
const m = new M({ state: 'invalid' })
m.save(function (err) {
  console.error(String(err)) // ValidationError: enum validator failed for path `state` with value `invalid`
  m.state = 'open'
  m.save(callback) // success
})

```
 
### SchemaString.prototype.lowercase()


##### Returns:


* «SchemaType» this



Adds a lowercase [setter](schematype#SchemaType.prototype.set()).

 ####   [Example:](#example)

 
```
const s = new Schema({ email: { type: String, lowercase: true }})
const M = db.model('M', s);
const m = new M({ email: 'SomeEmail@example.COM' });
console.log(m.email) // someemail@example.com
M.find({ email: 'SomeEmail@example.com' }); // Queries by 'someemail@example.com'

```
 Note that `lowercase` does **not** affect regular expression queries:

 ####   [Example:](#example-1)

 
```
// Still queries for documents whose `email` matches the regular
// expression /SomeEmail/. Mongoose does \*\*not\*\* convert the RegExp
// to lowercase.
M.find({ email: /SomeEmail/ });

```
 
### SchemaString.prototype.match()


##### Parameters:


* `regExp` «RegExp» regular expression to test against
* `[message]` «String» optional custom error message


##### Returns:


* «SchemaType» this


##### See:


* [Customized Error Messages](error#Error.messages)



Sets a regexp validator.

 Any value that does not pass `regExp`.test(val) will fail validation.

 ####   [Example:](#example)

 
```
const s = new Schema({ name: { type: String, match: /^a/ }})
const M = db.model('M', s)
const m = new M({ name: 'I am invalid' })
m.validate(function (err) {
  console.error(String(err)) // "ValidationError: Path `name` is invalid (I am invalid)."
  m.name = 'apples'
  m.validate(function (err) {
    assert.ok(err) // success
  })
})

// using a custom error message
const match = [ /\.html$/, "That file doesn't end in .html ({VALUE})" ];
const s = new Schema({ file: { type: String, match: match }})
const M = db.model('M', s);
const m = new M({ file: 'invalid' });
m.validate(function (err) {
  console.log(String(err)) // "ValidationError: That file doesn't end in .html (invalid)"
})

```
 Empty strings, `undefined`, and `null` values always pass the match validator. If you require these values, enable the `required` validator also.

 
```
const s = new Schema({ name: { type: String, match: /^a/, required: true }})

```
 
### SchemaString.prototype.maxlength()


##### Parameters:


* `value` «Number» maximum string length
* `[message]` «String» optional custom error message


##### Returns:


* «SchemaType» this


##### See:


* [Customized Error Messages](error#Error.messages)



Sets a maximum length validator.

 ####   [Example:](#example)

 
```
const schema = new Schema({ postalCode: { type: String, maxlength: 9 })
const Address = db.model('Address', schema)
const address = new Address({ postalCode: '9512512345' })
address.save(function (err) {
  console.error(err) // validator error
  address.postalCode = '95125';
  address.save() // success
})

// custom error messages
// We can also use the special {MAXLENGTH} token which will be replaced with the maximum allowed length
const maxlength = [9, 'The value of path `{PATH}` (`{VALUE}`) exceeds the maximum allowed length ({MAXLENGTH}).'];
const schema = new Schema({ postalCode: { type: String, maxlength: maxlength })
const Address = mongoose.model('Address', schema);
const address = new Address({ postalCode: '9512512345' });
address.validate(function (err) {
  console.log(String(err)) // ValidationError: The value of path `postalCode` (`9512512345`) exceeds the maximum allowed length (9).
})

```
 
### SchemaString.prototype.minlength()


##### Parameters:


* `value` «Number» minimum string length
* `[message]` «String» optional custom error message


##### Returns:


* «SchemaType» this


##### See:


* [Customized Error Messages](error#Error.messages)



Sets a minimum length validator.

 ####   [Example:](#example)

 
```
const schema = new Schema({ postalCode: { type: String, minlength: 5 })
const Address = db.model('Address', schema)
const address = new Address({ postalCode: '9512' })
address.save(function (err) {
  console.error(err) // validator error
  address.postalCode = '95125';
  address.save() // success
})

// custom error messages
// We can also use the special {MINLENGTH} token which will be replaced with the minimum allowed length
const minlength = [5, 'The value of path `{PATH}` (`{VALUE}`) is shorter than the minimum allowed length ({MINLENGTH}).'];
const schema = new Schema({ postalCode: { type: String, minlength: minlength })
const Address = mongoose.model('Address', schema);
const address = new Address({ postalCode: '9512' });
address.validate(function (err) {
  console.log(String(err)) // ValidationError: The value of path `postalCode` (`9512`) is shorter than the minimum length (5).
})

```
 
### SchemaString.prototype.trim()


##### Returns:


* «SchemaType» this



Adds a trim [setter](schematype#SchemaType.prototype.set()).

 The string value will be [trimmed](https://masteringjs.io/tutorials/fundamentals/trim-string) when set.

 ####   [Example:](#example)

 
```
const s = new Schema({ name: { type: String, trim: true }});
const M = db.model('M', s);
const string = ' some name ';
console.log(string.length); // 11
const m = new M({ name: string });
console.log(m.name.length); // 9

// Equivalent to `findOne({ name: string.trim() })`
M.findOne({ name: string });

```
 Note that `trim` does **not** affect regular expression queries:

 ####   [Example:](#example-1)

 
```
// Mongoose does \*\*not\*\* trim whitespace from the RegExp.
M.find({ name: / some name / });

```
 
### SchemaString.prototype.uppercase()


##### Returns:


* «SchemaType» this



Adds an uppercase [setter](schematype#SchemaType.prototype.set()).

 ####   [Example:](#example)

 
```
const s = new Schema({ caps: { type: String, uppercase: true }})
const M = db.model('M', s);
const m = new M({ caps: 'an example' });
console.log(m.caps) // AN EXAMPLE
M.find({ caps: 'an example' }) // Matches documents where caps = 'AN EXAMPLE'

```
 Note that `uppercase` does **not** affect regular expression queries:

 ####   [Example:](#example-1)

 
```
// Mongoose does \*\*not\*\* convert the RegExp to uppercase.
M.find({ email: /an example/ });

```
 
### SchemaString.schemaName


##### Type:


* «property»



This schema type's name, to defend against minifiers that mangle function names.

 
### SchemaString.set()


##### Parameters:


* `option` «String» The option you'd like to set the value for
* `value` «Any» value for option


##### Returns:


* «undefined,void»


##### Type:


* «property»



Sets a default option for all String instances.

 ####   [Example:](#example)

 
```
// Make all strings have option `trim` equal to true.
mongoose.Schema.String.set('trim', true);

const User = mongoose.model('User', new Schema({ name: String }));
new User({ name: ' John Doe ' }).name; // 'John Doe'

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schemastring.html>

MongooseDocumentArray
=====================



### MongooseDocumentArray.prototype.create()


##### Parameters:


* `obj` «Object» the value to cast to this arrays SubDocument schema



Creates a subdocument casted to this schema.

 This is the same subdocument constructor used for casting.

 
### MongooseDocumentArray.prototype.id()


##### Parameters:


* `id` «ObjectId|String|Number|Buffer»


##### Returns:


* «EmbeddedDocument,null» the subdocument or null if not found.



Searches array items for the first document with a matching \_id.

 ####   [Example:](#example)

 
```
const embeddedDoc = m.array.id(some_id);

```
 
### MongooseDocumentArray.prototype.inspect()



Helper for console.log

 
### MongooseDocumentArray.prototype.pull()


##### Parameters:


* `[...args]` «Object»



Pulls items from the array atomically.

 
### MongooseDocumentArray.prototype.push()


##### Parameters:


* `[...args]` «Object»



Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.

 
### MongooseDocumentArray.prototype.toObject()


##### Parameters:


* `[options]` «Object» optional options to pass to each documents `toObject` method call during conversion


##### Returns:


* «Array»



Returns a native js Array of plain js objects

 ####   [Note:](#note)

 *Each sub-document is converted to a plain object by calling its `#toObject` method.*

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/mongoosedocumentarray.html>

Subdocument
===========



### Subdocument.prototype.$parent()



Returns this sub-documents parent document.

 
### Subdocument.prototype.deleteOne()


##### Parameters:


* `[options]` «Object»
* `[callback]` «Function» optional callback for compatibility with Document.prototype.remove



Null-out this subdoc

 
### Subdocument.prototype.inspect()



Helper for console.log

 
### Subdocument.prototype.ownerDocument()


##### Returns:


* «Document»



Returns the top level document of this sub-document.

 
### Subdocument.prototype.parent()



Returns this sub-documents parent document.

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/subdocument.html>

ArraySubdocument
================



### ArraySubdocument.prototype.$parent()



Returns this sub-documents parent document.

 
### ArraySubdocument.prototype.parentArray()



Returns this subdocument's parent array.

 ####   [Example:](#example)

 
```
const Test = mongoose.model('Test', new Schema({
  docArr: [{ name: String }]
}));
const doc = new Test({ docArr: [{ name: 'test subdoc' }] });

doc.docArr[0].parentArray() === doc.docArr; // true

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/arraysubdocument.html>

Buffer
======



### MongooseBuffer.mixin.copy()


##### Parameters:


* `target` «Buffer»


##### Returns:


* «Number» The number of bytes copied.


##### Type:


* «property»



Copies the buffer.

 ####   [Note:](#note)

 `Buffer#copy` does not mark `target` as modified so you must copy from a `MongooseBuffer` for it to work as expected. This is a work around since `copy` modifies the target, not this.

 
### MongooseBuffer.mixin.equals()


##### Parameters:


* `other` «Buffer»


##### Returns:


* «Boolean»



Determines if this buffer is equals to `other` buffer

 
### MongooseBuffer.mixin.subtype()


##### Parameters:


* `subtype` «Hex»


##### See:


* [bsonspec](https://bsonspec.org/#/specification)



Sets the subtype option and marks the buffer modified.

 ####   [SubTypes:](#subtypes)

 
```
const bson = require('bson')
bson.BSON\_BINARY\_SUBTYPE\_DEFAULT
bson.BSON\_BINARY\_SUBTYPE\_FUNCTION
bson.BSON\_BINARY\_SUBTYPE\_BYTE\_ARRAY
bson.BSON\_BINARY\_SUBTYPE\_UUID
bson.BSON\_BINARY\_SUBTYPE\_MD5
bson.BSON\_BINARY\_SUBTYPE\_USER\_DEFINED

doc.buffer.subtype(bson.BSON\_BINARY\_SUBTYPE\_UUID);

```
 
### MongooseBuffer.mixin.toBSON()


##### Returns:


* «Binary»



Converts this buffer for storage in MongoDB, including subtype

 
### MongooseBuffer.mixin.toObject()


##### Parameters:


* `[subtype]` «Hex»


##### Returns:


* «Binary»


##### See:


* [bsonspec](https://bsonspec.org/#/specification)



Converts this buffer to its Binary type representation.

 ####   [SubTypes:](#subtypes)

 
```
const bson = require('bson')
bson.BSON\_BINARY\_SUBTYPE\_DEFAULT
bson.BSON\_BINARY\_SUBTYPE\_FUNCTION
bson.BSON\_BINARY\_SUBTYPE\_BYTE\_ARRAY
bson.BSON\_BINARY\_SUBTYPE\_UUID
bson.BSON\_BINARY\_SUBTYPE\_MD5
bson.BSON\_BINARY\_SUBTYPE\_USER\_DEFINED
doc.buffer.toObject(bson.BSON\_BINARY\_SUBTYPE\_USER\_DEFINED);

```
 
### MongooseBuffer.mixin.write()


##### Type:


* «property»



Writes the buffer.

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/buffer.html>

Error
=====



### Error()


##### Parameters:


* `msg` «String» Error message


##### Type:


* «constructor»


##### Inherits:


* [«Error»](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error)



MongooseError constructor. MongooseError is the base class for all Mongoose-specific errors.

 ####   [Example:](#example)

 
```
const Model = mongoose.model('Test', new mongoose.Schema({ answer: Number }));
const doc = new Model({ answer: 'not a number' });
const err = doc.validateSync();

err instanceof mongoose.Error.ValidationError; // true

```
 
### Error.CastError


##### Type:


* «property»



An instance of this error class will be returned when mongoose failed to cast a value.

 
### Error.DivergentArrayError


##### Type:


* «property»



An instance of this error will be returned if you used an array projection and then modified the array in an unsafe way.

 
### Error.DocumentNotFoundError


##### Type:


* «property»



An instance of this error class will be returned when `save()` fails because the underlying document was not found. The constructor takes one parameter, the conditions that mongoose passed to `updateOne()` when trying to update the document.

 
### Error.MissingSchemaError


##### Type:


* «property»



Thrown when you try to access a model that has not been registered yet

 
### Error.MongooseServerSelectionError


##### Type:


* «property»



Thrown when the MongoDB Node driver can't connect to a valid server to send an operation to.

 
### Error.OverwriteModelError


##### Type:


* «property»



Thrown when a model with the given name was already registered on the connection. See [the FAQ about `OverwriteModelError`](https://mongoosejs.com/docs/faq.html#overwrite-model-error).

 
### Error.ParallelSaveError


##### Type:


* «property»



An instance of this error class will be returned when you call `save()` multiple times on the same document in parallel. See the [FAQ](https://mongoosejs.com/docs/faq.html) for more information.

 
### Error.StrictModeError


##### Type:


* «property»



Thrown when your try to pass values to model constructor that were not specified in schema or change immutable properties when `strict` mode is `"throw"`

 
### Error.StrictPopulateError


##### Type:


* «property»



An instance of this error class will be returned when mongoose failed to populate with a path that is not existing.

 
### Error.ValidationError


##### Type:


* «property»



An instance of this error class will be returned when [validation](../validation) failed. The `errors` property contains an object whose keys are the paths that failed and whose values are instances of CastError or ValidationError.

 
### Error.ValidatorError


##### Type:


* «property»



A `ValidationError` has a hash of `errors` that contain individual `ValidatorError` instances.

 ####   [Example:](#example)

 
```
const schema = Schema({ name: { type: String, required: true } });
const Model = mongoose.model('Test', schema);
const doc = new Model({});

// Top-level error is a ValidationError, \*\*not\*\* a ValidatorError
const err = doc.validateSync();
err instanceof mongoose.Error.ValidationError; // true

// A ValidationError `err` has 0 or more ValidatorErrors keyed by the
// path in the `err.errors` property.
err.errors['name'] instanceof mongoose.Error.ValidatorError;

err.errors['name'].kind; // 'required'
err.errors['name'].path; // 'name'
err.errors['name'].value; // undefined

```
 Instances of `ValidatorError` have the following properties:

 * `kind`: The validator's `type`, like `'required'` or `'regexp'`
* `path`: The path that failed validation
* `value`: The value that failed validation

 
### Error.VersionError


##### Type:


* «property»



An instance of this error class will be returned when you call `save()` after the document in the database was changed in a potentially unsafe way. See the [`versionKey` option](../guide#versionKey) for more information.

 
### Error.messages


##### Type:


* «property»


##### See:


* [Error.messages](#Error.messages)



The default built-in validator error messages.

 
### Error.prototype.name


##### Type:


* «String»



The name of the error. The name uniquely identifies this Mongoose error. The possible values are:

 * `MongooseError`: general Mongoose error
* `CastError`: Mongoose could not convert a value to the type defined in the schema path. May be in a `ValidationError` class' `errors` property.
* `DivergentArrayError`: You attempted to `save()` an array that was modified after you loaded it with a `$elemMatch` or similar projection
* `MissingSchemaError`: You tried to access a model with [`mongoose.model()`](mongoose#Mongoose.model()) that was not defined
* `DocumentNotFoundError`: The document you tried to [`save()`](document#Document.prototype.save()) was not found
* `ValidatorError`: error from an individual schema path's validator
* `ValidationError`: error returned from [`validate()`](document#Document.prototype.validate()) or [`validateSync()`](document#Document.prototype.validateSync()). Contains zero or more `ValidatorError` instances in `.errors` property.
* `MissingSchemaError`: You called `mongoose.Document()` without a schema
* `ObjectExpectedError`: Thrown when you set a nested path to a non-object value with [strict mode set](../guide#strict).
* `ObjectParameterError`: Thrown when you pass a non-object value to a function which expects an object as a paramter
* `OverwriteModelError`: Thrown when you call [`mongoose.model()`](mongoose#Mongoose.model()) to re-define a model that was already defined.
* `ParallelSaveError`: Thrown when you call [`save()`](model#Model.prototype.save()) on a document when the same document instance is already saving.
* `StrictModeError`: Thrown when you set a path that isn't the schema and [strict mode](../guide#strict) is set to `throw`.
* `VersionError`: Thrown when the [document is out of sync](../guide#versionKey)

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/error.html>

Middleware
===========

 Middleware (also called pre and post *hooks*) are functions which are passed control during execution of asynchronous functions. Middleware is specified on the schema level and is useful for writing <plugins>.

  Types of Middleware
--------------------

 Mongoose has 4 types of middleware: document middleware, model middleware, aggregate middleware, and query middleware.

 Document middleware is supported for the following document functions. In Mongoose, a document is an instance of a `Model` class. In document middleware functions, `this` refers to the document. To access the model, use `this.constructor`.

 * [validate](api/document#document_Document-validate)
* [save](api/model#model_Model-save)
* [remove](api/model#model_Model-remove)
* [updateOne](api/document#document_Document-updateOne)
* [deleteOne](api/model#model_Model-deleteOne)
* [init](api/document#document_Document-init) (note: init hooks are [synchronous](#synchronous))

 Query middleware is supported for the following Query functions. Query middleware executes when you call `exec()` or `then()` on a Query object, or `await` on a Query object. In query middleware functions, `this` refers to the query.

 * [count](api/query#query_Query-count)
* [countDocuments](api/query#query_Query-countDocuments)
* [deleteMany](api/query#query_Query-deleteMany)
* [deleteOne](api/query#query_Query-deleteOne)
* [estimatedDocumentCount](api/query#query_Query-estimatedDocumentCount)
* [find](api/query#query_Query-find)
* [findOne](api/query#query_Query-findOne)
* [findOneAndDelete](api/query#query_Query-findOneAndDelete)
* [findOneAndRemove](api/query#query_Query-findOneAndRemove)
* [findOneAndReplace](api/query#query_Query-findOneAndReplace)
* [findOneAndUpdate](api/query#query_Query-findOneAndUpdate)
* [remove](api/model#model_Model-remove)
* [replaceOne](api/query#query_Query-replaceOne)
* [update](api/query#query_Query-update)
* [updateOne](api/query#query_Query-updateOne)
* [updateMany](api/query#query_Query-updateMany)
* [validate](validation#update-validators)

 Aggregate middleware is for `MyModel.aggregate()`. Aggregate middleware executes when you call `exec()` on an aggregate object. In aggregate middleware, `this` refers to the [aggregation object](api/model#model_Model-aggregate).

 * [aggregate](api/model#model_Model-aggregate)

 Model middleware is supported for the following model functions. Don't confuse model middleware and document middleware: model middleware hooks into *static* functions on a `Model` class, document middleware hooks into *methods* on a `Model` class. In model middleware functions, `this` refers to the model.

 * [insertMany](api/model#model_Model-insertMany)

 Here are the possible strings that can be passed to `pre()`

 * aggregate
* count
* countDocuments
* deleteOne
* deleteMany
* estimatedDocumentCount
* find
* findOne
* findOneAndDelete
* findOneAndRemove
* findOneAndReplace
* findOneAndUpdate
* init
* insertMany
* remove
* replaceOne
* save
* update
* updateOne
* updateMany
* validate

 All middleware types support pre and post hooks. How pre and post hooks work is described in more detail below.

 **Note:** If you specify `schema.pre('remove')`, Mongoose will register this middleware for [`doc.remove()`](api/model#model_Model-remove) by default. If you want your middleware to run on [`Query.remove()`](api/query#query_Query-remove) use [`schema.pre('remove', { query: true, document: false }, fn)`](api/schema#schema_Schema-pre).

 **Note:** Unlike `schema.pre('remove')`, Mongoose registers `updateOne` and `deleteOne` middleware on `Query#updateOne()` and `Query#deleteOne()` by default. This means that both `doc.updateOne()` and `Model.updateOne()` trigger `updateOne` hooks, but `this` refers to a query, not a document. To register `updateOne` or `deleteOne` middleware as document middleware, use `schema.pre('updateOne', { document: true, query: false })`.

 **Note:** The [`create()`](api/model#model_Model-create) function fires `save()` hooks.

 **Note:** Query middlewares are not executed on subdocuments.

 
```
const childSchema = new mongoose.Schema({
  name: String
});

const mainSchema = new mongoose.Schema({
  child: [childSchema]
});

mainSchema.pre('findOneAndUpdate', function() {
  console.log('Middleware on parent document'); // Will be executed
});

childSchema.pre('findOneAndUpdate', function() {
  console.log('Middleware on subdocument'); // Will not be executed
});

```
 Pre
---

 Pre middleware functions are executed one after another, when each middleware calls `next`.

 
```
const schema = new Schema({ /\* ... \*/ });
schema.pre('save', function(next) {
  // do stuff
  next();
});

```
 In [mongoose 5.x](http://thecodebarbarian.com/introducing-mongoose-5.html#promises-and-async-await-with-middleware), instead of calling `next()` manually, you can use a function that returns a promise. In particular, you can use [`async/await`](http://thecodebarbarian.com/common-async-await-design-patterns-in-node.js.html).

 
```
schema.pre('save', function() {
  return doStuff().
    then(() => doMoreStuff());
});

// Or, in Node.js >= 7.6.0:
schema.pre('save', async function() {
  await doStuff();
  await doMoreStuff();
});

```
 If you use `next()`, the `next()` call does **not** stop the rest of the code in your middleware function from executing. Use [the early `return` pattern](https://www.bennadel.com/blog/2323-use-a-return-statement-when-invoking-callbacks-especially-in-a-guard-statement.htm) to prevent the rest of your middleware function from running when you call `next()`.

 
```
const schema = new Schema({ /\* ... \*/ });
schema.pre('save', function(next) {
  if (foo()) {
    console.log('calling next!');
    // `return next();` will make sure the rest of this function doesn't run
    /\* return \*/ next();
  }
  // Unless you comment out the `return` above, 'after next' will print
  console.log('after next');
});

```
 ### Use Cases

 Middleware are useful for atomizing model logic. Here are some other ideas:

 * complex validation
* removing dependent documents (removing a user removes all their blogposts)
* asynchronous defaults
* asynchronous tasks that a certain action triggers

 ### Errors in Pre Hooks

 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 and/or reject the returned promise. There are several ways to report an error in middleware:

 
```
schema.pre('save', function(next) {
  const err = new Error('something went wrong');
  // If you call `next()` with an argument, that argument is assumed to be
  // an error.
  next(err);
});

schema.pre('save', function() {
  // You can also return a promise that rejects
  return new Promise((resolve, reject) => {
    reject(new Error('something went wrong'));
  });
});

schema.pre('save', function() {
  // You can also throw a synchronous error
  throw new Error('something went wrong');
});

schema.pre('save', async function() {
  await Promise.resolve();
  // You can also throw an error in an `async` function
  throw new Error('something went wrong');
});

// later...

// Changes will not be persisted to MongoDB because a pre hook errored out
myDoc.save(function(err) {
  console.log(err.message); // something went wrong
});

```
 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](https://mongoosejs.com/docs/api.html#schema_Schema-post) middleware are executed *after* the hooked method and all of its `pre` middleware have completed.

 
```
schema.post('init', function(doc) {
  console.log('%s has been initialized from the db', doc.\_id);
});
schema.post('validate', function(doc) {
  console.log('%s has been validated (but not saved yet)', doc.\_id);
});
schema.post('save', function(doc) {
  console.log('%s has been saved', doc.\_id);
});
schema.post('remove', function(doc) {
  console.log('%s has been removed', doc.\_id);
});

```
 Asynchronous Post Hooks
-----------------------

 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.

 
```
// Takes 2 parameters: this is an asynchronous post hook
schema.post('save', function(doc, next) {
  setTimeout(function() {
    console.log('post1');
    // Kick off the second post hook
    next();
  }, 10);
});

// Will not execute until the first middleware calls `next()`
schema.post('save', function(doc, next) {
  console.log('post2');
  next();
});

```
 Define Middleware Before Compiling Models
-----------------------------------------

 Calling `pre()` or `post()` after [compiling a model](models#compiling) does **not** work in Mongoose in general. For example, the below `pre('save')` middleware will not fire.

 
```
const schema = new mongoose.Schema({ name: String });

// Compile a model from the schema
const User = mongoose.model('User', schema);

// Mongoose will \*\*not\*\* call the middleware function, because
// this middleware was defined after the model was compiled
schema.pre('save', () => console.log('Hello from pre save'));

const user = new User({ name: 'test' });
user.save();

```
 This means that you must add all middleware and <plugins> **before** calling [`mongoose.model()`](api/mongoose#mongoose_Mongoose-model). The below script will print out "Hello from pre save":

 
```
const schema = new mongoose.Schema({ name: String });
// Mongoose will call this middleware function, because this script adds
// the middleware to the schema before compiling the model.
schema.pre('save', () => console.log('Hello from pre save'));

// Compile a model from the schema
const User = mongoose.model('User', schema);

const user = new User({ name: 'test' });
user.save();

```
 As a consequence, be careful about exporting Mongoose models from the same file that you define your schema. If you choose to use this pattern, you must define [global plugins](api/mongoose#mongoose_Mongoose-plugin) **before** calling `require()` on your model file.

 
```
const schema = new mongoose.Schema({ name: String });

// Once you `require()` this file, you can no longer add any middleware
// to this schema.
module.exports = mongoose.model('User', schema);

```
 Save/Validate Hooks
-------------------

 The `save()` function triggers `validate()` hooks, because mongoose has a built-in `pre('save')` hook that calls `validate()`. This means that all `pre('validate')` and `post('validate')` hooks get called **before** any `pre('save')` hooks.

 
```
schema.pre('validate', function() {
  console.log('this gets printed first');
});
schema.post('validate', function() {
  console.log('this gets printed second');
});
schema.pre('save', function() {
  console.log('this gets printed third');
});
schema.post('save', function() {
  console.log('this gets printed fourth');
});

```
 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).

 
```
const userSchema = new Schema({ name: String, age: Number });
userSchema.pre('findOneAndUpdate', function() {
  console.log(this.getFilter()); // { name: 'John' }
  console.log(this.getUpdate()); // { age: 30 }
});
const User = mongoose.model('User', userSchema);

await User.findOneAndUpdate({ name: 'John' }, { $set: { age: 30 } });

```
 For document middleware, like `pre('save')`, Mongoose passes the 1st parameter to `save()` as the 2nd argument to your `pre('save')` callback. You should use the 2nd argument to get access to the `save()` call's `options`, because Mongoose documents don't store all the options you can pass to `save()`.

 
```
const userSchema = new Schema({ name: String, age: Number });
userSchema.pre('save', function(next, options) {
  options.validateModifiedOnly; // true

  // Remember to call `next()` unless you're using an async function or returning a promise
  next();
});
const User = mongoose.model('User', userSchema);

const doc = new User({ name: 'John', age: 30 });
await doc.save({ validateModifiedOnly: true });

```
 Naming Conflicts
----------------

 Mongoose has both query and document hooks for `remove()`.

 
```
schema.pre('remove', function() { console.log('Removing!'); });

// Prints "Removing!"
doc.remove();

// Does \*\*not\*\* print "Removing!". Query middleware for `remove` is not
// executed by default.
Model.remove();

```
 You can pass options to [`Schema.pre()`](https://mongoosejs.com/docs/api.html#schema_Schema-pre) and [`Schema.post()`](https://mongoosejs.com/docs/api.html#schema_Schema-post) to switch whether Mongoose calls your `remove()` hook for [`Document.remove()`](api/model#model_Model-remove) or [`Model.remove()`](api/model#model_Model-remove). Note here that you need to set both `document` and `query` properties in the passed object:

 
```
// Only document middleware
schema.pre('remove', { document: true, query: false }, function() {
  console.log('Removing doc!');
});

// Only query middleware. This will get called when you do `Model.remove()`
// but not `doc.remove()`.
schema.pre('remove', { query: true, document: false }, function() {
  console.log('Removing!');
});

```
 Notes on findAndUpdate() and Query Middleware
---------------------------------------------

 Pre and post `save()` hooks are **not** executed on `update()`, `findOneAndUpdate()`, etc. You can see a more detailed discussion why in [this GitHub issue](http://github.com/Automattic/mongoose/issues/964). Mongoose 4.0 introduced distinct hooks for these functions.

 
```
schema.pre('find', function() {
  console.log(this instanceof mongoose.Query); // true
  this.start = Date.now();
});

schema.post('find', function(result) {
  console.log(this instanceof mongoose.Query); // true
  // prints returned documents
  console.log('find() returned ' + JSON.stringify(result));
  // prints number of milliseconds the query took
  console.log('find() took ' + (Date.now() - this.start) + ' milliseconds');
});

```
 Query middleware differs from document middleware in a subtle but important way: in document middleware, `this` refers to the document being updated. In query middleware, mongoose doesn't necessarily have a reference to the document being updated, so `this` refers to the **query** object rather than the document being updated.

 For instance, if you wanted to add an `updatedAt` timestamp to every `updateOne()` call, you would use the following pre hook.

 
```
schema.pre('updateOne', function() {
  this.set({ updatedAt: new Date() });
});

```
 You **cannot** access the document being updated in `pre('updateOne')` or `pre('findOneAndUpdate')` query middleware. If you need to access the document that will be updated, you need to execute an explicit query for the document.

 
```
schema.pre('findOneAndUpdate', async function() {
  const docToUpdate = await this.model.findOne(this.getQuery());
  console.log(docToUpdate); // The document that `findOneAndUpdate()` will modify
});

```
 However, if you define `pre('updateOne')` document middleware, `this` will be the document being updated. That's because `pre('updateOne')` document middleware hooks into [`Document#updateOne()`](api/document#document_Document-updateOne) rather than `Query#updateOne()`.

 
```
schema.pre('updateOne', { document: true, query: false }, function() {
  console.log('Updating');
});
const Model = mongoose.model('Test', schema);

const doc = new Model();
await doc.updateOne({ $set: { name: 'test' } }); // Prints "Updating"

// Doesn't print "Updating", because `Query#updateOne()` doesn't fire
// document middleware.
await Model.updateOne({}, { $set: { name: 'test' } });

```
 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 middleware called "error handling middleware" that executes specifically when an error occurs. Error handling middleware is useful for reporting errors and making error messages more readable.

 Error handling middleware is defined as middleware that takes one extra parameter: the 'error' that occurred as the first parameter to the function. Error handling middleware can then transform the error however you want.

 
```
const schema = new Schema({
  name: {
    type: String,
    // Will trigger a MongoServerError with code 11000 when
    // you save a duplicate
    unique: true
  }
});

// Handler \*\*must\*\* take 3 parameters: the error that occurred, the document
// in question, and the `next()` function
schema.post('save', function(error, doc, next) {
  if (error.name === 'MongoServerError' && error.code === 11000) {
    next(new Error('There was a duplicate key error'));
  } else {
    next();
  }
});

// Will trigger the `post('save')` error handler
Person.create([{ name: 'Axl Rose' }, { name: 'Axl Rose' }]);

```
 Error handling middleware also works with query middleware. You can also define a post `update()` hook that will catch MongoDB duplicate key errors.

 
```
// The same E11000 error can occur when you call `update()`
// This function \*\*must\*\* take 3 parameters. If you use the
// `passRawResult` function, this function \*\*must\*\* take 4
// parameters
schema.post('update', function(error, res, next) {
  if (error.name === 'MongoServerError' && error.code === 11000) {
    next(new Error('There was a duplicate key error'));
  } else {
    next(); // The `update()` call will still error out.
  }
});

const people = [{ name: 'Axl Rose' }, { name: 'Slash' }];
await Person.create(people);

// Throws "There was a duplicate key error"
await Person.update({ name: 'Slash' }, { $set: { name: 'Axl Rose' } });

```
 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
-----------------

 You can also define hooks for the [`Model.aggregate()` function](api/model#model_Model-aggregate). In aggregation middleware functions, `this` refers to the [Mongoose `Aggregate` object](api/aggregate#Aggregate). For example, suppose you're implementing soft deletes on a `Customer` model by adding an `isDeleted` property. To make sure `aggregate()` calls only look at customers that aren't soft deleted, you can use the below middleware to add a [`$match` stage](api/aggregate#aggregate_Aggregate-match) to the beginning of each [aggregation pipeline](https://www.mongodb.com/docs/manual/core/aggregation-pipeline/).

 
```
customerSchema.pre('aggregate', function() {
  // Add a $match state to the beginning of each pipeline.
  this.pipeline().unshift({ $match: { isDeleted: { $ne: true } } });
});

```
 The [`Aggregate#pipeline()` function](api/aggregate#aggregate_Aggregate-pipeline) 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
-----------------

 Certain Mongoose hooks are synchronous, which means they do **not** support functions that return promises or receive a `next()` callback. Currently, only `init` hooks are synchronous, because the [`init()` function](api/document#document_Document-init) is synchronous. Below is an example of using pre and post init hooks.

 
```
const schema = new Schema({ title: String, loadedAt: Date });

schema.pre('init', pojo => {
  assert.equal(pojo.constructor.name, 'Object'); // Plain object before init
});

const now = new Date();
schema.post('init', doc => {
  assert.ok(doc instanceof mongoose.Document); // Mongoose doc after init
  doc.loadedAt = now;
});

const Test = db.model('Test', schema);

return Test.create({ title: 'Casino Royale' }).
  then(doc => Test.findById(doc)).
  then(doc => assert.equal(doc.loadedAt.valueOf(), now.valueOf()));

```
 To report an error in an init hook, you must throw a **synchronous** error. Unlike all other middleware, init middleware does **not** handle promise rejections.

 
```
const schema = new Schema({ title: String });

const swallowedError = new Error('will not show');
// init hooks do \*\*not\*\* handle async errors or any sort of async behavior
schema.pre('init', () => Promise.reject(swallowedError));
schema.post('init', () => { throw Error('will show'); });

const Test = db.model('Test', schema);

return Test.create({ title: 'Casino Royale' }).
  then(doc => Test.findById(doc)).
  catch(error => assert.equal(error.message, 'will show'));

```
 Next Up
-------

 Now that we've covered middleware, let's take a look at Mongoose's approach to faking JOINs with its query [population](populate) helper.



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/middleware.html>

Defaults
=========

  Declaring Defaults in Your Schema
----------------------------------

 Your schemas can define default values for certain paths. If you create a new document without that path set, the default will kick in.

 Note: Mongoose only applies a default if the value of the path is strictly `undefined`.

 
```
const schema = new Schema({
  name: String,
  role: { type: String, default: 'guitarist' }
});

const Person = db.model('Person', schema);

const axl = new Person({ name: 'Axl Rose', role: 'singer' });
assert.equal(axl.role, 'singer');

const slash = new Person({ name: 'Slash' });
assert.equal(slash.role, 'guitarist');

const izzy = new Person({ name: 'Izzy', role: undefined });
assert.equal(izzy.role, 'guitarist');

// Defaults do \*\*not\*\* run on `null`, `''`, or value other than `undefined`.
const foo = new Person({ name: 'Bar', role: null });
assert.strictEqual(foo.role, null);

await Person.create(axl, slash);

const docs = await Person.find({ role: 'guitarist' });

assert.equal(docs.length, 1);
assert.equal(docs[0].name, 'Slash');

```
  Default Functions
------------------

 You can also set the `default` schema option to a function. Mongoose will execute that function and use the return value as the default.

 
```
const schema = new Schema({
  title: String,
  date: {
    type: Date,
    // `Date.now()` returns the current unix timestamp as a number
    default: Date.now
  }
});

const BlogPost = db.model('BlogPost', schema);

const post = new BlogPost({ title: '5 Best Arnold Schwarzenegger Movies' });

// The post has a default Date set to now
assert.ok(post.date.getTime() >= Date.now() - 1000);
assert.ok(post.date.getTime() <= Date.now());

```
  The `setDefaultsOnInsert` Option
---------------------------------

 Mongoose also sets defaults on `update()` and `findOneAndUpdate()` when the `upsert` option is set by adding your schema's defaults to a [MongoDB `$setOnInsert` operator](https://www.mongodb.com/docs/manual/reference/operator/update/setOnInsert/). You can disable this behavior by setting the `setDefaultsOnInsert` option to `false`.

 
```
const schema = new Schema({
  title: String,
  genre: { type: String, default: 'Action' }
});

const Movie = db.model('Movie', schema);

const query = {};
const update = { title: 'The Terminator' };
const options = {
  // Return the document after updates are applied
  new: true,
  // Create a document if one isn't found.
  upsert: true
};

let doc = await Movie.findOneAndUpdate(query, update, options).lean();
doc.genre; // 'Action', Mongoose set a default value.

await Movie.deleteMany({});

doc = await Movie.findOneAndUpdate(query, update, { new: true, upsert: true, setDefaultsOnInsert: false }).lean();
doc.genre; // undefined, Mongoose did not set a default value

```
 You can also set `setDefaultsOnInsert` to `false` globally:

 
```
mongoose.set('setDefaultsOnInsert', false);

```
  Default functions and `this`
-----------------------------

 Unless it is running on a query with `setDefaultsOnInsert`, a default function's `this` refers to the document.

 
```
const schema = new Schema({
  title: String,
  released: Boolean,
  releaseDate: {
    type: Date,
    default: function() {
      if (this.released) {
        return Date.now();
      }
      return null;
    }
  }
});

const Movie = db.model('Movie', schema);

const movie1 = new Movie({ title: 'The Terminator', released: true });

// The post has a default Date set to now
assert.ok(movie1.releaseDate.getTime() >= Date.now() - 1000);
assert.ok(movie1.releaseDate.getTime() <= Date.now());

const movie2 = new Movie({ title: 'The Legend of Conan', released: false });

// Since `released` is false, the default function will return null
assert.strictEqual(movie2.releaseDate, null);

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/defaults.html>

SchemaArray
===========



### SchemaArray()


##### Parameters:


* `key` «String»
* `cast` «SchemaType»
* `options` «Object»
* `schemaOptions` «Object»


##### Inherits:


* [«SchemaType»](schematype)



Array SchemaType constructor

 
### SchemaArray.checkRequired()


##### Parameters:


* `fn` «Function»


##### Returns:


* «Function»



Override the function the required validator uses to check whether an array passes the `required` check.

 ####   [Example:](#example)

 
```
// Require non-empty array to pass `required` check
mongoose.Schema.Types.Array.checkRequired(v => Array.isArray(v) && v.length);

const M = mongoose.model({ arr: { type: Array, required: true } });
new M({ arr: [] }).validateSync(); // `null`, validation fails!

```
 
### SchemaArray.get()


##### Parameters:


* `getter` «Function»


##### Returns:


* «this»


##### Type:


* «property»



Attaches a getter for all Array instances

 
### SchemaArray.options


##### Type:


* «property»



Options for all arrays.

 * `castNonArrays`: `true` by default. If `false`, Mongoose will throw a CastError when a value isn't an array. If `true`, Mongoose will wrap the provided value in an array before casting.

 
### SchemaArray.prototype.checkRequired()


##### Parameters:


* `value` «Any»
* `doc` «Document»


##### Returns:


* «Boolean»



Check if the given value satisfies the `required` validator.

 
### SchemaArray.prototype.enum()


##### Parameters:


* `[...args]` «String|Object» enumeration values


##### Returns:


* «SchemaArray» this



Adds an enum validator if this is an array of strings or numbers. Equivalent to `SchemaString.prototype.enum()` or `SchemaNumber.prototype.enum()`

 
### SchemaArray.schemaName


##### Type:


* «property»



This schema type's name, to defend against minifiers that mangle function names.

 
### SchemaArray.set()


##### Parameters:


* `option` «String» The option you'd like to set the value for
* `value` «Any» value for option


##### Returns:


* «undefined,void»



Sets a default option for all Array instances.

 ####   [Example:](#example)

 
```
// Make all Array instances have `required` of true by default.
mongoose.Schema.Array.set('required', true);

const User = mongoose.model('User', new Schema({ test: Array }));
new User({ }).validateSync().errors.test.message; // Path `test` is required.

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schemaarray.html>

DocumentArrayPath
=================



### DocumentArrayPath()


##### Parameters:


* `key` «String»
* `schema` «Schema»
* `options` «Object»
* `schemaOptions` «Object»


##### Inherits:


* [«SchemaArray»](schemaarray)



SubdocsArray SchemaType constructor

 
### DocumentArrayPath.get()


##### Parameters:


* `getter` «Function»


##### Returns:


* «this»


##### Type:


* «property»



Attaches a getter for all DocumentArrayPath instances

 
### DocumentArrayPath.options


##### Type:


* «property»



Options for all document arrays.

 * `castNonArrays`: `true` by default. If `false`, Mongoose will throw a CastError when a value isn't an array. If `true`, Mongoose will wrap the provided value in an array before casting.

 
### DocumentArrayPath.prototype.discriminator()


##### Parameters:


* `name` «String»
* `schema` «Schema» fields to add to the schema for instances of this sub-class
* `[options]` «Object|string» If string, same as `options.value`.
+ `[options.value]` «String» the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
+ `[options.clone=true]` «Boolean» By default, `discriminator()` clones the given `schema`. Set to `false` to skip cloning.


##### Returns:


* «Function» the constructor Mongoose will use for creating instances of this discriminator model


##### See:


* [discriminators](../discriminators)



Adds a discriminator to this document array.

 ####   [Example:](#example)

 
```
const shapeSchema = Schema({ name: String }, { discriminatorKey: 'kind' });
const schema = Schema({ shapes: [shapeSchema] });

const docArrayPath = parentSchema.path('shapes');
docArrayPath.discriminator('Circle', Schema({ radius: Number }));

```
 
### DocumentArrayPath.schemaName


##### Type:


* «property»



This schema type's name, to defend against minifiers that mangle function names.

 
### DocumentArrayPath.set()


##### Parameters:


* `option` «String» The name of the option you'd like to set (e.g. trim, lowercase, etc...)
* `value` «Any» The value of the option you'd like to set.


##### Returns:


* «void,void»


##### Type:


* «property»



Sets a default option for all DocumentArray instances.

 ####   [Example:](#example)

 
```
// Make all numbers have option `min` equal to 0.
mongoose.Schema.DocumentArray.set('\_id', false);

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/documentarraypath.html>

SubdocumentPath
===============



### SubdocumentPath()


##### Parameters:


* `schema` «Schema»
* `path` «String»
* `options` «Object»


##### Inherits:


* [«SchemaType»](schematype)



Single nested subdocument SchemaType constructor.

 
### SubdocumentPath.get()


##### Parameters:


* `getter` «Function»


##### Returns:


* «this»


##### Type:


* «property»



Attaches a getter for all SubdocumentPath instances

 
### SubdocumentPath.prototype.discriminator()


##### Parameters:


* `name` «String»
* `schema` «Schema» fields to add to the schema for instances of this sub-class
* `[options]` «Object|string» If string, same as `options.value`.
+ `[options.value]` «String» the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
+ `[options.clone=true]` «Boolean» By default, `discriminator()` clones the given `schema`. Set to `false` to skip cloning.


##### Returns:


* «Function» the constructor Mongoose will use for creating instances of this discriminator model


##### See:


* [discriminators](../discriminators)



Adds a discriminator to this single nested subdocument.

 ####   [Example:](#example)

 
```
const shapeSchema = Schema({ name: String }, { discriminatorKey: 'kind' });
const schema = Schema({ shape: shapeSchema });

const singleNestedPath = parentSchema.path('shape');
singleNestedPath.discriminator('Circle', Schema({ radius: Number }));

```
 
### SubdocumentPath.set()


##### Parameters:


* `option` «String» The option you'd like to set the value for
* `value` «Any» value for option


##### Returns:


* «void,void»


##### Type:


* «property»



Sets a default option for all SubdocumentPath instances.

 ####   [Example:](#example)

 
```
// Make all numbers have option `min` equal to 0.
mongoose.Schema.SubdocumentPath.set('required', true);

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/subdocumentpath.html>

SchemaBoolean
=============



### SchemaBoolean()


##### Parameters:


* `path` «String»
* `options` «Object»


##### Inherits:


* [«SchemaType»](schematype)



Boolean SchemaType constructor.

 
### SchemaBoolean.checkRequired()


##### Parameters:


* `fn` «Function»


##### Returns:


* «Function»


##### Type:


* «property»



Override the function the required validator uses to check whether a boolean passes the `required` check.

 
### SchemaBoolean.convertToFalse


##### Type:


* «Set»



Configure which values get casted to `false`.

 ####   [Example:](#example)

 
```
const M = mongoose.model('Test', new Schema({ b: Boolean }));
new M({ b: 'nay' }).b; // undefined
mongoose.Schema.Types.Boolean.convertToFalse.add('nay');
new M({ b: 'nay' }).b; // false

```
 
### SchemaBoolean.convertToTrue


##### Type:


* «Set»



Configure which values get casted to `true`.

 ####   [Example:](#example)

 
```
const M = mongoose.model('Test', new Schema({ b: Boolean }));
new M({ b: 'affirmative' }).b; // undefined
mongoose.Schema.Boolean.convertToTrue.add('affirmative');
new M({ b: 'affirmative' }).b; // true

```
 
### SchemaBoolean.get()


##### Parameters:


* `getter` «Function»


##### Returns:


* «this»


##### Type:


* «property»



Attaches a getter for all Boolean instances

 ####   [Example:](#example)

 
```
mongoose.Schema.Boolean.get(v => v === true ? 'yes' : 'no');

const Order = mongoose.model('Order', new Schema({ isPaid: Boolean }));
new Order({ isPaid: false }).isPaid; // 'no'

```
 
### SchemaBoolean.get()


##### Parameters:


* `caster` «Function»


##### Returns:


* «Function»


##### Type:


* «property»



Get/set the function used to cast arbitrary values to booleans.

 ####   [Example:](#example)

 
```
// Make Mongoose cast empty string '' to false.
const original = mongoose.Schema.Boolean.cast();
mongoose.Schema.Boolean.cast(v => {
  if (v === '') {
    return false;
  }
  return original(v);
});

// Or disable casting entirely
mongoose.Schema.Boolean.cast(false);

```
 
### SchemaBoolean.prototype.checkRequired()


##### Parameters:


* `value` «Any»


##### Returns:


* «Boolean»



Check if the given value satisfies a required validator. For a boolean to satisfy a required validator, it must be strictly equal to true or to false.

 
### SchemaBoolean.schemaName


##### Type:


* «property»



This schema type's name, to defend against minifiers that mangle function names.

 
### SchemaBoolean.set()


##### Parameters:


* `option` «String» The option you'd like to set the value for
* `value` «Any» value for option


##### Returns:


* «undefined,void»


##### Type:


* «property»



Sets a default option for all Boolean instances.

 ####   [Example:](#example)

 
```
// Make all booleans have `default` of false.
mongoose.Schema.Boolean.set('default', false);

const Order = mongoose.model('Order', new Schema({ isPaid: Boolean }));
new Order({ }).isPaid; // false

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schemaboolean.html>

SchemaBuffer
============



### SchemaBuffer()


##### Parameters:


* `key` «String»
* `options` «Object»


##### Inherits:


* [«SchemaType»](schematype)



Buffer SchemaType constructor

 
### SchemaBuffer.checkRequired()


##### Parameters:


* `fn` «Function»


##### Returns:


* «Function»


##### Type:


* «property»



Override the function the required validator uses to check whether a string passes the `required` check.

 ####   [Example:](#example)

 
```
// Allow empty strings to pass `required` check
mongoose.Schema.Types.String.checkRequired(v => v != null);

const M = mongoose.model({ buf: { type: Buffer, required: true } });
new M({ buf: Buffer.from('') }).validateSync(); // validation passes!

```
 
### SchemaBuffer.get()


##### Parameters:


* `getter` «Function»


##### Returns:


* «this»


##### Type:


* «property»



Attaches a getter for all Buffer instances

 ####   [Example:](#example)

 
```
// Always convert to string when getting an ObjectId
mongoose.Schema.Types.Buffer.get(v => v.toString('hex'));

const Model = mongoose.model('Test', new Schema({ buf: Buffer } }));
typeof (new Model({ buf: Buffer.fromString('hello') }).buf); // 'string'

```
 
### SchemaBuffer.prototype.checkRequired()


##### Parameters:


* `value` «Any»
* `doc` «Document»


##### Returns:


* «Boolean»



Check if the given value satisfies a required validator. To satisfy a required validator, a buffer must not be null or undefined and have non-zero length.

 
### SchemaBuffer.prototype.subtype()


##### Parameters:


* `subtype` «Number» the default subtype


##### Returns:


* «SchemaType» this



Sets the default [subtype](https://studio3t.com/whats-new/best-practices-uuid-mongodb/) for this buffer. You can find a [list of allowed subtypes here](https://api.mongodb.com/python/current/api/bson/binary.html).

 ####   [Example:](#example)

 
```
const s = new Schema({ uuid: { type: Buffer, subtype: 4 });
const M = db.model('M', s);
const m = new M({ uuid: 'test string' });
m.uuid.\_subtype; // 4

```
 
### SchemaBuffer.schemaName


##### Type:


* «property»



This schema type's name, to defend against minifiers that mangle function names.

 
### SchemaBuffer.set()


##### Parameters:


* `option` «String» The option you'd like to set the value for
* `value` «Any» value for option


##### Returns:


* «undefined,void»


##### Type:


* «property»



Sets a default option for all Buffer instances.

 ####   [Example:](#example)

 
```
// Make all buffers have `required` of true by default.
mongoose.Schema.Buffer.set('required', true);

const User = mongoose.model('User', new Schema({ test: Buffer }));
new User({ }).validateSync().errors.test.message; // Path `test` is required.

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schemabuffer.html>

Decimal128
==========



### Decimal128()



Decimal128 type constructor

 ####   [Example:](#example)

 
```
const id = new mongoose.Types.Decimal128('3.1415');

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/decimal128.html>

Array
=====



### MongooseArray.prototype.$pop()


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/operator/update/pop/)



Pops the array atomically at most one time per document `save()`.

 ####   [NOTE:](#note)

 *Calling this multiple times on an array before saving sends the same command as calling it once.* *This update is implemented using the MongoDB [$pop](https://www.mongodb.com/docs/manual/reference/operator/update/pop/) method which enforces this restriction.*

 
```
 doc.array = [1,2,3];

 const popped = doc.array.$pop();
 console.log(popped); // 3
 console.log(doc.array); // [1,2]

 // no affect
 popped = doc.array.$pop();
 console.log(doc.array); // [1,2]

 doc.save(function (err) {
   if (err) return handleError(err);

   // we saved, now $pop works again
   popped = doc.array.$pop();
   console.log(popped); // 2
   console.log(doc.array); // [1]
 })

```
 
### MongooseArray.prototype.$shift()


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/operator/update/pop/)



Atomically shifts the array at most one time per document `save()`.

 ####   [Note:](#note)

 *Calling this multiple times on an array before saving sends the same command as calling it once.* *This update is implemented using the MongoDB [$pop](https://www.mongodb.com/docs/manual/reference/operator/update/pop/) method which enforces this restriction.*

 
```
 doc.array = [1,2,3];

 const shifted = doc.array.$shift();
 console.log(shifted); // 1
 console.log(doc.array); // [2,3]

 // no affect
 shifted = doc.array.$shift();
 console.log(doc.array); // [2,3]

 doc.save(function (err) {
   if (err) return handleError(err);

   // we saved, now $shift works again
   shifted = doc.array.$shift();
   console.log(shifted ); // 2
   console.log(doc.array); // [3]
 })

```
 
### MongooseArray.prototype.addToSet()


##### Parameters:


* `[...args]` «any»


##### Returns:


* «Array» the values that were added



Adds values to the array if not already present.

 ####   [Example:](#example)

 
```
console.log(doc.array) // [2,3,4]
const added = doc.array.addToSet(4,5);
console.log(doc.array) // [2,3,4,5]
console.log(added)     // [5]

```
 
### MongooseArray.prototype.includes()


##### Parameters:


* `obj` «Object» the item to check
* `fromIndex` «Number»


##### Returns:


* «Boolean»



Return whether or not the `obj` is included in the array.

 
### MongooseArray.prototype.indexOf()


##### Parameters:


* `obj` «Object» the item to look for
* `fromIndex` «Number»


##### Returns:


* «Number»



Return the index of `obj` or `-1` if not found.

 
### MongooseArray.prototype.inspect()



Helper for console.log

 
### MongooseArray.prototype.nonAtomicPush()


##### Parameters:


* `[...args]` «any»



Pushes items to the array non-atomically.

 ####   [Note:](#note)

 *marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.*

 
### MongooseArray.prototype.pop()


##### See:


* [MongooseArray#$pop](#MongooseArray.prototype.$pop())



Wraps [`Array#pop`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/pop) with proper change tracking.

 ####   [Note:](#note)

 *marks the entire array as modified which will pass the entire thing to $set potentially overwriting any changes that happen between when you retrieved the object and when you save it.*

 
### MongooseArray.prototype.pull()


##### Parameters:


* `[...args]` «any»


##### See:


* [mongodb](https://www.mongodb.com/docs/manual/reference/operator/update/pull/)



Pulls items from the array atomically. Equality is determined by casting the provided value to an embedded document and comparing using [the `Document.equals()` function.](document#Document.prototype.equals())

 ####   [Example:](#example)

 
```
doc.array.pull(ObjectId)
doc.array.pull({ \_id: 'someId' })
doc.array.pull(36)
doc.array.pull('tag 1', 'tag 2')

```
 To remove a document from a subdocument array we may pass an object with a matching `_id`.

 
```
doc.subdocs.push({ \_id: 4815162342 })
doc.subdocs.pull({ \_id: 4815162342 }) // removed

```
 Or we may passing the \_id directly and let mongoose take care of it.

 
```
doc.subdocs.push({ \_id: 4815162342 })
doc.subdocs.pull(4815162342); // works

```
 The first pull call will result in a atomic operation on the database, if pull is called repeatedly without saving the document, a $set operation is used on the complete array instead, overwriting possible changes that happened on the database in the meantime.

 
### MongooseArray.prototype.push()


##### Parameters:


* `[...args]` «Object»



Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.

 ####   [Example:](#example)

 
```
const schema = Schema({ nums: [Number] });
const Model = mongoose.model('Test', schema);

const doc = await Model.create({ nums: [3, 4] });
doc.nums.push(5); // Add 5 to the end of the array
await doc.save();

// You can also pass an object with `$each` as the
// first parameter to use MongoDB's `$position`
doc.nums.push({
  $each: [1, 2],
  $position: 0
});
doc.nums; // [1, 2, 3, 4, 5]

```
 
### MongooseArray.prototype.remove()


##### See:


* [MongooseArray#pull](#MongooseArray.prototype.pull())
* [mongodb](https://www.mongodb.com/docs/manual/reference/operator/update/pull/)



Alias of [pull](#MongooseArray.prototype.pull())

 
### MongooseArray.prototype.set()


##### Returns:


* «Array» this



Sets the casted `val` at index `i` and marks the array modified.

 ####   [Example:](#example)

 
```
// given documents based on the following
const Doc = mongoose.model('Doc', new Schema({ array: [Number] }));

const doc = new Doc({ array: [2,3,4] })

console.log(doc.array) // [2,3,4]

doc.array.set(1,"5");
console.log(doc.array); // [2,5,4] // properly cast to number
doc.save() // the change is saved

// VS not using array#set
doc.array[1] = "5";
console.log(doc.array); // [2,"5",4] // no casting
doc.save() // change is not saved

```
 
### MongooseArray.prototype.shift()



Wraps [`Array#shift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.

 ####   [Example:](#example)

 
```
doc.array = [2,3];
const res = doc.array.shift();
console.log(res) // 2
console.log(doc.array) // [3]

```
 ####   [Note:](#note)

 *marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.*

 
### MongooseArray.prototype.sort()


##### See:


* [MasteringJS: Array sort](https://masteringjs.io/tutorials/fundamentals/array-sort)



Wraps [`Array#sort`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort) with proper change tracking.

 ####   [Note:](#note)

 *marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.*

 
### MongooseArray.prototype.splice()


##### See:


* [MasteringJS: Array splice](https://masteringjs.io/tutorials/fundamentals/array-splice)



Wraps [`Array#splice`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice) with proper change tracking and casting.

 ####   [Note:](#note)

 *marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.*

 
### MongooseArray.prototype.toObject()


##### Parameters:


* `options` «Object»


##### Returns:


* «Array»



Returns a native js Array.

 
### MongooseArray.prototype.unshift()



Wraps [`Array#unshift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.

 ####   [Note:](#note)

 *marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it.*

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/array.html>

Transactions in Mongoose
=========================

 [Transactions](https://www.mongodb.com/transactions) are new in MongoDB 4.0 and Mongoose 5.2.0. Transactions let you execute multiple operations in isolation and potentially undo all the operations if one of them fails. This guide will get you started using transactions with Mongoose.

 Getting Started with Transactions
---------------------------------

 If you haven't already, import mongoose:

 
```
import mongoose from 'mongoose';

```
 To create a transaction, you first need to create a session using [`Mongoose#startSession`](api/mongoose#mongoose_Mongoose-startSession) or [`Connection#startSession()`](api/connection#connection_Connection-startSession).

 
```
// Using Mongoose's default connection
const session = await mongoose.startSession();

// Using custom connection
const db = await mongoose.createConnection(mongodbUri).asPromise();
const session = await db.startSession();

```
 In practice, you should use either the [`session.withTransaction()` helper](https://mongodb.github.io/node-mongodb-native/3.2/api/ClientSession.html#withTransaction) or Mongoose's `Connection#transaction()` function to run a transaction. The `session.withTransaction()` helper handles:

 * Creating a transaction
* Committing the transaction if it succeeds
* Aborting the transaction if your operation throws
* Retrying in the event of a [transient transaction error](https://stackoverflow.com/questions/52153538/what-is-a-transienttransactionerror-in-mongoose-or-mongodb).

 
```
let session = null;
return Customer.createCollection().
  then(() => Customer.startSession()).
  // The `withTransaction()` function's first parameter is a function
  // that returns a promise.
  then(\_session => {
    session = _session;
    return session.withTransaction(() => {
      return Customer.create([{ name: 'Test' }], { session: session });
    });
  }).
  then(() => Customer.countDocuments()).
  then(count => assert.strictEqual(count, 1)).
  then(() => session.endSession());

```
 For more information on the `ClientSession#withTransaction()` function, please see [the MongoDB Node.js driver docs](https://mongodb.github.io/node-mongodb-native/3.2/api/ClientSession.html#withTransaction).

 Mongoose's `Connection#transaction()` function is a wrapper around `withTransaction()` that integrates Mongoose change tracking with transactions. For example, suppose you `save()` a document in a transaction that later fails. The changes in that document are not persisted to MongoDB. The `Connection#transaction()` function informs Mongoose change tracking that the `save()` was rolled back, and marks all fields that were changed in the transaction as modified.

 
```
const doc = new Person({ name: 'Will Riker' });

await db.transaction(async function setRank(session) {
  doc.name = 'Captain';
  await doc.save({ session });
  doc.isNew; // false

  // Throw an error to abort the transaction
  throw new Error('Oops!');
}, { readPreference: 'primary' }).catch(() => {});

// true, `transaction()` reset the document's state because the
// transaction was aborted.
doc.isNew;

```
 With Mongoose Documents and `save()`
------------------------------------

 If you get a [Mongoose document](documents) from [`findOne()`](api/model#model_Model-findOne) or [`find()`](api/model#model_Model-find) using a session, the document will keep a reference to the session and use that session for [`save()`](api/document#document_Document-save).

 To get/set the session associated with a given document, use [`doc.$session()`](api/document#document_Document-$session).

 
```
const User = db.model('User', new Schema({ name: String }));

let session = null;
return User.createCollection().
  then(() => db.startSession()).
  then(\_session => {
    session = _session;
    return User.create({ name: 'foo' });
  }).
  then(() => {
    session.startTransaction();
    return User.findOne({ name: 'foo' }).session(session);
  }).
  then(user => {
    // Getter/setter for the session associated with this document.
    assert.ok(user.$session());
    user.name = 'bar';
    // By default, `save()` uses the associated session
    return user.save();
  }).
  then(() => User.findOne({ name: 'bar' })).
  // Won't find the doc because `save()` is part of an uncommitted transaction
  then(doc => assert.ok(!doc)).
  then(() => session.commitTransaction()).
  then(() => session.endSession()).
  then(() => User.findOne({ name: 'bar' })).
  then(doc => assert.ok(doc));

```
 With the Aggregation Framework
------------------------------

 The `Model.aggregate()` function also supports transactions. Mongoose aggregations have a [`session()` helper](api/aggregate#aggregate_Aggregate-session) that sets the [`session` option](api/aggregate#aggregate_Aggregate-option). Below is an example of executing an aggregation within a transaction.

 
```
const Event = db.model('Event', new Schema({ createdAt: Date }), 'Event');

let session = null;
return Event.createCollection().
  then(() => db.startSession()).
  then(\_session => {
    session = _session;
    session.startTransaction();
    return Event.insertMany([
      { createdAt: new Date('2018-06-01') },
      { createdAt: new Date('2018-06-02') },
      { createdAt: new Date('2017-06-01') },
      { createdAt: new Date('2017-05-31') }
    ], { session: session });
  }).
  then(() => Event.aggregate([
    {
      $group: {
        \_id: {
          month: { $month: '$createdAt' },
          year: { $year: '$createdAt' }
        },
        count: { $sum: 1 }
      }
    },
    { $sort: { count: -1, '\_id.year': -1, '\_id.month': -1 } }
  ]).session(session)).
  then(res => assert.deepEqual(res, [
    { \_id: { month: 6, year: 2018 }, count: 2 },
    { \_id: { month: 6, year: 2017 }, count: 1 },
    { \_id: { month: 5, year: 2017 }, count: 1 }
  ])).
  then(() => session.commitTransaction()).
  then(() => session.endSession());

```
 Advanced Usage
--------------

 Advanced users who want more fine-grained control over when they commit or abort transactions can use `session.startTransaction()` to start a transaction:

 
```
const Customer = db.model('Customer', new Schema({ name: String }));

let session = null;
return Customer.createCollection().
  then(() => db.startSession()).
  then(\_session => {
    session = _session;
    // Start a transaction
    session.startTransaction();
    // This `create()` is part of the transaction because of the `session`
    // option.
    return Customer.create([{ name: 'Test' }], { session: session });
  }).
  // Transactions execute in isolation, so unless you pass a `session`
  // to `findOne()` you won't see the document until the transaction
  // is committed.
  then(() => Customer.findOne({ name: 'Test' })).
  then(doc => assert.ok(!doc)).
  // This `findOne()` will return the doc, because passing the `session`
  // means this `findOne()` will run as part of the transaction.
  then(() => Customer.findOne({ name: 'Test' }).session(session)).
  then(doc => assert.ok(doc)).
  // Once the transaction is committed, the write operation becomes
  // visible outside of the transaction.
  then(() => session.commitTransaction()).
  then(() => Customer.findOne({ name: 'Test' })).
  then(doc => assert.ok(doc)).
  then(() => session.endSession());

```
 You can also use `session.abortTransaction()` to abort a transaction:

 
```
let session = null;
return Customer.createCollection().
  then(() => Customer.startSession()).
  then(\_session => {
    session = _session;
    session.startTransaction();
    return Customer.create([{ name: 'Test' }], { session: session });
  }).
  then(() => Customer.create([{ name: 'Test2' }], { session: session })).
  then(() => session.abortTransaction()).
  then(() => Customer.countDocuments()).
  then(count => assert.strictEqual(count, 0)).
  then(() => session.endSession());

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/transactions.html>

How to Use `findOneAndUpdate()` in Mongoose
============================================

 The [`findOneAndUpdate()` function in Mongoose](../api/query#query_Query-findOneAndUpdate) has a wide variety of use cases. [You should use `save()` to update documents where possible](https://masteringjs.io/tutorials/mongoose/update), for better [validation](../validation) and [middleware](../middleware) support. However, there are some cases where you need to use [`findOneAndUpdate()`](https://masteringjs.io/tutorials/mongoose/findoneandupdate). In this tutorial, you'll see how to use `findOneAndUpdate()`, and learn when you need to use it.

 * [Getting Started](#getting-started)
* [Atomic Updates](#atomic-updates)
* [Upsert](#upsert)
* [The `rawResult` Option](#raw-result)

  Getting Started
----------------

 As the name implies, `findOneAndUpdate()` finds the first document that matches a given `filter`, applies an `update`, and returns the document. By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied.

 
```
const Character = mongoose.model('Character', new mongoose.Schema({
  name: String,
  age: Number
}));

await Character.create({ name: 'Jean-Luc Picard' });

const filter = { name: 'Jean-Luc Picard' };
const update = { age: 59 };

// `doc` is the document \_before\_ `update` was applied
let doc = await Character.findOneAndUpdate(filter, update);
doc.name; // 'Jean-Luc Picard'
doc.age; // undefined

doc = await Character.findOne(filter);
doc.age; // 59

```
 You should set the `new` option to `true` to return the document **after** `update` was applied.

 
```
const filter = { name: 'Jean-Luc Picard' };
const update = { age: 59 };

// `doc` is the document \_after\_ `update` was applied because of
// `new: true`
const doc = await Character.findOneAndUpdate(filter, update, {
  new: true
});
doc.name; // 'Jean-Luc Picard'
doc.age; // 59

```
 Mongoose's `findOneAndUpdate()` is slightly different from [the MongoDB Node.js driver's `findOneAndUpdate()`](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#findOneAndUpdate) because it returns the document itself, not a [result object](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~findAndModifyWriteOpResult).

 As an alternative to the `new` option, you can also use the `returnOriginal` option. `returnOriginal: false` is equivalent to `new: true`. The `returnOriginal` option exists for consistency with the [the MongoDB Node.js driver's `findOneAndUpdate()`](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#findOneAndUpdate), which has the same option.

 
```
const filter = { name: 'Jean-Luc Picard' };
const update = { age: 59 };

// `doc` is the document \_after\_ `update` was applied because of
// `returnOriginal: false`
const doc = await Character.findOneAndUpdate(filter, update, {
  returnOriginal: false
});
doc.name; // 'Jean-Luc Picard'
doc.age; // 59

```
  Atomic Updates
---------------

 With the exception of an [unindexed upsert](https://www.mongodb.com/docs/manual/reference/method/db.collection.findAndModify/#upsert-with-unique-index), [`findOneAndUpdate()` is atomic](https://www.mongodb.com/docs/manual/core/write-operations-atomicity/#atomicity). That means you can assume the document doesn't change between when MongoDB finds the document and when it updates the document, *unless* you're doing an [upsert](#upsert).

 For example, if you're using `save()` to update a document, the document can change in MongoDB in between when you load the document using `findOne()` and when you save the document using `save()` as show below. For many use cases, the `save()` race condition is a non-issue. But you can work around it with `findOneAndUpdate()` (or [transactions](../transactions)) if you need to.

 
```
const filter = { name: 'Jean-Luc Picard' };
const update = { age: 59 };

let doc = await Character.findOne({ name: 'Jean-Luc Picard' });

// Document changed in MongoDB, but not in Mongoose
await Character.updateOne(filter, { name: 'Will Riker' });

// This will update `doc` age to `59`, even though the doc changed.
doc.age = update.age;
await doc.save();

doc = await Character.findOne();
doc.name; // Will Riker
doc.age; // 59

```
  Upsert
-------

 Using the `upsert` option, you can use `findOneAndUpdate()` as a find-and-[upsert](https://www.mongodb.com/docs/manual/reference/method/db.collection.update/#db.collection.update) operation. An upsert behaves like a normal `findOneAndUpdate()` if it finds a document that matches `filter`. But, if no document matches `filter`, MongoDB will insert one by combining `filter` and `update` as shown below.

 
```
const filter = { name: 'Will Riker' };
const update = { age: 29 };

await Character.countDocuments(filter); // 0

const doc = await Character.findOneAndUpdate(filter, update, {
  new: true,
  upsert: true // Make this update into an upsert
});
doc.name; // Will Riker
doc.age; // 29

```
 The `rawResult` Option
----------------------

 Mongoose transforms the result of `findOneAndUpdate()` by default: it returns the updated document. That makes it difficult to check whether a document was upserted or not. In order to get the updated document and check whether MongoDB upserted a new document in the same operation, you can set the `rawResult` flag to make Mongoose return the raw result from MongoDB.

 
```
const filter = { name: 'Will Riker' };
const update = { age: 29 };

await Character.countDocuments(filter); // 0

const res = await Character.findOneAndUpdate(filter, update, {
  new: true,
  upsert: true,
  rawResult: true // Return the raw result from the MongoDB driver
});

res.value instanceof Character; // true
// The below property will be `false` if MongoDB upserted a new
// document, and `true` if MongoDB updated an existing object.
res.lastErrorObject.updatedExisting; // false

```
 Here's what the `res` object from the above example looks like:

 
```
{ lastErrorObject:
   { n: 1,
     updatedExisting: false,
     upserted: 5e6a9e5ec6e44398ae2ac16a },
  value:
   { _id: 5e6a9e5ec6e44398ae2ac16a,
     name: 'Will Riker',
     __v: 0,
     age: 29 },
  ok: 1 }

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/tutorials/findoneandupdate.html>

SchemaTypes
============

 SchemaTypes handle definition of path [defaults](api/schematype#schematype_SchemaType-default), [validation](api/schematype#schematype_SchemaType-validate), [getters](#getters), [setters](api/schematype#schematype_SchemaType-set), [field selection defaults](api/schematype#schematype_SchemaType-select) for [queries](api/query), and other general characteristics for Mongoose document properties.

 * [What is a SchemaType?](#what-is-a-schematype)
* [The `type` Key](#type-key)
* [SchemaType Options](#schematype-options)
* [Usage Notes](#usage-notes)
* [Getters](#getters)
* [Custom Types](#customtypes)
* [The `schema.path()` Function](#path)
* [Further Reading](#further-reading)

 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 property. A SchemaType says what type a given path should have, whether it has any getters/setters, and what values are valid for that path.

 
```
const schema = new Schema({ name: String });
schema.path('name') instanceof mongoose.SchemaType; // true
schema.path('name') instanceof mongoose.Schema.Types.String; // true
schema.path('name').instance; // 'String'

```
 A SchemaType is different from a type. In other words, `mongoose.ObjectId !== mongoose.Types.ObjectId`. A SchemaType is just a configuration object for Mongoose. An instance of the `mongoose.ObjectId` SchemaType doesn't actually create MongoDB ObjectIds, it is just a configuration for a path in a schema.

 The following are all the valid SchemaTypes in Mongoose. Mongoose plugins can also add custom SchemaTypes like [int32](http://plugins.mongoosejs.io/plugins/int32). Check out [Mongoose's plugins search](http://plugins.mongoosejs.io) to find plugins.

 * [String](#strings)
* [Number](#numbers)
* [Date](#dates)
* [Buffer](#buffers)
* [Boolean](#booleans)
* [Mixed](#mixed)
* [ObjectId](#objectids)
* [Array](#arrays)
* [Decimal128](api/mongoose#mongoose_Mongoose-Decimal128)
* [Map](#maps)
* [Schema](#schemas)
* [UUID](#uuid)
* [BigInt](#bigint)

 ### Example

 
```
const schema = new Schema({
  name: String,
  binary: Buffer,
  living: Boolean,
  updated: { type: Date, default: Date.now },
  age: { type: Number, min: 18, max: 65 },
  mixed: Schema.Types.Mixed,
  \_someId: Schema.Types.ObjectId,
  decimal: Schema.Types.Decimal128,
  array: [],
  ofString: [String],
  ofNumber: [Number],
  ofDates: [Date],
  ofBuffer: [Buffer],
  ofBoolean: [Boolean],
  ofMixed: [Schema.Types.Mixed],
  ofObjectId: [Schema.Types.ObjectId],
  ofArrays: [[]],
  ofArrayOfNumbers: [[Number]],
  nested: {
    stuff: { type: String, lowercase: true, trim: true }
  },
  map: Map,
  mapOfString: {
    type: Map,
    of: String
  }
});

// example use

const Thing = mongoose.model('Thing', schema);

const m = new Thing;
m.name = 'Statue of Liberty';
m.age = 125;
m.updated = new Date;
m.binary = Buffer.alloc(0);
m.living = false;
m.mixed = { any: { thing: 'i want' } };
m.markModified('mixed');
m.\_someId = new mongoose.Types.ObjectId;
m.array.push(1);
m.ofString.push('strings!');
m.ofNumber.unshift(1, 2, 3, 4);
m.ofDates.addToSet(new Date);
m.ofBuffer.pop();
m.ofMixed = [1, [], 'three', { four: 5 }];
m.nested.stuff = 'good';
m.map = new Map([['key', 'value']]);
m.save(callback);

```
 The `type` Key
--------------

 `type` is a special property in Mongoose schemas. When Mongoose finds a nested property named `type` in your schema, Mongoose assumes that it needs to define a SchemaType with the given type.

 
```
// 3 string SchemaTypes: 'name', 'nested.firstName', 'nested.lastName'
const schema = new Schema({
  name: { type: String },
  nested: {
    firstName: { type: String },
    lastName: { type: String }
  }
});

```
 As a consequence, [you need a little extra work to define a property named `type` in your schema](https://mongoosejs.com/docs/faq.html#type-key). For example, suppose you're building a stock portfolio app, and you want to store the asset's `type` (stock, bond, ETF, etc.). Naively, you might define your schema as shown below:

 
```
const holdingSchema = new Schema({
  // You might expect `asset` to be an object that has 2 properties,
  // but unfortunately `type` is special in Mongoose so mongoose
  // interprets this schema to mean that `asset` is a string
  asset: {
    type: String,
    ticker: String
  }
});

```
 However, when Mongoose sees `type: String`, it assumes that you mean `asset` should be a string, not an object with a property `type`. The correct way to define an object with a property `type` is shown below.

 
```
const holdingSchema = new Schema({
  asset: {
    // Workaround to make sure Mongoose knows `asset` is an object
    // and `asset.type` is a string, rather than thinking `asset`
    // is a string.
    type: { type: String },
    ticker: String
  }
});

```
 SchemaType Options
------------------

 You can declare a schema type using the type directly, or an object with a `type` property.

 
```
const schema1 = new Schema({
  test: String // `test` is a path of type String
});

const schema2 = new Schema({
  // The `test` object contains the "SchemaType options"
  test: { type: String } // `test` is a path of type string
});

```
 In addition to the type property, you can specify additional properties for a path. For example, if you want to lowercase a string before saving:

 
```
const schema2 = new Schema({
  test: {
    type: String,
    lowercase: true // Always convert `test` to lowercase
  }
});

```
 You can add any property you want to your SchemaType options. Many plugins rely on custom SchemaType options. For example, the [mongoose-autopopulate](http://plugins.mongoosejs.io/plugins/autopopulate) plugin automatically populates paths if you set `autopopulate: true` in your SchemaType options. Mongoose comes with support for several built-in SchemaType options, like `lowercase` in the above example.

 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

 * `required`: boolean or function, if true adds a [required validator](validation#built-in-validators) for this property
* `default`: Any or function, sets a default value for the path. If the value is a function, the return value of the function is used as the default.
* `select`: boolean, specifies default [projections](https://www.mongodb.com/docs/manual/tutorial/project-fields-from-query-results/) for queries
* `validate`: function, adds a [validator function](validation#built-in-validators) for this property
* `get`: function, defines a custom getter for this property using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
* `set`: function, defines a custom setter for this property using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
* `alias`: string, mongoose >= 4.10.0 only. Defines a [virtual](guide#virtuals) with the given name that gets/sets this path.
* `immutable`: boolean, defines path as immutable. Mongoose prevents you from changing immutable paths unless the parent document has `isNew: true`.
* `transform`: function, Mongoose calls this function when you call [`Document#toJSON()`](api/document#document_Document-toJSON) function, including when you [`JSON.stringify()`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript) a document.

 
```
const numberSchema = new Schema({
  integerOnly: {
    type: Number,
    get: v => Math.round(v),
    set: v => Math.round(v),
    alias: 'i'
  }
});

const Number = mongoose.model('Number', numberSchema);

const doc = new Number();
doc.integerOnly = 2.001;
doc.integerOnly; // 2
doc.i; // 2
doc.i = 3.001;
doc.integerOnly; // 3
doc.i; // 3

```
 ### Indexes

 You can also define [MongoDB indexes](https://www.mongodb.com/docs/manual/indexes/) using schema type options.

 * `index`: boolean, whether to define an [index](https://www.mongodb.com/docs/manual/indexes/) on this property.
* `unique`: boolean, whether to define a [unique index](https://www.mongodb.com/docs/manual/core/index-unique/) on this property.
* `sparse`: boolean, whether to define a [sparse index](https://www.mongodb.com/docs/manual/core/index-sparse/) on this property.

 
```
const schema2 = new Schema({
  test: {
    type: String,
    index: true,
    unique: true // Unique index. If you specify `unique: true`
    // specifying `index: true` is optional if you do `unique: true`
  }
});

```
 ### String

 * `lowercase`: boolean, whether to always call `.toLowerCase()` on the value
* `uppercase`: boolean, whether to always call `.toUpperCase()` on the value
* `trim`: boolean, whether to always call [`.trim()`](https://masteringjs.io/tutorials/fundamentals/trim-string) on the value
* `match`: RegExp, creates a [validator](validation) that checks if the value matches the given regular expression
* `enum`: Array, creates a [validator](validation) that checks if the value is in the given array.
* `minLength`: Number, creates a [validator](validation) that checks if the value length is not less than the given number
* `maxLength`: Number, creates a [validator](validation) that checks if the value length is not greater than the given number
* `populate`: Object, sets default [populate options](populate#query-conditions)

 ### Number

 * `min`: Number, creates a [validator](validation) that checks if the value is greater than or equal to the given minimum.
* `max`: Number, creates a [validator](validation) that checks if the value is less than or equal to the given maximum.
* `enum`: Array, creates a [validator](validation) that checks if the value is strictly equal to one of the values in the given array.
* `populate`: Object, sets default [populate options](populate#query-conditions)

 ### Date

 * `min`: Date, creates a [validator](validation) that checks if the value is greater than or equal to the given minimum.
* `max`: Date, creates a [validator](validation) 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

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

 Usage Notes
-----------

 ### String

 To declare a path as a string, you may use either the `String` global constructor or the string `'String'`.

 
```
const schema1 = new Schema({ name: String }); // name will be cast to string
const schema2 = new Schema({ name: 'String' }); // Equivalent

const Person = mongoose.model('Person', schema2);

```
 If you pass an element that has a `toString()` function, Mongoose will call it, unless the element is an array or the `toString()` function is strictly equal to `Object.prototype.toString()`.

 
```
new Person({ name: 42 }).name; // "42" as a string
new Person({ name: { toString: () => 42 } }).name; // "42" as a string

// "undefined", will get a cast error if you `save()` this document
new Person({ name: { foo: 42 } }).name;

```
 ### Number

 To declare a path as a number, you may use either the `Number` global constructor or the string `'Number'`.

 
```
const schema1 = new Schema({ age: Number }); // age will be cast to a Number
const schema2 = new Schema({ age: 'Number' }); // Equivalent

const Car = mongoose.model('Car', schema2);

```
 There are several types of values that will be successfully cast to a Number.

 
```
new Car({ age: '15' }).age; // 15 as a Number
new Car({ age: true }).age; // 1 as a Number
new Car({ age: false }).age; // 0 as a Number
new Car({ age: { valueOf: () => 83 } }).age; // 83 as a Number

```
 If you pass an object with a `valueOf()` function that returns a Number, Mongoose will call it and assign the returned value to the path.

 The values `null` and `undefined` are not cast.

 NaN, strings that cast to NaN, arrays, and objects that don't have a `valueOf()` function will all result in a [CastError](validation#cast-errors) once validated, meaning that it will not throw on initialization, only when validated.

 ### 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.

 
```
const Assignment = mongoose.model('Assignment', { dueDate: Date });
const doc = await Assignment.findOne();
doc.dueDate.setMonth(3);
await doc.save(); // THIS DOES NOT SAVE YOUR CHANGE

doc.markModified('dueDate');
await doc.save(); // works

```
 ### Buffer

 To declare a path as a Buffer, you may use either the `Buffer` global constructor or the string `'Buffer'`.

 
```
const schema1 = new Schema({ binData: Buffer }); // binData will be cast to a Buffer
const schema2 = new Schema({ binData: 'Buffer' }); // Equivalent

const Data = mongoose.model('Data', schema2);

```
 Mongoose will successfully cast the below values to buffers.

 
```
const file1 = new Data({ binData: 'test'}); // {"type":"Buffer","data":[116,101,115,116]}
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

 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 object literal. The following are equivalent.

 
```
const Any = new Schema({ any: {} });
const Any = new Schema({ any: Object });
const Any = new Schema({ any: Schema.Types.Mixed });
const Any = new Schema({ any: mongoose.Mixed });

```
 Since Mixed is a schema-less type, you can change the value to anything else you like, but Mongoose loses the ability to auto detect and save those changes. To tell Mongoose that the value of a Mixed type has changed, you need to call `doc.markModified(path)`, passing the path to the Mixed type you just changed.

 To avoid these side-effects, a [Subdocument](subdocs) path may be used instead.

 
```
person.anything = { x: [3, 4, { y: 'changed' }] };
person.markModified('anything');
person.save(); // Mongoose will save changes to `anything`.

```
 ### ObjectIds

 An [ObjectId](https://www.mongodb.com/docs/manual/reference/method/ObjectId/) is a special type typically used for unique identifiers. Here's how you declare a schema with a path `driver` that is an ObjectId:

 
```
const mongoose = require('mongoose');
const carSchema = new mongoose.Schema({ driver: mongoose.ObjectId });

```
 `ObjectId` is a class, and ObjectIds are objects. However, they are often represented as strings. When you convert an ObjectId to a string using `toString()`, you get a 24-character hexadecimal string:

 
```
const Car = mongoose.model('Car', carSchema);

const car = new Car();
car.driver = new mongoose.Types.ObjectId();

typeof car.driver; // 'object'
car.driver instanceof mongoose.Types.ObjectId; // true

car.driver.toString(); // Something like "5e1a0651741b255ddda996c4"

```
 ### Boolean

 Booleans in Mongoose are [plain JavaScript booleans](https://www.w3schools.com/js/js_booleans.asp). By default, Mongoose casts the below values to `true`:

 * `true`
* `'true'`
* `1`
* `'1'`
* `'yes'`

 Mongoose casts the below values to `false`:

 * `false`
* `'false'`
* `0`
* `'0'`
* `'no'`

 Any other value causes a [CastError](validation#cast-errors). You can modify what values Mongoose converts to true or false using the `convertToTrue` and `convertToFalse` properties, which are [JavaScript sets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set).

 
```
const M = mongoose.model('Test', new Schema({ b: Boolean }));
console.log(new M({ b: 'nay' }).b); // undefined

// Set { false, 'false', 0, '0', 'no' }
console.log(mongoose.Schema.Types.Boolean.convertToFalse);

mongoose.Schema.Types.Boolean.convertToFalse.add('nay');
console.log(new M({ b: 'nay' }).b); // false

```
 ### Arrays

 Mongoose supports arrays of [SchemaTypes](api/schema#schema_Schema-Types) and arrays of [subdocuments](subdocs). Arrays of SchemaTypes are also called *primitive arrays*, and arrays of subdocuments are also called *document arrays*.

 
```
const ToySchema = new Schema({ name: String });
const ToyBoxSchema = new Schema({
  toys: [ToySchema],
  buffers: [Buffer],
  strings: [String],
  numbers: [Number]
  // ... etc
});

```
 Arrays are special because they implicitly have a default value of `[]` (empty array).

 
```
const ToyBox = mongoose.model('ToyBox', ToyBoxSchema);
console.log((new ToyBox()).toys); // []

```
 To overwrite this default, you need to set the default value to `undefined`

 
```
const ToyBoxSchema = new Schema({
  toys: {
    type: [ToySchema],
    default: undefined
  }
});

```
 Note: specifying an empty array is equivalent to `Mixed`. The following all create arrays of `Mixed`:

 
```
const Empty1 = new Schema({ any: [] });
const Empty2 = new Schema({ any: Array });
const Empty3 = new Schema({ any: [Schema.Types.Mixed] });
const Empty4 = new Schema({ any: [{}] });

```
 ### 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. In Mongoose, maps are how you create a nested document with arbitrary keys.

 **Note**: In Mongoose Maps, keys must be strings in order to store the document in MongoDB.

 
```
const userSchema = new Schema({
  // `socialMediaHandles` is a map whose values are strings. A map's
  // keys are always strings. You specify the type of values using `of`.
  socialMediaHandles: {
    type: Map,
    of: String
  }
});

const User = mongoose.model('User', userSchema);
// Map { 'github' => 'vkarpov15', 'twitter' => '@code\_barbarian' }
console.log(new User({
  socialMediaHandles: {
    github: 'vkarpov15',
    twitter: '@code\_barbarian'
  }
}).socialMediaHandles);

```
 The above example doesn't explicitly declare `github` or `twitter` as paths, but, since `socialMediaHandles` is a map, you can store arbitrary key/value pairs. However, since `socialMediaHandles` is a map, you **must** use `.get()` to get the value of a key and `.set()` to set the value of a key.

 
```
const user = new User({
  socialMediaHandles: {}
});

// Good
user.socialMediaHandles.set('github', 'vkarpov15');
// Works too
user.set('socialMediaHandles.twitter', '@code\_barbarian');
// Bad, the `myspace` property will \*\*not\*\* get saved
user.socialMediaHandles.myspace = 'fail';

// 'vkarpov15'
console.log(user.socialMediaHandles.get('github'));
// '@code\_barbarian'
console.log(user.get('socialMediaHandles.twitter'));
// undefined
user.socialMediaHandles.github;

// Will only save the 'github' and 'twitter' properties
user.save();

```
 Map types are stored as [BSON objects in MongoDB](https://en.wikipedia.org/wiki/BSON#Data_types_and_syntax). Keys in a BSON object are ordered, so this means the [insertion order](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Description) property of maps is maintained.

 Mongoose supports a special `$*` syntax to <populate> all elements in a map. For example, suppose your `socialMediaHandles` map contains a `ref`:

 
```
const userSchema = new Schema({
  socialMediaHandles: {
    type: Map,
    of: new Schema({
      handle: String,
      oauth: {
        type: ObjectId,
        ref: 'OAuth'
      }
    })
  }
});
const User = mongoose.model('User', userSchema);

```
 To populate every `socialMediaHandles` entry's `oauth` property, you should populate on `socialMediaHandles.$*.oauth`:

 
```
const user = await User.findOne().populate('socialMediaHandles.$\*.oauth');

```
 ### 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.

 In Node.js, a UUID is represented as an instance of `bson.Binary` type with a [getter](tutorials/getters-setters) that converts the binary to a string when you access it. Mongoose stores UUIDs as [binary data with subtype 4 in MongoDB](https://www.mongodb.com/docs/manual/reference/bson-types/#binary-data).

 
```
const authorSchema = new Schema({
  \_id: Schema.Types.UUID, // Can also do `\_id: 'UUID'`
  name: String
});

const Author = mongoose.model('Author', authorSchema);

const bookSchema = new Schema({
  authorId: { type: Schema.Types.UUID, ref: 'Author' }
});
const Book = mongoose.model('Book', bookSchema);

const author = new Author({ name: 'Martin Fowler' });
console.log(typeof author.\_id); // 'string'
console.log(author.toObject().\_id instanceof mongoose.mongo.BSON.Binary); // true

const book = new Book({ authorId: '09190f70-3d30-11e5-8814-0f4df9a59c41' });

```
 To create UUIDs, we recommend using [Node's built-in UUIDv4 generator](https://nodejs.org/api/crypto.html#cryptorandomuuidoptions).

 
```
const { randomUUID } = require('crypto');

const schema = new mongoose.Schema({
  docId: {
    type: 'UUID',
    default: () => randomUUID()
  }
});

```
 ### 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/).

 
```
const questionSchema = new Schema({
  answer: BigInt
});
const Question = mongoose.model('Question', questionSchema);

const question = new Question({ answer: 42n });
typeof question.answer; // 'bigint'

```
 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 then add the hostname in your application. Below is how you would structure your `userSchema`:

 
```
const root = 'https://s3.amazonaws.com/mybucket';

const userSchema = new Schema({
  name: String,
  picture: {
    type: String,
    get: v => `${root}${v}`
  }
});

const User = mongoose.model('User', userSchema);

const doc = new User({ name: 'Val', picture: '/123.png' });
doc.picture; // 'https://s3.amazonaws.com/mybucket/123.png'
doc.toObject({ getters: false }).picture; // '/123.png'

```
 Generally, you only use getters on primitive paths as opposed to arrays or subdocuments. Because getters override what accessing a Mongoose path returns, declaring a getter on an object may remove Mongoose change tracking for that path.

 
```
const schema = new Schema({
  arr: [{ url: String }]
});

const root = 'https://s3.amazonaws.com/mybucket';

// Bad, don't do this!
schema.path('arr').get(v => {
  return v.map(el => Object.assign(el, { url: root + el.url }));
});

// Later
doc.arr.push({ key: String });
doc.arr[0]; // 'undefined' because every `doc.arr` creates a new array!

```
 Instead of declaring a getter on the array as shown above, you should declare a getter on the `url` string as shown below. If you need to declare a getter on a nested document or array, be very careful!

 
```
const schema = new Schema({
  arr: [{ url: String }]
});

const root = 'https://s3.amazonaws.com/mybucket';

// Good, do this instead of declaring a getter on `arr`
schema.path('arr.0.url').get(v => `${root}${v}`);

```
 Schemas
-------

 To declare a path as another [schema](guide#definition), set `type` to the sub-schema's instance.

 To set a default value based on the sub-schema's shape, simply set a default value, and the value will be cast based on the sub-schema's definition before being set during document creation.

 
```
const subSchema = new mongoose.Schema({
  // some schema definition here
});

const schema = new mongoose.Schema({
  data: {
    type: subSchema,
    default: {}
  }
});

```
 Creating Custom Types
---------------------

 Mongoose can also be extended with [custom SchemaTypes](customschematypes). Search the [plugins](http://plugins.mongoosejs.io) site for compatible types like [mongoose-long](https://github.com/aheckmann/mongoose-long), [mongoose-int32](https://github.com/vkarpov15/mongoose-int32), and [mongoose-function](https://github.com/aheckmann/mongoose-function).

 Read more about creating custom SchemaTypes [here](customschematypes).

 The `schema.path()` Function
----------------------------

 The `schema.path()` function returns the instantiated schema type for a given path.

 
```
const sampleSchema = new Schema({ name: { type: String, required: true } });
console.log(sampleSchema.path('name'));
// Output looks like:
/\*\*
 \* SchemaString {
 \* enumValues: [],
 \* regExp: null,
 \* path: 'name',
 \* instance: 'String',
 \* validators: ...
 \*/

```
 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
---------------

 * [An Introduction to Mongoose SchemaTypes](https://masteringjs.io/tutorials/mongoose/schematype)
* [Mongoose Schema Types](https://kb.objectrocket.com/mongo-db/mongoose-schema-types-1418)

  Next Up
--------

 Now that we've covered `SchemaTypes`, let's take a look at [Connections](connections).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/schematypes.html>

Map
===



### MongooseMap.prototype.$isMongooseMap


##### Type:


* «property»



Set to `true` for all Mongoose map instances

 
### MongooseMap.prototype.clear()



Overwrites native Map's `clear()` function to support change tracking.

 
### MongooseMap.prototype.delete()



Overwrites native Map's `delete()` function to support change tracking.

 
### MongooseMap.prototype.get()



Overwrites native Map's `get()` function to support Mongoose getters.

 
### MongooseMap.prototype.set()



Overwrites native Map's `set()` function to support setters, `populate()`, and change tracking. Note that Mongoose maps *only* support strings and ObjectIds as keys.

 ####   [Example:](#example)

 
```
doc.myMap.set('test', 42); // works
doc.myMap.set({ obj: 42 }, 42); // Throws "Mongoose maps only support string keys"

```
 
### MongooseMap.prototype.toBSON()



Converts this map to a native JavaScript Map so the MongoDB driver can serialize it.

 
### MongooseMap.prototype.toJSON()


##### Parameters:


* `[options]` «Object»
+ `[options.flattenMaps=false]` «Boolean» set to `true` to convert the map to a POJO rather than a native JavaScript map



Converts this map to a native JavaScript Map for `JSON.stringify()`. Set the `flattenMaps` option to convert this map to a POJO instead.

 ####   [Example:](#example)

 
```
doc.myMap.toJSON() instanceof Map; // true
doc.myMap.toJSON({ flattenMaps: true }) instanceof Map; // false

```
 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/map.html>

Faster Mongoose Queries With Lean
==================================

 The [lean option](../api/query#query_Query-lean) tells Mongoose to skip [hydrating](../api/model#model_Model-hydrate) the result documents. This makes queries faster and less memory intensive, but the result documents are plain old JavaScript objects (POJOs), **not** [Mongoose documents](../documents). In this tutorial, you'll learn more about the tradeoffs of using `lean()`.

 * [Using Lean](#using-lean)
* [Lean and Populate](#lean-and-populate)
* [When to Use Lean](#when-to-use-lean)
* [Plugins](#plugins)
* [BigInts](#bigints)

 Using Lean
----------

 By default, Mongoose queries return an instance of the [Mongoose `Document` class](../api/document#Document). Documents are much heavier than vanilla JavaScript objects, because they have a lot of internal state for change tracking. Enabling the `lean` option tells Mongoose to skip instantiating a full Mongoose document and just give you the POJO.

 
```
const leanDoc = await MyModel.findOne().lean();

```
 How much smaller are lean documents? Here's a comparison.

 
```
const schema = new mongoose.Schema({ name: String });
const MyModel = mongoose.model('Test', schema);

await MyModel.create({ name: 'test' });

const normalDoc = await MyModel.findOne();
// To enable the `lean` option for a query, use the `lean()` function.
const leanDoc = await MyModel.findOne().lean();

v8Serialize(normalDoc).length; // approximately 180
v8Serialize(leanDoc).length; // 32, about 5x smaller!

// In case you were wondering, the JSON form of a Mongoose doc is the same
// as the POJO. This additional memory only affects how much memory your
// Node.js process uses, not how much data is sent over the network.
JSON.stringify(normalDoc).length === JSON.stringify(leanDoc).length; // true

```
 Under the hood, after executing a query, Mongoose converts the query results from POJOs to Mongoose documents. If you turn on the `lean` option, Mongoose skips this step.

 
```
const normalDoc = await MyModel.findOne();
const leanDoc = await MyModel.findOne().lean();

normalDoc instanceof mongoose.Document; // true
normalDoc.constructor.name; // 'model'

leanDoc instanceof mongoose.Document; // false
leanDoc.constructor.name; // 'Object'

```
 The downside of enabling `lean` is that lean docs don't have:

 * Change tracking
* Casting and validation
* Getters and setters
* Virtuals
* `save()`

 For example, the following code sample shows that the `Person` model's getters and virtuals don't run if you enable `lean`.

 
```
// Define a `Person` model. Schema has 2 custom getters and a `fullName`
// virtual. Neither the getters nor the virtuals will run if lean is enabled.
const personSchema = new mongoose.Schema({
  firstName: {
    type: String,
    get: capitalizeFirstLetter
  },
  lastName: {
    type: String,
    get: capitalizeFirstLetter
  }
});
personSchema.virtual('fullName').get(function() {
  return `${this.firstName} ${this.lastName}`;
});
function capitalizeFirstLetter(v) {
  // Convert 'bob' -> 'Bob'
  return v.charAt(0).toUpperCase() + v.substring(1);
}
const Person = mongoose.model('Person', personSchema);

// Create a doc and load it as a lean doc
await Person.create({ firstName: 'benjamin', lastName: 'sisko' });
const normalDoc = await Person.findOne();
const leanDoc = await Person.findOne().lean();

normalDoc.fullName; // 'Benjamin Sisko'
normalDoc.firstName; // 'Benjamin', because of `capitalizeFirstLetter()`
normalDoc.lastName; // 'Sisko', because of `capitalizeFirstLetter()`

leanDoc.fullName; // undefined
leanDoc.firstName; // 'benjamin', custom getter doesn't run
leanDoc.lastName; // 'sisko', custom getter doesn't run

```
 Lean and Populate
-----------------

 [Populate](../populate) works with `lean()`. If you use both `populate()` and `lean()`, the `lean` option propagates to the populated documents as well. In the below example, both the top-level 'Group' documents and the populated 'Person' documents will be lean.

 
```
// Create models
const Group = mongoose.model('Group', new mongoose.Schema({
  name: String,
  members: [{ type: mongoose.ObjectId, ref: 'Person' }]
}));
const Person = mongoose.model('Person', new mongoose.Schema({
  name: String
}));

// Initialize data
const people = await Person.create([
  { name: 'Benjamin Sisko' },
  { name: 'Kira Nerys' }
]);
await Group.create({
  name: 'Star Trek: Deep Space Nine Characters',
  members: people.map(p => p.\_id)
});

// Execute a lean query
const group = await Group.findOne().lean().populate('members');
group.members[0].name; // 'Benjamin Sisko'
group.members[1].name; // 'Kira Nerys'

// Both the `group` and the populated `members` are lean.
group instanceof mongoose.Document; // false
group.members[0] instanceof mongoose.Document; // false
group.members[1] instanceof mongoose.Document; // false

```
 [Virtual populate](../populate#populate-virtuals) also works with lean.

 
```
// Create models
const groupSchema = new mongoose.Schema({ name: String });
groupSchema.virtual('members', {
  ref: 'Person',
  localField: '\_id',
  foreignField: 'groupId'
});
const Group = mongoose.model('Group', groupSchema);
const Person = mongoose.model('Person', new mongoose.Schema({
  name: String,
  groupId: mongoose.ObjectId
}));

// Initialize data
const g = await Group.create({ name: 'DS9 Characters' });
await Person.create([
  { name: 'Benjamin Sisko', groupId: g.\_id },
  { name: 'Kira Nerys', groupId: g.\_id }
]);

// Execute a lean query
const group = await Group.findOne().lean().populate({
  path: 'members',
  options: { sort: { name: 1 } }
});
group.members[0].name; // 'Benjamin Sisko'
group.members[1].name; // 'Kira Nerys'

// Both the `group` and the populated `members` are lean.
group instanceof mongoose.Document; // false
group.members[0] instanceof mongoose.Document; // false
group.members[1] instanceof mongoose.Document; // false

```
 When to Use Lean
----------------

 If you're executing a query and sending the results without modification to, say, an [Express response](http://expressjs.com/en/4x/api.html#res), you should use lean. In general, if you do not modify the query results and do not use [custom getters](../api/schematype#schematype_SchemaType-get), you should use `lean()`. If you modify the query results or rely on features like getters or [transforms](../api/document#document_Document-toObject), you should not use `lean()`.

 Below is an example of an [Express route](http://expressjs.com/en/guide/routing.html) that is a good candidate for `lean()`. This route does not modify the `person` doc and doesn't rely on any Mongoose-specific functionality.

 
```
// As long as you don't need any of the Person model's virtuals or getters,
// you can use `lean()`.
app.get('/person/:id', function(req, res) {
  Person.findOne({ \_id: req.params.id }).lean().
    then(person => res.json({ person })).
    catch(error => res.json({ error: error.message }));
});

```
 Below is an example of an Express route that should **not** use `lean()`. As a general rule of thumb, `GET` routes are good candidates for `lean()` in a [RESTful API](https://en.wikipedia.org/wiki/Representational_state_transfer). On the other hand, `PUT`, `POST`, etc. routes generally should not use `lean()`.

 
```
// This route should \*\*not\*\* use `lean()`, because lean means no `save()`.
app.put('/person/:id', function(req, res) {
  Person.findOne({ \_id: req.params.id }).
    then(person => {
      assert.ok(person);
      Object.assign(person, req.body);
      return person.save();
    }).
    then(person => res.json({ person })).
    catch(error => res.json({ error: error.message }));
});

```
 Remember that virtuals do **not** end up in `lean()` query results. Use the [mongoose-lean-virtuals plugin](http://plugins.mongoosejs.io/plugins/lean-virtuals) to add virtuals to your lean query results.

  Plugins
--------

 Using `lean()` bypasses all Mongoose features, including <virtuals>, [getters/setters](getters-setters), and [defaults](../api/schematype#schematype_SchemaType-default). If you want to use these features with `lean()`, you need to use the corresponding plugin:

 * [mongoose-lean-virtuals](https://plugins.mongoosejs.io/plugins/lean-virtuals)
* [mongoose-lean-getters](https://plugins.mongoosejs.io/plugins/lean-getters)
* [mongoose-lean-defaults](https://www.npmjs.com/package/mongoose-lean-defaults)

 However, you need to keep in mind that Mongoose does not hydrate lean documents, so `this` will be a POJO in virtuals, getters, and default functions.

 
```
const schema = new Schema({ name: String });
schema.plugin(require('mongoose-lean-virtuals'));

schema.virtual('lowercase', function() {
  this instanceof mongoose.Document; // false

  this.name; // Works
  this.get('name'); // Crashes because `this` is not a Mongoose document.
});

```
  BigInts
--------

 By default, the MongoDB Node driver converts longs stored in MongoDB into JavaScript numbers, **not** [BigInts](https://thecodebarbarian.com/an-overview-of-bigint-in-node-js.html). Set the `useBigInt64` option on your `lean()` queries to inflate longs into BigInts.

 
```
const Person = mongoose.model('Person', new mongoose.Schema({
  name: String,
  age: BigInt
}));
// Mongoose will convert `age` to a BigInt
const { age } = await Person.create({ name: 'Benjamin Sisko', age: 37 });
typeof age; // 'bigint'

// By default, if you store a document with a BigInt property in MongoDB and you
// load the document with `lean()`, the BigInt property will be a number
let person = await Person.findOne({ name: 'Benjamin Sisko' }).lean();
typeof person.age; // 'number'

// Set the `useBigInt64` option to opt in to converting MongoDB longs to BigInts.
person = await Person.findOne({ name: 'Benjamin Sisko' }).
  setOptions({ useBigInt64: true }).
  lean();
typeof person.age; // 'bigint'

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/tutorials/lean.html>

Plugins
========

 Schemas are pluggable, that is, they allow for applying pre-packaged capabilities to extend their functionality. This is a very powerful feature.

 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 to each one. Just create a plugin once and apply it to each `Schema`:

 
```
// loadedAt.js
module.exports = function loadedAtPlugin(schema, options) {
  schema.virtual('loadedAt').
    get(function() { return this.\_loadedAt; }).
    set(function(v) { this.\_loadedAt = v; });

  schema.post(['find', 'findOne'], function(docs) {
    if (!Array.isArray(docs)) {
      docs = [docs];
    }
    const now = new Date();
    for (const doc of docs) {
      doc.loadedAt = now;
    }
  });
};

// game-schema.js
const loadedAtPlugin = require('./loadedAt');
const gameSchema = new Schema({ /\* ... \*/ });
gameSchema.plugin(loadedAtPlugin);

// player-schema.js
const loadedAtPlugin = require('./loadedAt');
const playerSchema = new Schema({ /\* ... \*/ });
playerSchema.plugin(loadedAtPlugin);

```
 We just added last-modified behavior to both our `Game` and `Player` schemas and declared an index on the `lastMod` path of our Games to boot. Not bad for a few lines of code.

 Global Plugins
--------------

 Want to register a plugin for all schemas? The mongoose singleton has a `.plugin()` function that registers a plugin for every schema. For example:

 
```
const mongoose = require('mongoose');
mongoose.plugin(require('./loadedAt'));

const gameSchema = new Schema({ /\* ... \*/ });
const playerSchema = new Schema({ /\* ... \*/ });
// `loadedAtPlugin` gets attached to both schemas
const Game = mongoose.model('Game', gameSchema);
const Player = mongoose.model('Player', playerSchema);

```
 Apply Plugins Before Compiling Models
-------------------------------------

 Because many plugins rely on <middleware>, 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#defining).

 
```
// loadedAt.js
module.exports = function loadedAtPlugin(schema, options) {
  schema.virtual('loadedAt').
    get(function() { return this.\_loadedAt; }).
    set(function(v) { this.\_loadedAt = v; });

  schema.post(['find', 'findOne'], function(docs) {
    if (!Array.isArray(docs)) {
      docs = [docs];
    }
    const now = new Date();
    for (const doc of docs) {
      doc.loadedAt = now;
    }
  });
};

// game-schema.js
const loadedAtPlugin = require('./loadedAt');
const gameSchema = new Schema({ /\* ... \*/ });
const Game = mongoose.model('Game', gameSchema);

// `find()` and `findOne()` hooks from `loadedAtPlugin()` won't get applied
// because `mongoose.model()` was already called!
gameSchema.plugin(loadedAtPlugin);

```
 Officially Supported Plugins
----------------------------

 The Mongoose team maintains several plugins that add cool new features to Mongoose. Here's a couple:

 * [mongoose-autopopulate](http://plugins.mongoosejs.io/plugins/autopopulate): Always [`populate()`](populate) certain fields in your Mongoose schemas.
* [mongoose-lean-virtuals](http://plugins.mongoosejs.io/plugins/lean-virtuals): Attach virtuals to the results of Mongoose queries when using [`.lean()`](api/query#query_Query-lean).
* [mongoose-cast-aggregation](https://www.npmjs.com/package/mongoose-cast-aggregation)

 You can find a full list of officially supported plugins on [Mongoose's plugins search site](https://plugins.mongoosejs.io/).

  Community
----------

 Not only can you re-use schema functionality in your own projects, but you also reap the benefits of the Mongoose community as well. Any plugin published to [npm](https://npmjs.org/) and with 'mongoose' as an [npm keyword](https://docs.npmjs.com/files/package.json#keywords) will show up on our [search results](http://plugins.mongoosejs.io) page.



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/plugins.html>

Mongoose Virtuals
==================

 In Mongoose, a virtual is a property that is **not** stored in MongoDB. Virtuals are typically used for computed properties on documents.

 * [Your First Virtual](#your-first-virtual)
* [Virtual Setters](#virtual-setters)
* [Virtuals in JSON](#virtuals-in-json)
* [Virtuals with Lean](#virtuals-with-lean)
* [Limitations](#limitations)
* [Populate](#populate)
* [Virtuals via schema options](#virtuals-via-schema-options)
* [Further Reading](#further-reading)

  Your First Virtual
-------------------

 Suppose you have a `User` model. Every user has an `email`, but you also want the email's domain. For example, the domain portion of '[test@gmail.com](mailto:test@gmail.com)' is 'gmail.com'.

 Below is one way to implement the `domain` property using a virtual. You define virtuals on a schema using the [`Schema#virtual()` function](../api/schema#schema_Schema-virtual).

 
```
const userSchema = mongoose.Schema({
  email: String
});
// Create a virtual property `domain` that's computed from `email`.
userSchema.virtual('domain').get(function() {
  return this.email.slice(this.email.indexOf('@') + 1);
});
const User = mongoose.model('User', userSchema);

const doc = await User.create({ email: 'test@gmail.com' });
// `domain` is now a property on User documents.
doc.domain; // 'gmail.com'

```
 The `Schema#virtual()` function returns a [`VirtualType` object](../api/virtualtype). Unlike normal document properties, virtuals do not have any underlying value and Mongoose does not do any type coercion on virtuals. However, virtuals do have [getters and setters](getters-setters), which make them ideal for computed properties, like the `domain` example above.

  Virtual Setters
----------------

 You can also use virtuals to set multiple properties at once as an alternative to [custom setters on normal properties](getters-setters#setters). For example, suppose you have two string properties: `firstName` and `lastName`. You can create a virtual property `fullName` that lets you set both of these properties at once. The key detail is that, in virtual getters and setters, `this` refers to the document the virtual is attached to.

 
```
const userSchema = mongoose.Schema({
  firstName: String,
  lastName: String
});
// Create a virtual property `fullName` with a getter and setter.
userSchema.virtual('fullName').
  get(function() { return `${this.firstName} ${this.lastName}`; }).
  set(function(v) {
    // `v` is the value being set, so use the value to set
    // `firstName` and `lastName`.
    const firstName = v.substring(0, v.indexOf(' '));
    const lastName = v.substring(v.indexOf(' ') + 1);
    this.set({ firstName, lastName });
  });
const User = mongoose.model('User', userSchema);

const doc = new User();
// Vanilla JavaScript assignment triggers the setter
doc.fullName = 'Jean-Luc Picard';

doc.fullName; // 'Jean-Luc Picard'
doc.firstName; // 'Jean-Luc'
doc.lastName; // 'Picard'

```
  Virtuals in JSON
-----------------

 By default, Mongoose does not include virtuals when you convert a document to JSON. For example, if you pass a document to [Express' `res.json()` function](http://expressjs.com/en/4x/api.html#res.json), virtuals will **not** be included by default.

 To include virtuals in `res.json()`, you need to set the [`toJSON` schema option](../guide#toJSON) to `{ virtuals: true }`.

 
```
const opts = { toJSON: { virtuals: true } };
const userSchema = mongoose.Schema({
  \_id: Number,
  email: String
}, opts);
// Create a virtual property `domain` that's computed from `email`.
userSchema.virtual('domain').get(function() {
  return this.email.slice(this.email.indexOf('@') + 1);
});
const User = mongoose.model('User', userSchema);

const doc = new User({ \_id: 1, email: 'test@gmail.com' });

doc.toJSON().domain; // 'gmail.com'
// {"\_id":1,"email":"test@gmail.com","domain":"gmail.com","id":"1"}
JSON.stringify(doc);

// To skip applying virtuals, pass `virtuals: false` to `toJSON()`
doc.toJSON({ virtuals: false }).domain; // undefined

```
  Virtuals in `console.log()`
----------------------------

 By default, Mongoose does **not** include virtuals in `console.log()` output. To include virtuals in `console.log()`, you need to set the [`toObject` schema option](../guide#toObject) to `{ virtuals: true }`, or use `toObject()` before printing the object.

 
```
console.log(doc.toObject({ virtuals: true }));

```
  Virtuals with Lean
-------------------

 Virtuals are properties on Mongoose documents. If you use the [lean option](lean), that means your queries return POJOs rather than full Mongoose documents. That means no virtuals if you use [`lean()`](../api/query#query_Query-lean).

 
```
const fullDoc = await User.findOne();
fullDoc.domain; // 'gmail.com'

const leanDoc = await User.findOne().lean();
leanDoc.domain; // undefined

```
 If you use `lean()` for performance, but still need virtuals, Mongoose has an [officially supported `mongoose-lean-virtuals` plugin](https://plugins.mongoosejs.io/plugins/lean-virtuals) that decorates lean documents with virtuals.

  Limitations
------------

 Mongoose virtuals are **not** stored in MongoDB, which means you can't query based on Mongoose virtuals.

 
```
// Will \*\*not\*\* find any results, because `domain` is not stored in
// MongoDB.
const doc = await User.findOne({ domain: 'gmail.com' }, null, { strictQuery: false });
doc; // undefined

```
 If you want to query by a computed property, you should set the property using a [custom setter](getters-setters) or [pre save middleware](../middleware).

  Populate
---------

 Mongoose also supports [populating virtuals](../populate). A populated virtual contains documents from another collection. To define a populated virtual, you need to specify:

 * The `ref` option, which tells Mongoose which model to populate documents from.
* The `localField` and `foreignField` options. Mongoose will populate documents from the model in `ref` whose `foreignField` matches this document's `localField`.

 
```
const userSchema = mongoose.Schema({ \_id: Number, email: String });
const blogPostSchema = mongoose.Schema({
  title: String,
  authorId: Number
});
// When you `populate()` the `author` virtual, Mongoose will find the
// first document in the User model whose `\_id` matches this document's
// `authorId` property.
blogPostSchema.virtual('author', {
  ref: 'User',
  localField: 'authorId',
  foreignField: '\_id',
  justOne: true
});
const User = mongoose.model('User', userSchema);
const BlogPost = mongoose.model('BlogPost', blogPostSchema);
await BlogPost.create({ title: 'Introduction to Mongoose', authorId: 1 });
await User.create({ \_id: 1, email: 'test@gmail.com' });

const doc = await BlogPost.findOne().populate('author');
doc.author.email; // 'test@gmail.com'

```
  Virtuals via schema options
----------------------------

 Virtuals can also be defined in the schema-options directly without having to use [`.virtual`](../api/schema#Schema.prototype.virtual):

 
```
const userSchema = mongoose.Schema({
  firstName: String,
  lastName: String
}, {
  virtuals: {
    // Create a virtual property `fullName` with a getter and setter
    fullName: {
      get() { return `${this.firstName} ${this.lastName}`; },
      set(v) {
        // `v` is the value being set, so use the value to set
        // `firstName` and `lastName`.
        const firstName = v.substring(0, v.indexOf(' '));
        const lastName = v.substring(v.indexOf(' ') + 1);
        this.set({ firstName, lastName });
      }
    }
  }
});
const User = mongoose.model('User', userSchema);

const doc = new User();
// Vanilla JavaScript assignment triggers the setter
doc.fullName = 'Jean-Luc Picard';

doc.fullName; // 'Jean-Luc Picard'
doc.firstName; // 'Jean-Luc'
doc.lastName; // 'Picard'

```
 The same also goes for virtual options, like virtual populate:

 
```
const userSchema = mongoose.Schema({ \_id: Number, email: String });
const blogPostSchema = mongoose.Schema({
  title: String,
  authorId: Number
}, {
  virtuals: {
    // When you `populate()` the `author` virtual, Mongoose will find the
    // first document in the User model whose `\_id` matches this document's
    // `authorId` property.
    author: {
      options: {
        ref: 'User',
        localField: 'authorId',
        foreignField: '\_id',
        justOne: true
      }
    }
  }
});
const User = mongoose.model('User', userSchema);
const BlogPost = mongoose.model('BlogPost', blogPostSchema);
await BlogPost.create({ title: 'Introduction to Mongoose', authorId: 1 });
await User.create({ \_id: 1, email: 'test@gmail.com' });

const doc = await BlogPost.findOne().populate('author');
doc.author.email; // 'test@gmail.com'

```
  Further Reading
----------------

 * [Virtuals in Mongoose Schemas](../guide#virtuals)
* [Populate Virtuals](../populate#populate-virtuals)
* [Mongoose Lean Virtuals plugin](https://plugins.mongoosejs.io/plugins/lean-virtuals)
* [Getting Started With Mongoose Virtuals](https://masteringjs.io/tutorials/mongoose/virtuals)
* [Understanding Virtuals in Mongoose](https://futurestud.io/tutorials/understanding-virtuals-in-mongoose)



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/tutorials/virtuals.html>

Getters/Setters in Mongoose
============================

 Mongoose getters and setters allow you to execute custom logic when getting or setting a property on a [Mongoose document](../documents). Getters let you transform data in MongoDB into a more user friendly form, and setters let you transform user data before it gets to MongoDB.

  Getters
--------

 Suppose you have a `User` collection and you want to obfuscate user emails to protect your users' privacy. Below is a basic `userSchema` that obfuscates the user's email address.

 
```
const userSchema = new Schema({
  email: {
    type: String,
    get: obfuscate
  }
});

// Mongoose passes the raw value in MongoDB `email` to the getter
function obfuscate(email) {
  const separatorIndex = email.indexOf('@');
  if (separatorIndex < 3) {
    // 'ab@gmail.com' -> '\*\*@gmail.com'
    return email.slice(0, separatorIndex).replace(/./g, '\*') +
      email.slice(separatorIndex);
  }
  // 'test42@gmail.com' -> 'te\*\*\*\*@gmail.com'
  return email.slice(0, 2) +
    email.slice(2, separatorIndex).replace(/./g, '\*') +
    email.slice(separatorIndex);
}

const User = mongoose.model('User', userSchema);
const user = new User({ email: 'ab@gmail.com' });
user.email; // \*\*@gmail.com

```
 Keep in mind that getters do **not** impact the underlying data stored in MongoDB. If you save `user`, the `email` property will be '[ab@gmail.com](mailto:ab@gmail.com)' in the database.

 By default, Mongoose does **not** execute getters when converting a document to JSON, including [Express' `res.json()` function](http://expressjs.com/en/4x/api.html#res.json).

 
```
app.get(function(req, res) {
  return User.findOne().
    // The `email` getter will NOT run here
    then(doc => res.json(doc)).
    catch(err => res.status(500).json({ message: err.message }));
});

```
 To run getters when converting a document to JSON, set the [`toJSON.getters` option to `true` in your schema](../guide#toJSON) as shown below.

 
```
const userSchema = new Schema({
  email: {
    type: String,
    get: obfuscate
  }
}, { toJSON: { getters: true } });

// Or, globally
mongoose.set('toJSON', { getters: true });

// Or, on a one-off basis
app.get(function(req, res) {
  return User.findOne().
    // The `email` getter will run here
    then(doc => res.json(doc.toJSON({ getters: true }))).
    catch(err => res.status(500).json({ message: err.message }));
});

```
 To skip getters on a one-off basis, use [`user.get()` with the `getters` option set to `false`](../api/document#document_Document-get) as shown below.

 
```
user.get('email', null, { getters: false }); // 'ab@gmail.com'

```
  Setters
--------

 Suppose you want to make sure all user emails in your database are lowercased to make it easy to search without worrying about case. Below is an example `userSchema` that ensures emails are lowercased.

 
```
const userSchema = new Schema({
  email: {
    type: String,
    set: v => v.toLowerCase()
  }
});

const User = mongoose.model('User', userSchema);

const user = new User({ email: 'TEST@gmail.com' });
user.email; // 'test@gmail.com'

// The raw value of `email` is lowercased
user.get('email', null, { getters: false }); // 'test@gmail.com'

user.set({ email: 'NEW@gmail.com' });
user.email; // 'new@gmail.com'

```
 Mongoose also runs setters on update operations, like [`updateOne()`](../api/query#query_Query-updateOne). Mongoose will [upsert a document](https://masteringjs.io/tutorials/mongoose/upsert) with a lowercased `email` in the below example.

 
```
await User.updateOne({}, { email: 'TEST@gmail.com' }, { upsert: true });

const doc = await User.findOne();
doc.email; // 'test@gmail.com'

```
 In a setter function, `this` can be either the document being set or the query being run. If you don't want your setter to run when you call `updateOne()`, you add an if statement that checks if `this` is a Mongoose document as shown below.

 
```
const userSchema = new Schema({
  email: {
    type: String,
    set: toLower
  }
});

function toLower(email) {
  // Don't transform `email` if using `updateOne()` or `updateMany()`
  if (!(this instanceof mongoose.Document)) {
    return email;
  }
  return email.toLowerCase();
}

const User = mongoose.model('User', userSchema);
await User.updateOne({}, { email: 'TEST@gmail.com' }, { upsert: true });

const doc = await User.findOne();
doc.email; // 'TEST@gmail.com'

```
  Passing Parameters using `$locals`
-----------------------------------

 You can't pass parameters to your getter and setter functions like you do to normal function calls. To configure or pass additional properties to your getters and setters, you can use the document's `$locals` property.

 The `$locals` property is the preferred place to store any program-defined data on your document without conflicting with schema-defined properties. In your getter and setter functions, `this` is the document being accessed, so you set properties on `$locals` and then access those properties in your getters examples. For example, the following shows how you can use `$locals` to configure the language for a custom getter that returns a string in different languages.

 
```
const internationalizedStringSchema = new Schema({
  en: String,
  es: String
});

const ingredientSchema = new Schema({
  // Instead of setting `name` to just a string, set `name` to a map
  // of language codes to strings.
  name: {
    type: internationalizedStringSchema,
    // When you access `name`, pull the document's locale
    get: function(value) {
      return value[this.$locals.language || 'en'];
    }
  }
});

const recipeSchema = new Schema({
  ingredients: [{ type: mongoose.ObjectId, ref: 'Ingredient' }]
});

const Ingredient = mongoose.model('Ingredient', ingredientSchema);
const Recipe = mongoose.model('Recipe', recipeSchema);

// Create some sample data
const { _id } = await Ingredient.create({
  name: {
    en: 'Eggs',
    es: 'Huevos'
  }
});
await Recipe.create({ ingredients: [_id] });

// Populate with setting `$locals.language` for internationalization
const language = 'es';
const recipes = await Recipe.find().populate({
  path: 'ingredients',
  transform: function(doc) {
    doc.$locals.language = language;
    return doc;
  }
});

// Gets the ingredient's name in Spanish `name.es`
assert.equal(recipes[0].ingredients[0].name, 'Huevos'); // 'Huevos'

```
  Differences vs ES6 Getters/Setters
-----------------------------------

 Mongoose setters are different from [ES6 setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) because they allow you to transform the value being set. With ES6 setters, you would need to store an internal `_email` property to use a setter. With Mongoose, you do **not** need to define an internal `_email` property or define a corresponding getter for `email`.

 
```
class User {
  // This won't convert the email to lowercase! That's because `email`
  // is just a setter, the actual `email` property doesn't store any data.
  // also eslint will warn about using "return" on a setter
  set email(v) {
    // eslint-disable-next-line no-setter-return
    return v.toLowerCase();
  }
}

const user = new User();
user.email = 'TEST@gmail.com';

user.email; // undefined

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/tutorials/getters-setters.html>

Connections
============

 You can connect to MongoDB with the `mongoose.connect()` method.

 
```
mongoose.connect('mongodb://127.0.0.1:27017/myapp');

```
 This is the minimum needed to connect the `myapp` database running locally on the default port (27017). For local MongoDB databases, we recommend using `127.0.0.1` instead of `localhost`. That is because Node.js 18 and up prefer IPv6 addresses, which means, on many machines, Node.js will resolve `localhost` to the IPv6 address `::1` and Mongoose will be unable to connect, unless the mongodb instance is running with ipv6 enabled.

 You can also specify several more parameters in the `uri`:

 
```
mongoose.connect('mongodb://username:password@host:port/database?options...');

```
 See the [mongodb connection string spec](http://www.mongodb.com/docs/manual/reference/connection-string/) for more details.

 Operation Buffering
-------------------

 Mongoose lets you start using your models immediately, without waiting for mongoose to establish a connection to MongoDB.

 
```
mongoose.connect('mongodb://127.0.0.1:27017/myapp');
const MyModel = mongoose.model('Test', new Schema({ name: String }));
// Works
await MyModel.findOne();

```
 That's because mongoose buffers model function calls internally. This buffering is convenient, but also a common source of confusion. Mongoose will *not* throw any errors by default if you use a model without connecting.

 
```
const MyModel = mongoose.model('Test', new Schema({ name: String }));
const promise = MyModel.findOne();

setTimeout(function() {
  mongoose.connect('mongodb://127.0.0.1:27017/myapp');
}, 60000);

// Will just hang until mongoose successfully connects
await promise;

```
 To disable buffering, turn off the [`bufferCommands` option on your schema](guide#bufferCommands). If you have `bufferCommands` on and your connection is hanging, try turning `bufferCommands` off to see if you haven't opened a connection properly. You can also disable `bufferCommands` globally:

 
```
mongoose.set('bufferCommands', false);

```
 Note that buffering is also responsible for waiting until Mongoose creates collections if you use the [`autoCreate` option](guide#autoCreate). If you disable buffering, you should also disable the `autoCreate` option and use [`createCollection()`](api/model#model_Model-createCollection) to create [capped collections](guide#capped) or [collections with collations](guide#collation).

 
```
const schema = new Schema({
  name: String
}, {
  capped: { size: 1024 },
  bufferCommands: false,
  autoCreate: false // disable `autoCreate` since `bufferCommands` is false
});

const Model = mongoose.model('Test', schema);
// Explicitly create the collection before using it
// so the collection is capped.
await Model.createCollection();

```
 Error Handling
--------------

 There are two classes of errors that can occur with a Mongoose connection.

 * **Error on initial connection**: If initial connection fails, Mongoose will emit an 'error' event and the promise `mongoose.connect()` returns will reject. However, Mongoose will **not** automatically try to reconnect.
* **Error after initial connection was established**: Mongoose will attempt to reconnect, and it will emit an 'error' event.

 To handle initial connection errors, you should use `.catch()` or `try/catch` with async/await.

 
```
mongoose.connect('mongodb://127.0.0.1:27017/test').
  catch(error => handleError(error));

// Or:
try {
  await mongoose.connect('mongodb://127.0.0.1:27017/test');
} catch (error) {
  handleError(error);
}

```
 To handle errors after initial connection was established, you should listen for error events on the connection. However, you still need to handle initial connection errors as shown above.

 
```
mongoose.connection.on('error', err => {
  logError(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
-------

 The `connect` method also accepts an `options` object which will be passed on to the underlying MongoDB driver.

 
```
mongoose.connect(uri, options);

```
 A full list of options can be found on the [MongoDB Node.js driver docs for `MongoClientOptions`](https://mongodb.github.io/node-mongodb-native/4.2/interfaces/MongoClientOptions.html). Mongoose passes options to the driver without modification, modulo a few exceptions that are explained below.

 * `bufferCommands` - This is a mongoose-specific option (not passed to the MongoDB driver) that disables [Mongoose's buffering mechanism](https://mongoosejs.com/docs/faq.html#callback_never_executes)
* `user`/`pass` - The username and password for authentication. These options are Mongoose-specific, they are equivalent to the MongoDB driver's `auth.username` and `auth.password` options.
* `autoIndex` - By default, mongoose will automatically build indexes defined in your schema when it connects. This is great for development, but not ideal for large production deployments, because index builds can cause performance degradation. If you set `autoIndex` to false, mongoose will not automatically build indexes for **any** model associated with this connection.
* `dbName` - Specifies which database to connect to and overrides any database specified in the connection string. This is useful if you are unable to specify a default database in the connection string like with [some `mongodb+srv` syntax connections](https://stackoverflow.com/questions/48917591/fail-to-connect-mongoose-to-atlas/48917626#48917626).

 Below are some of the options that are important for tuning Mongoose.

 * `promiseLibrary` - Sets the [underlying driver's promise library](http://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
* `maxPoolSize` - The maximum number of sockets the MongoDB driver will keep open for this connection. By default, `maxPoolSize` is 100. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](http://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs). You may want to decrease `maxPoolSize` if you are running into [connection limits](https://www.mongodb.com/docs/atlas/reference/atlas-limits/#connection-limits-and-cluster-tier).
* `minPoolSize` - The minimum number of sockets the MongoDB driver will keep open for this connection. The MongoDB driver may close sockets that have been inactive for some time. You may want to increase `minPoolSize` if you expect your app to go through long idle times and want to make sure your sockets stay open to avoid slow trains when activity picks up.
* `socketTimeoutMS` - How long the MongoDB driver will wait before killing a socket due to inactivity *after initial connection*. A socket may be inactive because of either no activity or a long-running operation. `socketTimeoutMS` defaults to 0, which means Node.js will not time out the socket due to inactivity. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
* `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 })`
* `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.
* `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
------------------------

 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()`.

 By default, `serverSelectionTimeoutMS` is 30000 (30 seconds). This means that, for example, if you call `mongoose.connect()` when your standalone MongoDB server is down, your `mongoose.connect()` call will only throw an error after 30 seconds.

 
```
// Throws an error "getaddrinfo ENOTFOUND doesnt.exist" after 30 seconds
await mongoose.connect('mongodb://doesnt.exist:27017/test');

```
 Similarly, if your standalone MongoDB server goes down after initial connection, any `find()` or `save()` calls will error out after 30 seconds, unless your MongoDB server is restarted.

 While 30 seconds seems like a long time, `serverSelectionTimeoutMS` means you're unlikely to see any interruptions during a [replica set failover](https://www.mongodb.com/docs/manual/replication/#automatic-failover). If you lose your replica set primary, the MongoDB Node driver will ensure that any operations you send during the replica set election will eventually execute, assuming that the replica set election takes less than `serverSelectionTimeoutMS`.

 To get faster feedback on failed connections, you can reduce `serverSelectionTimeoutMS` to 5000 as follows. We don't recommend reducing `serverSelectionTimeoutMS` unless you are running a standalone MongoDB server rather than a replica set, or unless you are using a serverless runtime like [AWS Lambda](lambda).

 
```
mongoose.connect(uri, {
  serverSelectionTimeoutMS: 5000
});

```
 There is no way to tune `serverSelectionTimeoutMS` independently for `mongoose.connect()` vs for queries. If you want to reduce `serverSelectionTimeoutMS` for queries and other operations, but still retry `mongoose.connect()` for longer, you are responsible for retrying the `connect()` calls yourself using a `for` loop or [a tool like p-retry](https://github.com/Automattic/mongoose/issues/12967#issuecomment-1411227968).

 
```
const serverSelectionTimeoutMS = 5000;

// Prints "Failed 0", "Failed 1", "Failed 2" and then throws an
// error. Exits after approximately 15 seconds.
for (let i = 0; i < 3; ++i) {
  try {
    await mongoose.connect('mongodb://doesnt.exist:27017/test', {
      serverSelectionTimeoutMS
    });
    break;
  } catch (err) {
    console.log('Failed', i);
    if (i >= 2) {
      throw err;
    }
  }
}

```
 Callback
--------

 The `connect()` function also accepts a callback parameter and returns a [promise](promises).

 
```
mongoose.connect(uri, options, function(error) {
  // Check error in initial connection. There is no 2nd param to the callback.
});

// Or using promises
mongoose.connect(uri, options).then(
  () => { /\*\* ready to use. The `mongoose.connect()` promise resolves to mongoose instance. \*/ },
  err => { /\*\* handle initial connection error \*/ }
);

```
 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) portion of the URI. This only applies to options passed to the MongoDB driver. You **can't** set Mongoose-specific options like `bufferCommands` in the query string.

 
```
mongoose.connect('mongodb://127.0.0.1:27017/test?socketTimeoutMS=1000&bufferCommands=false&authSource=otherdb');
// The above is equivalent to:
mongoose.connect('mongodb://127.0.0.1:27017/test', {
  socketTimeoutMS: 1000
  // Note that mongoose will \*\*not\*\* pull `bufferCommands` from the query string
});

```
 The disadvantage of putting options in the query string is that query string options are harder to read. The advantage is that you only need a single configuration option, the URI, rather than separate options for `socketTimeoutMS`, etc. Best practice is to put options that likely differ between development and production, like `replicaSet` or `ssl`, in the connection string, and options that should remain constant, like `socketTimeoutMS` or `maxPoolSize`, in the options object.

 The MongoDB docs have a full list of [supported connection string options](https://www.mongodb.com/docs/manual/reference/connection-string/). Below are some options that are often useful to set in the connection string because they 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
-----------------

 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 connectivity to the MongoDB server. Below is a list of events that a connection may emit.

 * `connecting`: Emitted when Mongoose starts making its initial connection to the MongoDB server
* `connected`: Emitted when Mongoose successfully makes its initial connection to the MongoDB server, or when Mongoose reconnects after losing connectivity. May be emitted multiple times if Mongoose loses connectivity.
* `open`: Emitted after `'connected'` and `onOpen` is executed on all of this connection's models.
* `disconnecting`: Your app called [`Connection#close()`](api/connection#connection_Connection-close) to disconnect from MongoDB
* `disconnected`: Emitted when Mongoose lost connection to the MongoDB server. This event may be due to your code explicitly closing the connection, the database server crashing, or network connectivity issues.
* `close`: Emitted after [`Connection#close()`](api/connection#connection_Connection-close) successfully closes the connection. If you call `conn.close()`, you'll get both a 'disconnected' event and a 'close' event.
* `reconnected`: Emitted if Mongoose lost connectivity to MongoDB and successfully reconnected. Mongoose attempts to [automatically reconnect](https://thecodebarbarian.com/managing-connections-with-the-mongodb-node-driver.html) when it loses connection to the database.
* `error`: Emitted if an error occurs on a connection, like a `parseError` due to malformed data or a payload larger than [16MB](https://www.mongodb.com/docs/manual/reference/limits/#BSON-Document-Size).
* `fullsetup`: Emitted when you're connecting to a replica set and Mongoose has successfully connected to the primary and at least one secondary.
* `all`: Emitted when you're connecting to a replica set and Mongoose has successfully connected to all servers specified in your connection string.

 When you're connecting to a single MongoDB server (a "standalone"), Mongoose will emit 'disconnected' if it gets disconnected from the standalone server, and 'connected' if it successfully connects to the standalone. In a replica set, Mongoose will emit 'disconnected' if it loses connectivity to the replica set primary, and 'connected' if it manages to reconnect to the replica set primary.

 A note about 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 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
-----------------------

 To connect to a replica set you pass a comma delimited list of hosts to connect to rather than a single host.

 
```
mongoose.connect('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]' [, options]);

```
 For example:

 
```
mongoose.connect('mongodb://user:pw@host1.com:27017,host2.com:27017,host3.com:27017/testdb');

```
 To connect to a single node replica set, specify the `replicaSet` option.

 
```
mongoose.connect('mongodb://host1:port1/?replicaSet=rsName');

```
 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`, you'll get the below error:

 
```
MongoTimeoutError: Server selection timed out after 30000 ms

```
 You can configure the timeout using the `serverSelectionTimeoutMS` option to `mongoose.connect()`:

 
```
mongoose.connect(uri, {
  serverSelectionTimeoutMS: 5000 // Timeout after 5s instead of 30s
});

```
 A `MongoTimeoutError` has a `reason` property that explains why server selection timed out. For example, if you're connecting to a standalone server with an incorrect password, `reason` will contain an "Authentication failed" error.

 
```
const mongoose = require('mongoose');

const uri = 'mongodb+srv://username:badpw@cluster0-OMITTED.mongodb.net/' +
  'test?retryWrites=true&w=majority';
// Prints "MongoServerError: bad auth Authentication failed."
mongoose.connect(uri, {
  serverSelectionTimeoutMS: 5000
}).catch(err => console.log(err.reason));

```
 Replica Set Host Names
----------------------

 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. This can cause confusing errors if you're connecting to a remote MongoDB replica set running on a machine that reports its `hostname` as `localhost`:

 
```
// Can get this error even if your connection string doesn't include
// `localhost` if `rs.conf()` reports that one replica set member has
// `localhost` as its host name.
MongooseServerSelectionError: connect ECONNREFUSED localhost:27017

```
 If you're experiencing a similar error, connect to the replica set using the `mongo` shell and run the [`rs.conf()`](https://www.mongodb.com/docs/manual/reference/method/rs.conf/) command to check the host names of each replica set member. Follow [this page's instructions to change a replica set member's host name](https://www.mongodb.com/docs/manual/tutorial/change-hostnames-in-a-replica-set/#change-hostnames-while-maintaining-replica-set-availability).

 You can also check the `reason.servers` property of `MongooseServerSelectionError` to see what the MongoDB Node driver thinks the state of your replica set is. The `reason.servers` property contains a [map](https://masteringjs.io/tutorials/fundamentals/map) of server descriptions.

 
```
if (err.name === 'MongooseServerSelectionError') {
  // Contains a Map describing the state of your replica set. For example:
  // Map(1) {
  // 'localhost:27017' => ServerDescription {
  // address: 'localhost:27017',
  // type: 'Unknown',
  // ...
  // }
  // }
  console.log(err.reason.servers);
}

```
 Multi-mongos support
--------------------

 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 [not need to pass any special options to connect to multiple mongos](http://mongodb.github.io/node-mongodb-native/3.0/tutorials/connect/#connect-to-sharded-cluster) in mongoose 5.x.

 
```
// Connect to 2 mongos servers
mongoose.connect('mongodb://mongosA:27501,mongosB:27501', cb);

```
 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()`. You can access the default connection using `mongoose.connection`.

 You may need multiple connections to MongoDB for several reasons. One reason is if you have multiple databases or multiple MongoDB clusters. Another reason is to work around [slow trains](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs). The `mongoose.createConnection()` function takes the same arguments as `mongoose.connect()` and returns a new connection.

 
```
const conn = mongoose.createConnection('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]', options);

```
 This [connection](api/connection#connection_Connection) object is then used to create and retrieve [models](api/model#model_Model). Models are **always** scoped to a single connection.

 
```
const UserModel = conn.model('User', userSchema);

```
 If you use multiple connections, you should make sure you export schemas, **not** models. Exporting a model from a file is called the *export model pattern*. The export model pattern is limited because you can only use one connection.

 
```
const userSchema = new Schema({ name: String, email: String });

// The alternative to the export model pattern is the export schema pattern.
module.exports = userSchema;

// Because if you export a model as shown below, the model will be scoped
// to Mongoose's default connection.
// module.exports = mongoose.model('User', userSchema);

```
 If you use the export schema pattern, you still need to create models somewhere. There are two common patterns. First is to export a connection and register the models on the connection in the file:

 
```
// connections/fast.js
const mongoose = require('mongoose');

const conn = mongoose.createConnection(process.env.MONGODB\_URI);
conn.model('User', require('../schemas/user'));

module.exports = conn;

// connections/slow.js
const mongoose = require('mongoose');

const conn = mongoose.createConnection(process.env.MONGODB\_URI);
conn.model('User', require('../schemas/user'));
conn.model('PageView', require('../schemas/pageView'));

module.exports = conn;

```
 Another alternative is to register connections with a dependency injector or another [inversion of control (IOC) pattern](https://thecodebarbarian.com/using-ramda-as-a-dependency-injector).

 
```
const mongoose = require('mongoose');

module.exports = function connectionFactory() {
  const conn = mongoose.createConnection(process.env.MONGODB\_URI);

  conn.model('User', require('../schemas/user'));
  conn.model('PageView', require('../schemas/pageView'));

  return conn;
};

```
 Connection Pools
----------------

 Each `connection`, whether created with `mongoose.connect` or `mongoose.createConnection` are all backed by an internal configurable connection pool defaulting to a maximum size of 100. Adjust the pool size using your connection options:

 
```
// With object options
mongoose.createConnection(uri, { maxPoolSize: 10 });

// With connection string options
const uri = 'mongodb://127.0.0.1:27017/test?maxPoolSize=10';
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
------------------------

 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.

 We recommend reading [this article about multi-tenancy with Mongoose](https://medium.com/brightlab-techblog/multitenant-node-js-application-with-mongoose-mongodb-f8841a285b4f); it has a good description of how we define multi-tenancy and a more detailed overview of our recommended patterns.

 There are two patterns we recommend for multi-tenancy in Mongoose:

 1. Maintain one connection pool, switch between tenants using the [`Connection.prototype.useDb()` method](api/connection#Connection.prototype.useDb()).
2. Maintain a separate connection pool per tenant, store connections in a map or [POJO](https://masteringjs.io/tutorials/fundamentals/pojo).

 The following is an example of pattern (1). We recommend pattern (1) for cases where you have a small number of tenants, or if each individual tenant's workload is light (approximately < 1 request per second, all requests take < 10ms of database processing time). Pattern (1) is simpler to implement and simpler to manage in production, because there is only 1 connection pool. But, under high load, you will likely run into issues where some tenants' operations slow down other tenants' operations due to [slow trains](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).

 
```
const express = require('express');
const mongoose = require('mongoose');

mongoose.connect('mongodb://127.0.0.1:27017/main');
mongoose.set('debug', true);

mongoose.model('User', mongoose.Schema({ name: String }));

const app = express();

app.get('/users/:tenantId', function(req, res) {
  const db = mongoose.connection.useDb(`tenant\_${req.params.tenantId}`, {
    // `useCache` tells Mongoose to cache connections by database name, so
    // `mongoose.connection.useDb('foo', { useCache: true })` returns the
    // same reference each time.
    useCache: true
  });
  // Need to register models every time a new connection is created
  if (!db.models['User']) {
    db.model('User', mongoose.Schema({ name: String }));
  }
  console.log('Find users from', db.name);
  db.model('User').find().
    then(users => res.json({ users })).
    catch(err => res.status(500).json({ message: err.message }));
});

app.listen(3000);

```
 The following is an example of pattern (2). Pattern (2) is more flexible and better for use cases with > 10k tenants and > 1 requests/second. Because each tenant has a separate connection pool, one tenants' slow operations will have minimal impact on other tenants. However, this pattern is harder to implement and manage in production. In particular, [MongoDB does have a limit on the number of open connections](https://www.mongodb.com/blog/post/tuning-mongodb--linux-to-allow-for-tens-of-thousands-connections), and [MongoDB Atlas has separate limits on the number of open connections](https://www.mongodb.com/docs/atlas/reference/atlas-limits), so you need to make sure the total number of sockets in your connection pools doesn't go over MongoDB's limits.

 
```
const express = require('express');
const mongoose = require('mongoose');

const tenantIdToConnection = {};

const app = express();

app.get('/users/:tenantId', function(req, res) {
  let initialConnection = Promise.resolve();
  const { tenantId } = req.params;
  if (!tenantIdToConnection[tenantId]) {
    tenantIdToConnection[tenantId] = mongoose.createConnection(`mongodb://127.0.0.1:27017/tenant\_${tenantId}`);
    tenantIdToConnection[tenantId].model('User', mongoose.Schema({ name: String }));
    initialConnection = tenantIdToConnection[tenantId].asPromise();
  }
  const db = tenantIdToConnection[tenantId];
  initialConnection.
    then(() => db.model('User').find()).
    then(users => res.json({ users })).
    catch(err => res.status(500).json({ message: err.message }));
});

app.listen(3000);

```
 Next Up
-------

 Now that we've covered connections, let's take a look at <models>.



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/connections.html>

Subdocuments
=============

 Subdocuments are documents embedded in other documents. In Mongoose, this means you can nest schemas in other schemas. Mongoose has two distinct notions of subdocuments: [arrays of subdocuments](https://masteringjs.io/tutorials/mongoose/array#document-arrays) and single nested subdocuments.

 
```
const childSchema = new Schema({ name: 'string' });

const parentSchema = new Schema({
  // Array of subdocuments
  children: [childSchema],
  // Single nested subdocuments
  child: childSchema
});

```
 Note that populated documents are **not** subdocuments in Mongoose. Subdocument data is embedded in the top-level document. Referenced documents are separate top-level documents.

 
```
const childSchema = new Schema({ name: 'string' });
const Child = mongoose.model('Child', childSchema);

const parentSchema = new Schema({
  child: {
    type: mongoose.ObjectId,
    ref: 'Child'
  }
});
const Parent = mongoose.model('Parent', parentSchema);

const doc = await Parent.findOne().populate('child');
// NOT a subdocument. `doc.child` is a separate top-level document.
doc.child;

```
  What is a Subdocument?
-----------------------

 Subdocuments are similar to normal documents. Nested schemas can have <middleware>, [custom validation logic](validation), virtuals, and any other feature top-level schemas can use. The major difference is that subdocuments are not saved individually, they are saved whenever their top-level parent document is saved.

 
```
const Parent = mongoose.model('Parent', parentSchema);
const parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] });
parent.children[0].name = 'Matthew';

// `parent.children[0].save()` is a no-op, it triggers middleware but
// does \*\*not\*\* actually save the subdocument. You need to save the parent
// doc.
await parent.save();

```
 Subdocuments have `save` and `validate` <middleware> just like top-level documents. Calling `save()` on the parent document triggers the `save()` middleware for all its subdocuments, and the same for `validate()` middleware.

 
```
childSchema.pre('save', function(next) {
  if ('invalid' == this.name) {
    return next(new Error('#sadpanda'));
  }
  next();
});

const parent = new Parent({ children: [{ name: 'invalid' }] });
try {
  await parent.save();
} catch (err) {
  err.message; // '#sadpanda'
}

```
 Subdocuments' `pre('save')` and `pre('validate')` middleware execute **before** the top-level document's `pre('save')` but **after** the top-level document's `pre('validate')` middleware. This is because validating before `save()` is actually a piece of built-in middleware.

 
```
// Below code will print out 1-4 in order
const childSchema = new mongoose.Schema({ name: 'string' });

childSchema.pre('validate', function(next) {
  console.log('2');
  next();
});

childSchema.pre('save', function(next) {
  console.log('3');
  next();
});

const parentSchema = new mongoose.Schema({
  child: childSchema
});

parentSchema.pre('validate', function(next) {
  console.log('1');
  next();
});

parentSchema.pre('save', function(next) {
  console.log('4');
  next();
});

```
  Subdocuments versus Nested Paths
---------------------------------

 In Mongoose, nested paths are subtly different from subdocuments. For example, below are two schemas: one with `child` as a subdocument, and one with `child` as a nested path.

 
```
// Subdocument
const subdocumentSchema = new mongoose.Schema({
  child: new mongoose.Schema({ name: String, age: Number })
});
const Subdoc = mongoose.model('Subdoc', subdocumentSchema);

// Nested path
const nestedSchema = new mongoose.Schema({
  child: { name: String, age: Number }
});
const Nested = mongoose.model('Nested', nestedSchema);

```
 These two schemas look similar, and the documents in MongoDB will have the same structure with both schemas. But there are a few Mongoose-specific differences:

 First, instances of `Nested` never have `child === undefined`. You can always set subproperties of `child`, even if you don't set the `child` property. But instances of `Subdoc` can have `child === undefined`.

 
```
const doc1 = new Subdoc({});
doc1.child === undefined; // true
doc1.child.name = 'test'; // Throws TypeError: cannot read property...

const doc2 = new Nested({});
doc2.child === undefined; // false
console.log(doc2.child); // Prints 'MongooseDocument { undefined }'
doc2.child.name = 'test'; // Works

```
  Subdocument Defaults
---------------------

 Subdocument paths are undefined by default, and Mongoose does not apply subdocument defaults unless you set the subdocument path to a non-nullish value.

 
```
const subdocumentSchema = new mongoose.Schema({
  child: new mongoose.Schema({
    name: String,
    age: {
      type: Number,
      default: 0
    }
  })
});
const Subdoc = mongoose.model('Subdoc', subdocumentSchema);

// Note that the `age` default has no effect, because `child`
// is `undefined`.
const doc = new Subdoc();
doc.child; // undefined

```
 However, if you set `doc.child` to any object, Mongoose will apply the `age` default if necessary.

 
```
doc.child = {};
// Mongoose applies the `age` default:
doc.child.age; // 0

```
 Mongoose applies defaults recursively, which means there's a nice workaround if you want to make sure Mongoose applies subdocument defaults: make the subdocument path default to an empty object.

 
```
const childSchema = new mongoose.Schema({
  name: String,
  age: {
    type: Number,
    default: 0
  }
});
const subdocumentSchema = new mongoose.Schema({
  child: {
    type: childSchema,
    default: () => ({})
  }
});
const Subdoc = mongoose.model('Subdoc', subdocumentSchema);

// Note that Mongoose sets `age` to its default value 0, because
// `child` defaults to an empty object and Mongoose applies
// defaults to that empty object.
const doc = new Subdoc();
doc.child; // { age: 0 }

```
  Finding a Subdocument
----------------------

 Each subdocument has an `_id` by default. Mongoose document arrays have a special [id](api/mongoosedocumentarray#mongoosedocumentarray_MongooseDocumentArray-id) method for searching a document array to find a document with a given `_id`.

 
```
const doc = parent.children.id(_id);

```
  Adding Subdocs to Arrays
-------------------------

 MongooseArray methods such as `push`, `unshift`, `addToSet`, and others cast arguments to their proper types transparently:

 
```
const Parent = mongoose.model('Parent');
const parent = new Parent();

// create a comment
parent.children.push({ name: 'Liesl' });
const subdoc = parent.children[0];
console.log(subdoc); // { \_id: '501d86090d371bab2c0341c5', name: 'Liesl' }
subdoc.isNew; // true

await parent.save();
console.log('Success!');

```
 You can also create a subdocument without adding it to an array by using the [`create()` method](api/mongoosedocumentarray#mongoosedocumentarray_MongooseDocumentArray-create) of Document Arrays.

 
```
const newdoc = parent.children.create({ name: 'Aaron' });

```
  Removing Subdocs
-----------------

 Each subdocument has its own [deleteOne](api/subdocument#Subdocument.prototype.deleteOne()) method. For an array subdocument, this is equivalent to calling `.pull()` on the subdocument. For a single nested subdocument, `deleteOne()` is equivalent to setting the subdocument to [`null`](https://masteringjs.io/tutorials/fundamentals/null).

 
```
// Equivalent to `parent.children.pull(\_id)`
parent.children.id(_id).deleteOne();
// Equivalent to `parent.child = null`
parent.child.deleteOne();

await parent.save();
console.log('the subdocs were removed');

```
 Parents of Subdocs
------------------

 Sometimes, you need to get the parent of a subdoc. You can access the parent using the `parent()` function.

 
```
const schema = new Schema({
  docArr: [{ name: String }],
  singleNested: new Schema({ name: String })
});
const Model = mongoose.model('Test', schema);

const doc = new Model({
  docArr: [{ name: 'foo' }],
  singleNested: { name: 'bar' }
});

doc.singleNested.parent() === doc; // true
doc.docArr[0].parent() === doc; // true

```
 If you have a deeply nested subdoc, you can access the top-level document using the `ownerDocument()` function.

 
```
const schema = new Schema({
  level1: new Schema({
    level2: new Schema({
      test: String
    })
  })
});
const Model = mongoose.model('Test', schema);

const doc = new Model({ level1: { level2: 'test' } });

doc.level1.level2.parent() === doc; // false
doc.level1.level2.parent() === doc.level1; // true
doc.level1.level2.ownerDocument() === doc; // true

```
 ### Alternate declaration syntax for arrays

 If you create a schema with an array of objects, Mongoose will automatically convert the object to a schema for you:

 
```
const parentSchema = new Schema({
  children: [{ name: 'string' }]
});
// Equivalent
const parentSchema = new Schema({
  children: [new Schema({ name: 'string' })]
});

```
 ###  Next Up

 Now that we've covered Subdocuments, let's take a look at [querying](queries).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/subdocs.html>

Discriminators
===============

  The `model.discriminator()` function
-------------------------------------

 Discriminators are a schema inheritance mechanism. They enable you to have multiple models with overlapping schemas on top of the same underlying MongoDB collection.

 Suppose you wanted to track different types of events in a single collection. Every event will have a timestamp, but events that represent clicked links should have a URL. You can achieve this using the `model.discriminator()` function. This function takes 3 parameters, a model name, a discriminator schema and an optional key (defaults to the model name). It returns a model whose schema is the union of the base schema and the discriminator schema.

 
```
const options = { discriminatorKey: 'kind' };

const eventSchema = new mongoose.Schema({ time: Date }, options);
const Event = mongoose.model('Event', eventSchema);

// ClickedLinkEvent is a special type of Event that has
// a URL.
const ClickedLinkEvent = Event.discriminator('ClickedLink',
  new mongoose.Schema({ url: String }, options));

// When you create a generic event, it can't have a URL field...
const genericEvent = new Event({ time: Date.now(), url: 'google.com' });
assert.ok(!genericEvent.url);

// But a ClickedLinkEvent can
const clickedEvent = new ClickedLinkEvent({ time: Date.now(), url: 'google.com' });
assert.ok(clickedEvent.url);

```
  Discriminators save to the Event model's collection
----------------------------------------------------

 Suppose you created another discriminator to track events where a new user registered. These `SignedUpEvent` instances will be stored in the same collection as generic events and `ClickedLinkEvent` instances.

 
```
const event1 = new Event({ time: Date.now() });
const event2 = new ClickedLinkEvent({ time: Date.now(), url: 'google.com' });
const event3 = new SignedUpEvent({ time: Date.now(), user: 'testuser' });


await Promise.all([event1.save(), event2.save(), event3.save()]);
const count = await Event.countDocuments();
assert.equal(count, 3);

```
  Discriminator keys
-------------------

 The way Mongoose tells the difference between the different discriminator models is by the 'discriminator key', which is `__t` by default. Mongoose adds a String path called `__t` to your schemas that it uses to track which discriminator this document is an instance of.

 
```
const event1 = new Event({ time: Date.now() });
const event2 = new ClickedLinkEvent({ time: Date.now(), url: 'google.com' });
const event3 = new SignedUpEvent({ time: Date.now(), user: 'testuser' });

assert.ok(!event1.\_\_t);
assert.equal(event2.\_\_t, 'ClickedLink');
assert.equal(event3.\_\_t, 'SignedUp');

```
  Updating the discriminator key
-------------------------------

 By default, Mongoose doesn't let you update the discriminator key. `save()` will throw an error if you attempt to update the discriminator key. And `findOneAndUpdate()`, `updateOne()`, etc. will strip out discriminator key updates.

 
```
let event = new ClickedLinkEvent({ time: Date.now(), url: 'google.com' });
await event.save();

event.\_\_t = 'SignedUp';
// ValidationError: ClickedLink validation failed: \_\_t: Cast to String failed for value "SignedUp" (type string) at path "\_\_t"
  await event.save();

event = await ClickedLinkEvent.findByIdAndUpdate(event.\_id, { \_\_t: 'SignedUp' }, { new: true });
event.\_\_t; // 'ClickedLink', update was a no-op

```
 To update a document's discriminator key, use `findOneAndUpdate()` or `updateOne()` with the `overwriteDiscriminatorKey` option set as follows.

 
```
let event = new ClickedLinkEvent({ time: Date.now(), url: 'google.com' });
await event.save();

event = await ClickedLinkEvent.findByIdAndUpdate(
  event.\_id,
  { \_\_t: 'SignedUp' },
  { overwriteDiscriminatorKey: true, new: true }
);
event.\_\_t; // 'SignedUp', updated discriminator key

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/discriminators.html>

Migrating from 6.x to 7.x
==========================

 There are several backwards-breaking changes you should be aware of when migrating from Mongoose 6.x to Mongoose 7.x.

 If you're still on Mongoose 5.x, please read the [Mongoose 5.x to 6.x migration guide](migrating_to_6) and upgrade to Mongoose 6.x first.

 * [`strictQuery`](#strictquery)
* [Removed `remove()`](#removed-remove)
* [Dropped callback support](#dropped-callback-support)
* [Removed `update()`](#removed-update)
* [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)
* [ObjectId bsontype now has lowercase d](#objectid-bsontype-now-has-lowercase-d)
* [Removed support for custom promise libraries](#removed-support-for-custom-promise-libraries)
* [Removed mapReduce](#removed-mapreduce)
* [TypeScript-specific changes](#typescript-specific-changes)
	+ [Removed `LeanDocument` and support for `extends Document`](#removed-leandocument-and-support-for-extends-document)
	+ [New parameters for `HydratedDocument`](#new-parameters-for-hydrateddocument)

 `strictQuery`
-------------

 `strictQuery` is now false by default.

 
```
const mySchema = new Schema({ field: Number });
const MyModel = mongoose.model('Test', mySchema);

// Mongoose will not strip out `notInSchema: 1` because `strictQuery` is false by default
const docs = await MyModel.find({ notInSchema: 1 });
// Empty array in Mongoose 7. In Mongoose 6, this would contain all documents in MyModel
docs;

```
 Removed `remove()`
------------------

 The `remove()` method on documents and models has been removed. Use `deleteOne()` or `deleteMany()` instead.

 
```
const mySchema = new Schema({ field: Number });
const MyModel = mongoose.model('Test', mySchema);

// Change this:
await MyModel.remove(filter);

// To this:
await MyModel.deleteOne(filter);
// Or this, if you want to delete multiple:
await MyModel.deleteMany(filter);

// For documents, change this:
await doc.remove();

// To this:
await doc.deleteOne();

```
 Keep in mind that `deleteOne()` hooks are treated as query middleware by default. So for middleware, please do the following:

 
```
// Replace this:
schema.pre('remove', function() {
  /\* ... \*/
});

// With this:
schema.pre('deleteOne', { document: true, query: false }, function() {
  /\* ... \*/
});

```
 Dropped callback support
------------------------

 The following functions no longer accept callbacks. They always return promises.

 * `Aggregate.prototype.exec`
* `Aggregate.prototype.explain`
* `AggregationCursor.prototype.close`
* `Connection.prototype.startSession`
* `Connection.prototype.dropCollection`
* `Connection.prototype.createCollection`
* `Connection.prototype.dropDatabase`
* `Connection.prototype.openUri`
* `Connection.prototype.close`
* `Connection.prototype.destroy`
* `Document.prototype.populate`
* `Document.prototype.validate`
* `Mongoose.prototype.connect`
* `Mongoose.prototype.createConnection`
* `Model.prototype.save`
* `Model.aggregate`
* `Model.bulkWrite`
* `Model.cleanIndexes`
* `Model.countDocuments`
* `Model.create`
* `Model.createCollection`
* `Model.createIndexes`
* `Model.deleteOne`
* `Model.deleteMany`
* `Model.distinct`
* `Model.ensureIndexes`
* `Model.estimatedDocumentCount`
* `Model.exists`
* `Model.find`
* `Model.findById`
* `Model.findByIdAndUpdate`
* `Model.findByIdAndReplace`
* `Model.findOne`
* `Model.findOneAndDelete`
* `Model.findOneAndUpdate`
* `Model.findOneAndRemove`
* `Model.insertMany`
* `Model.listIndexes`
* `Model.replaceOne`
* `Model.syncIndexes`
* `Model.updateMany`
* `Model.updateOne`
* `Query.prototype.find`
* `Query.prototype.findOne`
* `Query.prototype.findOneAndDelete`
* `Query.prototype.findOneAndUpdate`
* `Query.prototype.findOneAndRemove`
* `Query.prototype.findOneAndReplace`
* `Query.prototype.validate`
* `Query.prototype.deleteOne`
* `Query.prototype.deleteMany`
* `Query.prototype.exec`
* `QueryCursor.prototype.close`
* `QueryCursor.prototype.next`

 If you are using the above functions with callbacks, we recommend switching to async/await, or promises if async functions don't work for you. If you need help refactoring a legacy codebase, [this tool from Mastering JS callbacks to async await](https://masteringjs.io/tutorials/tools/callback-to-async-await) using ChatGPT.

 
```
// Before
conn.startSession(function(err, session) {
  // ...
});

// After
const session = await conn.startSession();
// Or:
conn.startSession().then(sesson => { /\* ... \*/ });

// With error handling
try {
  await conn.startSession();
} catch (err) { /\* ... \*/ }
// Or:
const [err, session] = await conn.startSession().then(
  session => ([null, session]),
  err => ([err, null])
);

```
 Removed `update()`
------------------

 `Model.update()`, `Query.prototype.update()`, and `Document.prototype.update()` have been removed. Use `updateOne()` instead.

 
```
// Before
await Model.update(filter, update);
await doc.update(update);

// After
await Model.updateOne(filter, update);
await doc.updateOne(update);

```
 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.

 
```
const baseSchema = Schema({}, { typeKey: '$type' });
const Base = db.model('Base', baseSchema);

// In Mongoose 6.x, the `Base.discriminator()` call would throw because
// no `typeKey` option. In Mongoose 7, Mongoose uses the base schema's
// `typeKey` by default.
const childSchema = new Schema({}, {});
const Test = Base.discriminator('Child', childSchema);

Test.schema.options.typeKey; // '$type'

```
 Removed `castForQueryWrapper`, updated `castForQuery()` signature
-----------------------------------------------------------------

 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.

 
```
// Mongoose 6.x format:
MySchemaType.prototype.castForQuery = function($conditional, value) {
  if (arguments.length === 2) {
    // Handle casting value with `$conditional` - $eq, $in, $not, etc.
  } else {
    value = $conditional;
    // Handle casting `value` with no conditional
  }
};

// Mongoose 7.x format
MySchemaType.prototype.castForQuery = function($conditional, value, context) {
  if ($conditional != null) {
    // Handle casting value with `$conditional` - $eq, $in, $not, etc.
  } else {
    // Handle casting `value` with no conditional
  }
};

```
 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.

 
```
const baseSchema = new Schema({ created: Date }, { id: true, toJSON: { virtuals: true } });
const childSchema = new Schema([baseSchema, { name: String }]);

childSchema.options.toJSON; // { virtuals: true } in Mongoose 7. undefined in Mongoose 6.

```
 This applies both when creating a new schema using an array of schemas, as well as when calling `add()` as follows.

 
```
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
-------------------------------------

 The internal `_bsontype` property on ObjectIds is equal to `'ObjectId'` in Mongoose 7, as opposed to `'ObjectID'` in Mongoose 6.

 
```
const oid = new mongoose.Types.ObjectId();

oid.\_bsontype; // 'ObjectId' in Mongoose 7, 'ObjectID' in older versions of Mongoose

```
 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
-----------------

 MongoDB no longer supports `mapReduce`, so Mongoose 7 no longer has a `Model.mapReduce()` function. Use the aggregation framework as a replacement for `mapReduce()`.

 
```
// The following no longer works in Mongoose 7.
const o = {
  map: function() {
    emit(this.author, 1);
  },
  reduce: function(k, vals) {
    return vals.length;
  }
};

await MR.mapReduce(o);

```
 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.

 
```
const mongoose = require('mongoose');

// No-op on Mongoose 7
mongoose.Promise = require('bluebird');

```
 If you want to use Bluebird for all promises globally, you can do the following:

 
```
global.Promise = require('bluebird');

```
 TypeScript-specific Changes
---------------------------

 ### 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<>`.

 
```
// No longer supported
interface ITest extends Document {
  name?: string;
}
const Test = model<ITest>('Test', schema);

// Do this instead, no `extends Document`
interface ITest {
  name?: string;
}
const Test = model<ITest>('Test', schema);

// If you need to access the hydrated document type, use the following code
type TestDocument = ReturnType<(typeof Test)['hydrate']>;

```
 ### 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. In Mongoose 6, the generic parameters were:

 
```
type HydratedDocument<
  DocType,
  TMethodsAndOverrides = {},
  TVirtuals = {}
> = Document<unknown, any, DocType> &
Require_id<DocType> &
TMethodsAndOverrides &
TVirtuals;

```
 In Mongoose 7, the new type is as follows.

 
```
type HydratedDocument<
  DocType,
  TOverrides = {},
  TQueryHelpers = {}
> = Document<unknown, TQueryHelpers, DocType> &
Require_id<DocType> &
TOverrides;

```
 In Mongoose 7, the first parameter is the raw document interface, the 2nd parameter is any document-specific overrides (usually virtuals and methods), and the 3rd parameter is any query helpers associated with the document's model.

 The key difference is that, in Mongoose 6, the 3rd generic param was the document's *virtuals*. In Mongoose 7, the 3rd generic param is the document's *query helpers*.

 
```
// Mongoose 6 version:
type UserDocument = HydratedDocument<TUser, TUserMethods, TUserVirtuals>;

// Mongoose 7:
type UserDocument = HydratedDocument<TUser, TUserMethods & TUserVirtuals, TUserQueryHelpers>;

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/migrating_to_7.html>

SchemaDateOptions
=================



### SchemaDateOptions()


##### Type:


* «constructor»


##### Inherits:


* [«SchemaTypeOptions»](schematypeoptions)



The options defined on a Date schematype.

 ####   [Example:](#example)

 
```
const schema = new Schema({ startedAt: Date });
schema.path('startedAt').options; // SchemaDateOptions instance

```
 
### SchemaDateOptions.prototype.expires


##### Type:


* «Date»



If set, Mongoose creates a TTL index on this path.

 mongo TTL index `expireAfterSeconds` value will take 'expires' value expressed in seconds.

 ####   [Example:](#example)

 
```
const schema = new Schema({ "expireAt": { type: Date,  expires: 11 } });
// if 'expireAt' is set, then document expires at expireAt + 11 seconds

```
 
### SchemaDateOptions.prototype.max


##### Type:


* «Date»



If set, Mongoose adds a validator that checks that this path is before the given `max`.

 
### SchemaDateOptions.prototype.min


##### Type:


* «Date»



If set, Mongoose adds a validator that checks that this path is after the given `min`.

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schemadateoptions.html>

SchemaTypeOptions
=================



### SchemaTypeOptions()


##### Type:


* «constructor»



The options defined on a schematype.

 ####   [Example:](#example)

 
```
const schema = new Schema({ name: String });
schema.path('name').options instanceof mongoose.SchemaTypeOptions; // true

```
 
### SchemaTypeOptions.prototype.cast


##### Type:


* «String»



Allows overriding casting logic for this individual path. If a string, the given string overwrites Mongoose's default cast error message.

 ####   [Example:](#example)

 
```
const schema = new Schema({
  num: {
    type: Number,
    cast: '{VALUE} is not a valid number'
  }
});

// Throws 'CastError: "bad" is not a valid number'
schema.path('num').cast('bad');

const Model = mongoose.model('Test', schema);
const doc = new Model({ num: 'fail' });
const err = doc.validateSync();

err.errors['num']; // 'CastError: "fail" is not a valid number'

```
 
### SchemaTypeOptions.prototype.default


##### Type:


* «Function|Any»



The default value for this path. If a function, Mongoose executes the function and uses the return value as the default.

 
### SchemaTypeOptions.prototype.immutable


##### Type:


* «Function|Boolean»



If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will disallow changes to this path once the document is saved to the database for the first time. Read more about [immutability in Mongoose here](https://thecodebarbarian.com/whats-new-in-mongoose-5-6-immutable-properties.html).

 
### SchemaTypeOptions.prototype.index


##### Type:


* «Boolean|Number|Object»



If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will build an index on this path when the model is compiled.

 
### SchemaTypeOptions.prototype.ref


##### Type:


* «Function|String»



The model that `populate()` should use if populating this path.

 
### SchemaTypeOptions.prototype.ref


##### Type:


* «Function|String»



The path in the document that `populate()` should use to find the model to use.

 
### SchemaTypeOptions.prototype.required


##### Type:


* «Function|Boolean»



If true, attach a required validator to this path, which ensures this path cannot be set to a nullish value. If a function, Mongoose calls the function and only checks for nullish values if the function returns a truthy value.

 
### SchemaTypeOptions.prototype.select


##### Type:


* «Boolean|Number»



Whether to include or exclude this path by default when loading documents using `find()`, `findOne()`, etc.

 
### SchemaTypeOptions.prototype.sparse


##### Type:


* «Boolean|Number»



If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will build a sparse index on this path.

 
### SchemaTypeOptions.prototype.text


##### Type:


* «Boolean|Number|Object»



If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will build a text index on this path.

 
### SchemaTypeOptions.prototype.transform


##### Type:


* «Function»



Define a transform function for this individual schema type. Only called when calling `toJSON()` or `toObject()`.

 ####   [Example:](#example)

 
```
const schema = Schema({
  myDate: {
    type: Date,
    transform: v => v.getFullYear()
  }
});
const Model = mongoose.model('Test', schema);

const doc = new Model({ myDate: new Date('2019/06/01') });
doc.myDate instanceof Date; // true

const res = doc.toObject({ transform: true });
res.myDate; // 2019

```
 
### SchemaTypeOptions.prototype.type


##### Type:


* «Function|String|Object»



The type to cast this path to.

 
### SchemaTypeOptions.prototype.unique


##### Type:


* «Boolean|Number»



If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will build a unique index on this path when the model is compiled. [The `unique` option is **not** a validator](../validation#the-unique-option-is-not-a-validator).

 
### SchemaTypeOptions.prototype.validate


##### Type:


* «Function|Object»



Function or object describing how to validate this schematype.

 


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/api/schematypeoptions.html>

Custom Schema Types
====================

  Creating a Basic Custom Schema Type
------------------------------------

 *New in Mongoose 4.4.0:* Mongoose supports custom types. Before you reach for a custom type, however, know that a custom type is overkill for most use cases. You can do most basic tasks with [custom getters/setters](http://mongoosejs.com/docs/2.7.x/docs/getters-setters.html), [virtuals](http://mongoosejs.com/docs/guide.html#virtuals), and [single embedded docs](http://mongoosejs.com/docs/subdocs.html#single-embedded).

 Let's take a look at an example of a basic schema type: a 1-byte integer. To create a new schema type, you need to inherit from `mongoose.SchemaType` and add the corresponding property to `mongoose.Schema.Types`. The one method you need to implement is the `cast()` method.

 
```
class Int8 extends mongoose.SchemaType {
  constructor(key, options) {
    super(key, options, 'Int8');
  }

  // `cast()` takes a parameter that can be anything. You need to
  // validate the provided `val` and throw a `CastError` if you
  // can't convert it.
  cast(val) {
    let _val = Number(val);
    if (isNaN(_val)) {
      throw new Error('Int8: ' + val + ' is not a number');
    }
    _val = Math.round(_val);
    if (_val < -0x80 || _val > 0x7F) {
      throw new Error('Int8: ' + val +
        ' is outside of the range of valid 8-bit ints');
    }
    return _val;
  }
}

// Don't forget to add `Int8` to the type registry
mongoose.Schema.Types.Int8 = Int8;

const testSchema = new Schema({ test: Int8 });
const Test = mongoose.model('CustomTypeExample', testSchema);

const t = new Test();
t.test = 'abc';
assert.ok(t.validateSync());
assert.equal(t.validateSync().errors['test'].name, 'CastError');
assert.equal(t.validateSync().errors['test'].message,
  'Cast to Int8 failed for value "abc" (type string) at path "test"');
assert.equal(t.validateSync().errors['test'].reason.message,
  'Int8: abc is not a number');

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/customschematypes.html>

Promises
=========

  Built-in Promises
------------------

 Mongoose async operations, like `.save()` and queries, return thenables. This means that you can do things like `MyModel.findOne({}).then()` and `await MyModel.findOne({}).exec()` if you're using [async/await](http://thecodebarbarian.com/80-20-guide-to-async-await-in-node.js.html).

 You can find the return type of specific operations [in the api docs](api/mongoose) You can also read more about [promises in Mongoose](https://masteringjs.io/tutorials/mongoose/promise).

 
```
const gnr = new Band({
  name: 'Guns N\' Roses',
  members: ['Axl', 'Slash']
});

const promise = gnr.save();
assert.ok(promise instanceof Promise);

promise.then(function(doc) {
  assert.equal(doc.name, 'Guns N\' Roses');
});

```
  Queries are not promises
-------------------------

 [Mongoose queries](http://mongoosejs.com/docs/queries.html) are **not** promises. They have a `.then()` function for [co](https://www.npmjs.com/package/co) and async/await as a convenience. If you need a fully-fledged promise, use the `.exec()` function.

 
```
const query = Band.findOne({ name: 'Guns N\' Roses' });
assert.ok(!(query instanceof Promise));

// A query is not a fully-fledged promise, but it does have a `.then()`.
query.then(function(doc) {
  // use doc
});

// `.exec()` gives you a fully-fledged promise
const promise = Band.findOne({ name: 'Guns N\' Roses' }).exec();
assert.ok(promise instanceof Promise);

promise.then(function(doc) {
  // use doc
});

```
  Queries are thenable
---------------------

 Although queries are not promises, queries are [thenables](https://promisesaplus.com/#terminology). That means they have a `.then()` function, so you can use queries as promises with either promise chaining or [async await](https://asyncawait.net)

 
```
Band.findOne({ name: 'Guns N\' Roses' }).then(function(doc) {
  // use doc
});

```
  Should You Use `exec()` With `await`?
--------------------------------------

 There are two alternatives for using `await` with queries:

 * `await Band.findOne();`
* `await Band.findOne().exec();`

 As far as functionality is concerned, these two are equivalent. However, we recommend using `.exec()` because that gives you better stack traces.

 
```
const doc = await Band.findOne({ name: 'Guns N\' Roses' }); // works

const badId = 'this is not a valid id';
try {
  await Band.findOne({ \_id: badId });
} catch (err) {
  // Without `exec()`, the stack trace does \*\*not\*\* include the
  // calling code. Below is the stack trace:
  //
  // CastError: Cast to ObjectId failed for value "this is not a valid id" at path "\_id" for model "band-promises"
  // at new CastError (/app/node\_modules/mongoose/lib/error/cast.js:29:11)
  // at model.Query.exec (/app/node\_modules/mongoose/lib/query.js:4331:21)
  // at model.Query.Query.then (/app/node\_modules/mongoose/lib/query.js:4423:15)
  // at process.\_tickCallback (internal/process/next\_tick.js:68:7)
  err.stack;
}

try {
  await Band.findOne({ \_id: badId }).exec();
} catch (err) {
  // With `exec()`, the stack trace includes where in your code you
  // called `exec()`. Below is the stack trace:
  //
  // CastError: Cast to ObjectId failed for value "this is not a valid id" at path "\_id" for model "band-promises"
  // at new CastError (/app/node\_modules/mongoose/lib/error/cast.js:29:11)
  // at model.Query.exec (/app/node\_modules/mongoose/lib/query.js:4331:21)
  // at Context.<anonymous> (/app/test/index.test.js:138:42)
  // at process.\_tickCallback (internal/process/next\_tick.js:68:7)
  err.stack;
}

```
  *Want to learn how to check whether your favorite npm modules work with async/await without cobbling together contradictory answers from Google and Stack Overflow? Chapter 4 of Mastering Async/Await explains the basic principles for determining whether frameworks like React and Mongoose support async/await. [Get your copy!](http://asyncawait.net/?utm_source=mongoosejs&utm_campaign=promises)*    
  
  [![] 

 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/promises.html>

Using Mongoose With AWS Lambda
===============================

 [AWS Lambda](https://aws.amazon.com/lambda/) is a popular service for running arbitrary functions without managing individual servers. Using Mongoose in your AWS Lambda functions is easy. Here's a sample function that connects to a MongoDB instance and finds a single document:

 
```
const mongoose = require('mongoose');

let conn = null;

const uri = 'YOUR CONNECTION STRING HERE';

exports.handler = async function(event, context) {
  // Make sure to add this so you can re-use `conn` between function calls.
  // See https://www.mongodb.com/blog/post/serverless-development-with-nodejs-aws-lambda-mongodb-atlas
  context.callbackWaitsForEmptyEventLoop = false;

  // Because `conn` is in the global scope, Lambda may retain it between
  // function calls thanks to `callbackWaitsForEmptyEventLoop`.
  // This means your Lambda function doesn't have to go through the
  // potentially expensive process of connecting to MongoDB every time.
  if (conn == null) {
    conn = mongoose.createConnection(uri, {
      // and tell the MongoDB driver to not wait more than 5 seconds
      // before erroring out if it isn't connected
      serverSelectionTimeoutMS: 5000
    });

    // `await`ing connection after assigning to the `conn` variable
    // to avoid multiple function calls creating new connections
    await conn.asPromise();
    conn.model('Test', new mongoose.Schema({ name: String }));
  }

  const M = conn.model('Test');

  const doc = await M.findOne();
  console.log(doc);

  return doc;
};

```
  Connection Helper
------------------

 The above code works fine for a single Lambda function, but what if you want to reuse the same connection logic in multiple Lambda functions? You can export the below function.

 
```
const mongoose = require('mongoose');

let conn = null;

const uri = 'YOUR CONNECTION STRING HERE';

exports.connect = async function() {
  if (conn == null) {
    conn = mongoose.createConnection(uri, {
      serverSelectionTimeoutMS: 5000
    });

    // `await`ing connection after assigning to the `conn` variable
    // to avoid multiple function calls creating new connections
    await conn.asPromise();
  }

  return conn;
};

```
  Using `mongoose.connect()`
---------------------------

 You can also use `mongoose.connect()`, so you can use `mongoose.model()` to create models.

 
```
const mongoose = require('mongoose');

let conn = null;

const uri = 'YOUR CONNECTION STRING HERE';

exports.connect = async function() {
  if (conn == null) {
    conn = mongoose.connect(uri, {
      serverSelectionTimeoutMS: 5000
    }).then(() => mongoose);

    // `await`ing connection after assigning to the `conn` variable
    // to avoid multiple function calls creating new connections
    await conn;
  }

  return conn;
};

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/lambda.html>

Migrating from 5.x to 6.x
==========================

 Please note: we plan to discontinue Mongoose 5 support on March 1, 2024. Please see our [version support guide](version-support).

 There are several [backwards-breaking changes](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) you should be aware of when migrating from Mongoose 5.x to Mongoose 6.x.

 If you're still on Mongoose 4.x, please read the [Mongoose 4.x to 5.x migration guide](migrating_to_5) and upgrade to Mongoose 5.x first.

 * [Version Requirements](#version-requirements)
* [MongoDB Driver 4.0](#mongodb-driver-40)
* [No More Deprecation Warning Options](#no-more-deprecation-warning-options)
* [The `asPromise()` Method for Connections](#the-aspromise-method-for-connections)
* [`mongoose.connect()` Returns a Promise](#mongoose-connect-returns-a-promise)
* [Duplicate Query Execution](#duplicate-query-execution)
* [`Model.exists()` Returns a lean document instead of Boolean](#model-exists-returns-a-lean-document-instead-of-boolean)
* [`strictQuery` is now equal to `strict` by default](#strictquery-is-removed-and-replaced-by-strict)
* [MongoError is now MongoServerError](#mongoerror-is-now-mongoservererror)
* [Simplified `isValidObjectId()` and separate `isObjectIdOrHexString()`](#simplified-isvalidobjectid-and-separate-isobjectidorhexstring)
* [Clone Discriminator Schemas By Default](#clone-discriminator-schemas-by-default)
* [Schema Defined Document Key Order](#schema-defined-document-key-order)
* [`sanitizeFilter` and `trusted()`](#sanitizefilter-and-trusted)
* [Removed `omitUndefined`: Mongoose now removes `undefined` keys in updates instead of setting them to `null`](#removed-omitundefined)
* [Document Parameter to Default Functions](#document-parameter-to-default-functions)
* [Arrays are Proxies](#arrays-are-proxies)
* [`typePojoToMixed`](#typepojotomixed)
* [`strictPopulate()`](#strictpopulate)
* [Subdocument `ref` Function Context](#subdocument-ref-function-context)
* [Schema Reserved Names Warning](#schema-reserved-names-warning)
* [Subdocument Paths](#subdocument-paths)
* [Creating Aggregation Cursors](#creating-aggregation-cursors)
* [`autoCreate` Defaults to `true`](#autocreate-defaults-to-true)
* [No More `context: 'query'`](#no-more-context-query)
* [Custom Validators with Populated Paths](#custom-validators-with-populated-paths)
* [Disconnected Event with Replica Sets](#disconnected-event-with-replica-sets)
* [Removed `execPopulate()`](#removed-execpopulate)
* [`create()` with Empty Array](#create-with-empty-array)
* [Removed Nested Path Merging](#removed-nested-path-merging)
* [ObjectId `valueOf()`](#objectid-valueof)
* [Immutable `createdAt`](#immutable-createdat)
* [Removed Validator `isAsync`](#removed-validator-isasync)
* [Removed `safe`](#removed-safe)
* [SchemaType `set` parameters now use `priorValue` as the second parameter instead of `self`](#schematype-set-parameters)
* [No default model for `Query.prototype.populate()`](#no-default-model-for-query-prototype-populate)
* [`toObject()` and `toJSON()` Use Nested Schema `minimize`](#toobject-and-tojson-use-nested-schema-minimize)
* [TypeScript changes](#typescript-changes)
* [Removed `reconnectTries` and `reconnectInterval` options](#removed-reconnecttries-and-reconnectinterval-options)

 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
------------------

 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. Below are some of the most noteworthy changes:

 * MongoDB Driver 4.x is written in TypeScript and has its own TypeScript type definitions. These may conflict with `@types/mongodb`, so if you have TypeScript compiler errors please make sure you upgrade to the [latest version of `@types/mongodb`](https://www.npmjs.com/package/@types/mongodb), which is an empty stub.
* The `poolSize` option for connections has been [replaced with `minPoolSize` and `maxPoolSize`](https://github.com/mongodb/node-mongodb-native/blob/4.1/docs/CHANGES_4.0.0.md#connection-pool-options). The Mongoose 5.x `poolSize` option is equivalent to the Mongoose 6 `maxPoolSize` option. The default value of `maxPoolSize` has been increased to 100.
* The result of `updateOne()` and `updateMany()` is now different.
* The result of `deleteOne()` and `deleteMany()` no longer has an `n` property.

 
```
const res = await TestModel.updateMany({}, { someProperty: 'someValue' });

res.matchedCount; // Number of documents that were found that match the filter. Replaces `res.n`
res.modifiedCount; // Number of documents modified. Replaces `res.nModified`
res.upsertedCount; // Number of documents upserted. Replaces `res.upserted`

```
 
```
const res = await TestModel.deleteMany({});

// In Mongoose 6: `{ acknowledged: true, deletedCount: 2 }`
// In Mongoose 5: `{ n: 2, ok: 1, deletedCount: 2 }`
res;

res.deletedCount; // Number of documents that were deleted. Replaces `res.n`

```
 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.

 
```
// No longer necessary:
mongoose.set('useFindAndModify', false);

await mongoose.connect('mongodb://127.0.0.1:27017/test', {
  useNewUrlParser: true, // <-- no longer necessary
  useUnifiedTopology: true // <-- no longer necessary
});

```
 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).

 
```
// The below no longer works in Mongoose 6
await mongoose.createConnection(uri);

// Do this instead
await mongoose.createConnection(uri).asPromise();

```
 
`mongoose.connect()` Returns a Promise
---------------------------------------

 The `mongoose.connect()` function now always returns a promise, **not** a Mongoose instance.

 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)

 
```
// Results in 'Query was already executed' error, because technically this `find()` query executes twice.
await Model.find({}, function(err, result) {});

const q = Model.find();
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
----------------------------------------------------------------

 
```
// in Mongoose 5.x, `existingUser` used to be a boolean
// now `existingUser` will be either `{ \_id: ObjectId(...) }` or `null`.
const existingUser = await User.exists({ name: 'John' });
if (existingUser) {
  console.log(existingUser.\_id);
}

```
 
`strictQuery` is now equal to `strict` by default
--------------------------------------------------

 ~~Mongoose no longer supports a `strictQuery` option. You must now use `strict`.~~ As of Mongoose 6.0.10, we brought back the `strictQuery` option. However, `strictQuery` is tied to `strict` by default. This means that, by default, Mongoose will filter out query filter properties that are not in the schema.

 
```
const userSchema = new Schema({ name: String });
const User = mongoose.model('User', userSchema);

// By default, this is equivalent to `User.find()` because Mongoose filters out `notInSchema`
await User.find({ notInSchema: 1 });

// Set `strictQuery: false` to opt in to filtering by properties that aren't in the schema
await User.find({ notInSchema: 1 }, null, { strictQuery: false });
// equivalent:
await User.find({ notInSchema: 1 }).setOptions({ strictQuery: false });

```
 You can also disable `strictQuery` globally to override:

 
```
mongoose.set('strictQuery', false);

```
 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
--------------------------------------

 Mongoose now clones discriminator schemas by default. This means you need to pass `{ clone: false }` to `discriminator()` if you're using recursive embedded discriminators.

 
```
// In Mongoose 6, these two are equivalent:
User.discriminator('author', authorSchema);
User.discriminator('author', authorSchema.clone());

// To opt out if `clone()` is causing issues, pass `clone: false`
User.discriminator('author', authorSchema, { clone: false });

```
 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.

 In Mongoose 6, `mongoose.isValidObjectId()` is just a wrapper for `mongoose.Types.ObjectId.isValid()` for consistency.

 Mongoose 6.2.5 now includes a `mongoose.isObjectIdOrHexString()` function, which does a better job of capturing the more common use case for `isValidObjectId()`: is the given value an `ObjectId` instance or a 24 character hex string representing an `ObjectId`?

 
```
// `isValidObjectId()` returns `true` for some surprising values, because these
// values are \_technically\_ ObjectId representations
mongoose.isValidObjectId(new mongoose.Types.ObjectId()); // true
mongoose.isValidObjectId('0123456789ab'); // true
mongoose.isValidObjectId(6); // true
mongoose.isValidObjectId(new User({ name: 'test' })); // true

// `isObjectIdOrHexString()` instead only returns `true` for ObjectIds and 24
// character hex strings.
mongoose.isObjectIdOrHexString(new mongoose.Types.ObjectId()); // true
mongoose.isObjectIdOrHexString('62261a65d66c6be0a63c051f'); // true
mongoose.isObjectIdOrHexString('0123456789ab'); // false
mongoose.isObjectIdOrHexString(6); // false

```
 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.

 
```
const schema = new Schema({
  profile: {
    name: {
      first: String,
      last: String
    }
  }
});
const Test = db.model('Test', schema);

const doc = new Test({
  profile: { name: { last: 'Musashi', first: 'Miyamoto' } }
});

// Note that 'first' comes before 'last', even though the argument to `new Test()` flips the key order.
// Mongoose uses the schema's key order, not the provided objects' key order.
assert.deepEqual(Object.keys(doc.toObject().profile.name), ['first', 'last']);

```
 
`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`:

 
```
// Mongoose will convert this filter into `{ username: 'val', pwd: { $eq: { $ne: null } } }`, preventing
// a query selector injection.
await Test.find({ username: 'val', pwd: { $ne: null } }).setOptions({ sanitizeFilter: true });

```
 To explicitly allow a query selector, use `mongoose.trusted()`:

 
```
// `mongoose.trusted()` allows query selectors through
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`
-----------------------------------------------------------------------------------------------------------

 In Mongoose 5.x, setting a key to `undefined` in an update operation was equivalent to setting it to `null`.

 
```
let res = await Test.findOneAndUpdate({}, { $set: { name: undefined } }, { new: true });

res.name; // `null` in Mongoose 5.x

// Equivalent to `findOneAndUpdate({}, {}, { new: true })` because `omitUndefined` will
// remove `name: undefined`
res = await Test.findOneAndUpdate({}, { $set: { name: undefined } }, { new: true, omitUndefined: true });

```
 Mongoose 5.x supported an `omitUndefined` option to strip out `undefined` keys. In Mongoose 6.x, the `omitUndefined` option has been removed, and Mongoose will always strip out undefined keys.

 
```
// In Mongoose 6, equivalent to `findOneAndUpdate({}, {}, { new: true })` because Mongoose will
// remove `name: undefined`
const res = await Test.findOneAndUpdate({}, { $set: { name: undefined } }, { new: true });

```
 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
---------------------------------------

 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.

 This may affect you if you pass a function that expects different parameters to `default`, like `default: mongoose.Types.ObjectId`. See [gh-9633](https://github.com/Automattic/mongoose/issues/9633). If you're passing a default function that does **not** utilize the document, change `default: myFunction` to `default: () => myFunction()` to avoid accidentally passing parameters that potentially change the behavior.

 
```
const schema = new Schema({
  name: String,
  age: Number,
  canVote: {
    type: Boolean,
    // Default functions now receive a `doc` parameter, helpful for arrow functions
    default: doc => doc.age >= 18
  }
});

```
 Arrays are Proxies
------------------

 Mongoose arrays are now ES6 proxies. You no longer need to `markModified()` after setting an array index directly.

 
```
const post = await BlogPost.findOne();

post.tags[0] = 'javascript';
await post.save(); // Works, no need for `markModified()`!

```
 `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).

 
```
// In Mongoose 6, the below makes `foo` into a subdocument with a `name` property.
// In Mongoose 5, the below would make `foo` a `Mixed` type, \_unless\_ you set `typePojoToMixed: true`.
const schema = new Schema({
  foo: { type: { name: String } }
});

```
 `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
----------------------------------

 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).

 
```
const schema = new Schema({
  works: [{
    modelId: String,
    data: {
      type: mongoose.ObjectId,
      ref: function(doc) {
        // In Mongoose 6, `doc` is the array element, so you can access `modelId`.
        // In Mongoose 5, `doc` was the top-level document.
        return doc.modelId;
      }
    }
  }]
});

```
 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
-----------------

 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
----------------------------

 `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` 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'`
--------------------------

 The `context` option for queries has been removed. Now Mongoose always uses `context = 'query'`.

 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
------------------------------------

 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()`
------------------------

 `Document#populate()` now returns a promise and is now no longer chainable.

 * Replace `await doc.populate('path1').populate('path2').execPopulate();` with `await doc.populate(['path1', 'path2']);`
* Replace `await doc.populate('path1', 'select1').populate('path2', 'select2').execPopulate();` with

 
```
await doc.populate([{path: 'path1', select: 'select1'}, {path: 'path2', select: 'select2'}]);

```

 
`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
---------------------------

 `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()`
--------------------

 Mongoose now adds a `valueOf()` function to ObjectIds. This means you can now use `==` to compare an ObjectId against a string.

 
```
const a = ObjectId('6143b55ac9a762738b15d4f0');

a == '6143b55ac9a762738b15d4f0'; // true

```
 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`
---------------------------

 `isAsync` is no longer an option for `validate`. Use an `async function` instead.

 Removed `safe`
--------------

 `safe` is no longer an option for schemas, queries, or `save()`. Use `writeConcern` instead.

 SchemaType `set` parameters
---------------------------

 Mongoose now calls setter functions with `priorValue` as the 2nd parameter, rather than `schemaType` in Mongoose 5.

 
```
const userSchema = new Schema({
  name: {
    type: String,
    trimStart: true,
    set: trimStartSetter
  }
});

// in v5.x the parameters were (value, schemaType), in v6.x the parameters are (value, priorValue, schemaType).
function trimStartSetter(val, priorValue, schemaType) {
  if (schemaType.options.trimStart && typeof val === 'string') {
    return val.trimStart();
  }
  return val;
}

const User = mongoose.model('User', userSchema);

const user = new User({ name: 'Robert Martin' });
console.log(user.name); // 'robert martin'

```
 
`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.

 
```
const child = new Schema({ thing: Schema.Types.Mixed });
const parent = new Schema({ child }, { minimize: false });
const Parent = model('Parent', parent);
const p = new Parent({ child: { thing: {} } });

// In v5.10.4, would contain `child.thing` because `toObject()` uses `parent` schema's `minimize` option
// In `>= 5.10.5`, `child.thing` is omitted because `child` schema has `minimize: true`
console.log(p.toObject());

```
 As a workaround, you can either explicitly pass `minimize` to `toObject()` or `toJSON()`:

 
```
console.log(p.toObject({ minimize: false }));

```
 Or define the `child` schema inline (Mongoose 6 only) to inherit the parent's `minimize` option.

 
```
const parent = new Schema({
  // Implicitly creates a new schema with the top-level schema's `minimize` option.
  child: { type: { thing: Schema.Types.Mixed } }
}, { minimize: false });

```
 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.

 
```
const testSchema = new mongoose.Schema({
  data: String,
  parents: Array // Array of mixed
});

const Test = mongoose.model('Test', testSchema);

// The below `populate()`...
await Test.findOne().populate('parents');
// Is a shorthand for the following populate in Mongoose 5
await Test.findOne().populate({ path: 'parents', model: Test });

```
 In Mongoose 6, populating a path with no `ref`, `refPath`, or `model` is a no-op.

 
```
// The below `populate()` does nothing.
await Test.findOne().populate('parents');

```
  TypeScript changes
-------------------

 The `Schema` class now takes 3 generic params instead of 4. The 3rd generic param, `SchemaDefinitionType`, is now the same as the 1st generic param `DocType`. Replace `new Schema<UserDocument, UserModel, User>(schemaDefinition)` with `new Schema<UserDocument, UserModel>(schemaDefinition)`

 `Types.ObjectId` is now a class, which means you can no longer omit `new` when creating a new ObjectId using `new mongoose.Types.ObjectId()`. Currently, you can still omit `new` in JavaScript, but you **must** put `new` in TypeScript.

 The following legacy types have been removed:

 * `ModelUpdateOptions`
* `DocumentQuery`
* `HookSyncCallback`
* `HookAsyncCallback`
* `HookErrorCallback`
* `HookNextFunction`
* `HookDoneFunction`
* `SchemaTypeOpts`
* `ConnectionOptions`

 Mongoose 6 infers the document's type for `this` in virtual getters and setters. In Mongoose 5.x, `this` would be `any` in the following code.

 
```
schema.virtual('myVirtual').get(function() {
  this; // any in Mongoose 5.x
});

```
 In Mongoose 6, `this` will be set to the document type.

 
```
const schema = new Schema({ name: String });

schema.virtual('myVirtual').get(function() {
  this.name; // string
});

```
 Removed `reconnectTries` and `reconnectInterval` options
--------------------------------------------------------

 The `reconnectTries` and `reconnectInterval` options have been removed since they are no longer necessary.

 The MongoDB node driver will always attempt to retry any operation for up to `serverSelectionTimeoutMS`, even if MongoDB is down for a long period of time. So, it will never run out of retries or try to reconnect to MongoDB.



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/migrating_to_6.html>

Version Support
================

 Mongoose 7.x (released February 27, 2023) is the current Mongoose major version. We ship all new bug fixes and features to 7.x.

  Mongoose 6
-----------

 Mongoose 6.x (released August 24, 2021) is currently in legacy support. We will continue to ship bug fixes to Mongoose 6 until August 24, 2023. After August 24, 2023, we will only ship security fixes, and backport requested fixes to Mongoose 6. Please open a [bug report on GitHub](https://github.com/Automattic/mongoose/issues/new?assignees=&labels=&template=bug.yml) to request backporting a fix to Mongoose 6.

 We are **not** actively backporting any new features from Mongoose 7 into Mongoose 6. Until August 24, 2023, we will backport requested features into Mongoose 6; please open a [feature request on GitHub](https://github.com/Automattic/mongoose/issues/new?assignees=&labels=enhancement%2Cnew+feature&template=feature.yml) to request backporting a feature into Mongoose 6. After August 24, 2023, we will not backport any new features into Mongoose 6.

 We do not currently have a formal end of life (EOL) date for Mongoose 6. However, we will not end support for Mongoose 6 until at least January 1, 2024.

  Mongoose 5
-----------

 Mongoose 5.x (released January 17, 2018) is currently only receiving security fixes and requested bug fixes. Please open a [bug report on GitHub](https://github.com/Automattic/mongoose/issues/new?assignees=&labels=&template=bug.yml) to request backporting a fix to Mongoose 5. We will **not** backport any new features from Mongoose 6 or Mongoose 7 into Mongoose 5.

 Mongoose 5.x end of life (EOL) is March 1, 2024. Mongoose 5.x will no longer receive any updates, security or otherwise, after that date.



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/version-support.html>

Migrating from 4.x to 5.x
==========================

 Please note: we plan to discontinue Mongoose 5 support on March 1, 2024. Please see our [version support guide](version-support).

 There are several [backwards-breaking changes](https://github.com/Automattic/mongoose/blob/master/History.md) you should be aware of when migrating from Mongoose 4.x to Mongoose 5.x.

 If you're still on Mongoose 3.x, please read the [Mongoose 3.x to 4.x migration guide](https://mongoosejs.com/docs/migration.html).

 * [Version Requirements](#version-requirements)
* [Query Middleware](#query-middleware)
* [Promises and Callbacks for `mongoose.connect()`](#promises-and-callbacks)
* [Connection Logic and `useMongoClient`](#connection-logic)
* [Setter Order](#setter-order)
* [Checking if a path is populated](#id-getter)
* [Return Values for `remove()` and `deleteX()`](#return-value-for-delete)
* [Aggregation Cursors](#aggregation-cursors)
* [geoNear](#geonear)
* [Required URI encoding of connection strings](#uri-encoding)
* [Passwords which contain certain characters](#password-characters)
* [Domain sockets](#domain-sockets)
* [`toObject()` Options](#toobject-options)
* [Aggregate Parameters](#aggregate-parameters)
* [Boolean Casting](#boolean-casting)
* [Query Casting](#query-casting)
* [Post Save Hooks Get Flow Control](#post-save-flow-control)
* [The `$pushAll` Operator](#pushall)
* [Always Use Forward Key Order](#retain-key-order)
* [Run setters on queries](#run-setters-on-queries)
* [Pre-compiled Browser Bundle](#browser-bundle)
* [Save Errors](#save-errors)
* [Init hook signatures](#init-hooks)
* [`numAffected` and `save()`](#save-num-affected)
* [`remove()` and debouncing](#remove-debounce)
* [`getPromiseConstructor()`](#get-promise-constructor)
* [Passing Parameters from Pre Hooks](#pre-hook-params)
* [`required` validator for arrays](#array-required)
* [debug output defaults to stdout instead of stderr](#debug-output)
* [Overwriting filter properties](#overwrite-filter)
* [`bulkWrite()` results](#bulkwrite-results)
* [Strict SSL validation](#strict-ssl-validation)

 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 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.

 
```
const schema = new Schema({ name: String });
const MyModel = mongoose.model('Test', schema);
schema.pre('find', () => { console.log('find!'); });

MyModel.find().exec(function() {
  // In mongoose 4.x, the above `.find()` will print "find!"
  // In mongoose 5.x, "find!" will \*\*not\*\* be printed.
  // Call `pre('find')` \*\*before\*\* calling `mongoose.model()` to make the middleware apply.
});

```
  Promises and Callbacks for `mongoose.connect()`
------------------------------------------------

 `mongoose.connect()` and `mongoose.disconnect()` now return a promise if no callback specified, or `null` otherwise. It does **not** return the mongoose singleton.

 
```
// Worked in mongoose 4. Does \*\*not\*\* work in mongoose 5, `mongoose.connect()`
// now returns a promise consistently. This is to avoid the horrible things
// we've done to allow mongoose to be a thenable that resolves to itself.
mongoose.connect('mongodb://127.0.0.1:27017/test').model('Test', new Schema({}));

// Do this instead
mongoose.connect('mongodb://127.0.0.1:27017/test');
mongoose.model('Test', new Schema({}));

```
  Connection Logic and `useMongoClient`
--------------------------------------

 The [`useMongoClient` option](4.x/docs/connections#use-mongo-client) was removed in Mongoose 5, it is now always `true`. As a consequence, Mongoose 5 no longer supports several function signatures for `mongoose.connect()` that worked in Mongoose 4.x if the `useMongoClient` option was off. Below are some examples of `mongoose.connect()` calls that do **not** work in Mongoose 5.x.

 * `mongoose.connect('127.0.0.1', 27017);`
* `mongoose.connect('127.0.0.1', 'mydb', 27017);`
* `mongoose.connect('mongodb://host1:27017,mongodb://host2:27017');`

 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
-------------

 Setters run in reverse order in 4.x:

 
```
const schema = new Schema({ name: String });
schema.path('name').
  set(() => console.log('This will print 2nd')).
  set(() => console.log('This will print first'));

```
 In 5.x, setters run in the order they're declared.

 
```
const schema = new Schema({ name: String });
schema.path('name').
  set(() => console.log('This will print first')).
  set(() => console.log('This will print 2nd'));

```
  Checking if a path is populated
--------------------------------

 Mongoose 5.1.0 introduced an `_id` getter to ObjectIds that lets you get an ObjectId regardless of whether a path is populated.

 
```
const blogPostSchema = new Schema({
  title: String,
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Author'
  }
});
const BlogPost = mongoose.model('BlogPost', blogPostSchema);

await BlogPost.create({ title: 'test', author: author.\_id });
const blogPost = await BlogPost.findOne();

console.log(blogPost.author); // '5b207f84e8061d1d2711b421'
// New in Mongoose 5.1.0: this will print '5b207f84e8061d1d2711b421' as well
console.log(blogPost.author.\_id);

await blogPost.populate('author');
console.log(blogPost.author.\_id); // '5b207f84e8061d1d2711b421'

```
 As a consequence, checking whether `blogPost.author._id` is [no longer viable as a way to check whether `author` is populated](https://github.com/Automattic/mongoose/issues/6415#issuecomment-388579185). Use `blogPost.populated('author') != null` or `blogPost.author instanceof mongoose.Types.ObjectId` to check whether `author` is populated instead.

 Note that you can call `mongoose.set('objectIdGetter', false)` to change this behavior.

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

 `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).

 
```
// In 4.x, this is how you got the number of documents deleted
MyModel.deleteMany().then(res => console.log(res.result.n));
// In 5.x this is how you get the number of documents deleted
MyModel.deleteMany().then(res => res.n);

```
  Aggregation Cursors
--------------------

 The `useMongooseAggCursor` option from 4.x is now always on. This is the new syntax for aggregation cursors in mongoose 5:

 
```
// When you call `.cursor()`, `.exec()` will now return a mongoose aggregation
// cursor.
const cursor = MyModel.aggregate([{ $match: { name: 'Val' } }]).cursor().exec();
// No need to `await` on the cursor or wait for a promise to resolve
cursor.eachAsync(doc => console.log(doc));

// Can also pass options to `cursor()`
const cursorWithOptions = MyModel.
  aggregate([{ $match: { name: 'Val' } }]).
  cursor({ batchSize: 10 }).
  exec();

```
  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
--------------------------------------------

 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
-------------------------------------------

 See a [full list of affected characters](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding).

 If your app is used by a lot of different connection strings, it's possible that your test cases will pass, but production passwords will fail. Encode all your connection strings to be safe.

 If you want to continue to use unencoded connection strings, the easiest fix is to use the `mongodb-uri` module to parse the connection strings, and then produce the properly encoded versions. You can use a function like this:

 
```
const uriFormat = require('mongodb-uri');
function encodeMongoURI(urlString) {
  if (urlString) {
    const parsed = uriFormat.parse(urlString);
    urlString = uriFormat.format(parsed);
  }
  return urlString;
}

// Your un-encoded string.
const mongodbConnectString = 'mongodb://...';
mongoose.connect(encodeMongoURI(mongodbConnectString));

```
 The function above is safe to use whether the existing string is already encoded or not.

  Domain sockets
---------------

 Domain sockets must be URI encoded. For example:

 
```
// Works in mongoose 4. Does \*\*not\*\* work in mongoose 5 because of more
// stringent URI parsing.
const host = '/tmp/mongodb-27017.sock';
mongoose.createConnection(`mongodb://aaron:psw@${host}/fake`);

// Do this instead
const host = encodeURIComponent('/tmp/mongodb-27017.sock');
mongoose.createConnection(`mongodb://aaron:psw@${host}/fake`);

```
  `toObject()` Options
---------------------

 The `options` parameter to `toObject()` and `toJSON()` merge defaults rather than overwriting them.

 
```
// Note the `toObject` option below
const schema = new Schema({ name: String }, { toObject: { virtuals: true } });
schema.virtual('answer').get(() => 42);
const MyModel = db.model('MyModel', schema);

const doc = new MyModel({ name: 'test' });
// In mongoose 4.x this prints "undefined", because `{ minimize: false }`
// overwrites the entire schema-defined options object.
// In mongoose 5.x this prints "42", because `{ minimize: false }` gets
// merged with the schema-defined options.
console.log(doc.toJSON({ minimize: false }).answer);

```
  Aggregate Parameters
---------------------

 `aggregate()` no longer accepts a spread, you **must** pass your aggregation pipeline as an array. The below code worked in 4.x:

 
```
MyModel.aggregate({ $match: { isDeleted: false } }, { $skip: 10 }).exec(cb);

```
 The above code does **not** work in 5.x, you **must** wrap the `$match` and `$skip` stages in an array.

 
```
MyModel.aggregate([{ $match: { isDeleted: false } }, { $skip: 10 }]).exec(cb);

```
  Boolean Casting
----------------

 By default, mongoose 4 would coerce any value to a boolean without error.

 
```
// Fine in mongoose 4, would save a doc with `boolField = true`
const MyModel = mongoose.model('Test', new Schema({
  boolField: Boolean
}));

MyModel.create({ boolField: 'not a boolean' });

```
 Mongoose 5 only casts the following values to `true`:

 * `true`
* `'true'`
* `1`
* `'1'`
* `'yes'`

 And the following values to `false`:

 * `false`
* `'false'`
* `0`
* `'0'`
* `'no'`

 All other values will cause a `CastError`

  Query Casting
--------------

 Casting for `update()`, `updateOne()`, `updateMany()`, `replaceOne()`, `remove()`, `deleteOne()`, and `deleteMany()` doesn't happen until `exec()`. This makes it easier for hooks and custom query helpers to modify data, because mongoose won't restructure the data you passed in until after your hooks and query helpers have ran. It also makes it possible to set the `overwrite` option *after* passing in an update.

 
```
// In mongoose 4.x, this becomes `{ $set: { name: 'Baz' } }` despite the `overwrite`
// In mongoose 5.x, this overwrite is respected and the first document with
// `name = 'Bar'` will be replaced with `{ name: 'Baz' }`
User.where({ name: 'Bar' }).update({ name: 'Baz' }).setOptions({ overwrite: true });

```
  Post Save Hooks Get 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.

 
```
const ChildModelSchema = new mongoose.Schema({
  text: {
    type: String
  }
});
ChildModelSchema.post('save', function(doc) {
  // In mongoose 5.x this will print \*\*before\*\* the `console.log()`
  // in the `save()` callback. In mongoose 4.x this was reversed.
  console.log('Child post save');
});
const ParentModelSchema = new mongoose.Schema({
  children: [ChildModelSchema]
});

const Model = mongoose.model('Parent', ParentModelSchema);
const m = new Model({ children: [{ text: 'test' }] });
m.save(function() {
  // In mongoose 5.xm this prints \*\*after\*\* the "Child post save" message.
  console.log('Save callback');
});

```
  The `$pushAll` Operator
------------------------

 `$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
-----------------------------

 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
-----------------------

 Setters now run on queries by default, and the old `runSettersOnQuery` option has been removed.

 
```
const schema = new Schema({
  email: { type: String, lowercase: true }
});
const Model = mongoose.model('Test', schema);
Model.find({ email: 'FOO@BAR.BAZ' }); // Converted to `find({ email: 'foo@bar.baz' })`

```
  Pre-compiled 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
------------

 The `saveErrorIfNotFound` option was removed, mongoose will now always error out from `save()` if the underlying document was not found

  Init hook signatures
---------------------

 `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()`
---------------------------

 `doc.save()` no longer passes `numAffected` as a 3rd param to its callback.

  `remove()` and debouncing
--------------------------

 `doc.remove()` no longer debounces

  `getPromiseConstructor()`
--------------------------

 `getPromiseConstructor()` is gone, just use `mongoose.Promise`.

  Passing Parameters from Pre Hooks
----------------------------------

 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
--------------------------------

 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
--------------------------------------------------

 In mongoose 5 the default debug function uses `console.info()` to display messages instead of `console.error()`.

  Overwriting filter properties
------------------------------

 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' })`

 
```
Sport.find({ name: 'baseball' }).where({ name: { $ne: 'softball' } });

```
 In Mongoose 5.x, the above code will correctly overwrite `'baseball'` with `{ $ne: 'softball' }`

  `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#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).

 
```
const Model = mongoose.model('Test', new Schema({ name: String }));

const res = await Model.bulkWrite([{ insertOne: { document: { name: 'test' } } }]);

console.log(res);

```
 In Mongoose 4.x, the above will print:

 
```
BulkWriteResult {
  ok: [Getter],
  nInserted: [Getter],
  nUpserted: [Getter],
  nMatched: [Getter],
  nModified: [Getter],
  nRemoved: [Getter],
  getInsertedIds: [Function],
  getUpsertedIds: [Function],
  getUpsertedIdAt: [Function],
  getRawResponse: [Function],
  hasWriteErrors: [Function],
  getWriteErrorCount: [Function],
  getWriteErrorAt: [Function],
  getWriteErrors: [Function],
  getLastOp: [Function],
  getWriteConcernError: [Function],
  toJSON: [Function],
  toString: [Function],
  isOk: [Function],
  insertedCount: 1,
  matchedCount: 0,
  modifiedCount: 0,
  deletedCount: 0,
  upsertedCount: 0,
  upsertedIds: {},
  insertedIds: { '0': 5be9a3101638a066702a0d38 },
  n: 1 }

```
 In Mongoose 5.x, the script will print:

 
```
BulkWriteResult {
  result: 
  { ok: 1,
    writeErrors: [],
    writeConcernErrors: [],
    insertedIds: [ [Object] ],
    nInserted: 1,
    nUpserted: 0,
    nMatched: 0,
    nModified: 0,
    nRemoved: 0,
    upserted: [],
    lastOp: { ts: [Object], t: 1 } },
  insertedCount: 1,
  matchedCount: 0,
  modifiedCount: 0,
  deletedCount: 0,
  upsertedCount: 0,
  upsertedIds: {},
  insertedIds: { '0': 5be9a1c87decfc6443dd9f18 },
  n: 1 }

```
  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).

 If this is blocking you from upgrading, you can set the `tlsInsecure` option to `true`.

 
```
mongoose.connect(uri, { tlsInsecure: false }); // Opt out of additional SSL validation

```


 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/migrating_to_5.html>

Connections
===========


You can connect to MongoDB with the `mongoose.connect()` method.



```
mongoose.connect('mongodb://localhost/myapp');

```

This is the minimum needed to connect the `myapp` database running locally on the default port (27017). If the local connection fails then try using 127.0.0.1 instead of localhost. Sometimes issues may arise when the local hostname has been changed.

 You can also specify several more parameters in the `uri`:



```
mongoose.connect('mongodb://username:password@host:port/database?options...');

```

See the [mongodb connection string spec](http://docs.mongodb.org/manual/reference/connection-string/) for more detail.


Operation Buffering
-------------------


Mongoose lets you start using your models immediately, without waiting for mongoose to establish a connection to MongoDB.



```
mongoose.connect('mongodb://localhost/myapp');
var MyModel = mongoose.model('Test', new Schema({ name: String }));
// Works
MyModel.findOne(function(error, result) { /\* ... \*/ });

```

That's because mongoose buffers model function calls internally. This buffering is convenient, but also a common source of confusion. Mongoose will *not* throw any errors by default if you use a model without connecting.



```
var MyModel = mongoose.model('Test', new Schema({ name: String }));
// Will just hang until mongoose successfully connects
MyModel.findOne(function(error, result) { /\* ... \*/ });

setTimeout(function() {
  mongoose.connect('mongodb://localhost/myapp');
}, 60000);

```

To disable buffering, turn off the [`bufferCommands` option on your schema](guide#bufferCommands). If you have `bufferCommands` on and your connection is hanging, try turning `bufferCommands` off to see if you haven't opened a connection properly.


Options
-------


The `connect` method also accepts an `options` object which will be passed on to the underlying MongoDB driver.



```
mongoose.connect(uri, options);

```

A full list of options can be found on the [MongoDB Node.js driver docs for `connect()`](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html#connect). Mongoose passes options to the driver without modification, modulo three exceptions that are explained below.

 * `useMongoClient` - This is a mongoose-specific option (not passed to the MongoDB driver) that opts in to mongoose 4.11's new connection logic. If you are writing a new application, you **should** set this to `true`.
* `user`/`pass` - The username and password for authentication. These options are mongoose-specific, they are equivalent to the MongoDB driver's `auth.user` and `auth.password` options.
* `autoIndex` - By default, mongoose will automatically build indexes defined in your schema when it connects. This is great for development, but not ideal for large production deployments, because index builds can cause performance degradation. If you set `autoIndex` to false, mongoose will not automatically build indexes for **any** model associated with this connection.

 Below are some of the options that are important for tuning mongoose.

 * `autoReconnect` - The underlying MongoDB driver will automatically try to reconnect when it loses connection to MongoDB. Unless you are an extremely advanced user that wants to manage their own connection pool, do **not** set this option to `false`.
* `reconnectTries` - If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every `reconnectInterval` milliseconds for `reconnectTries` times, and give up afterward. When the driver gives up, the mongoose connection emits a `reconnectFailed` event. This option does nothing for replica set connections.
* `reconnectInterval` - See `reconnectTries`
* `promiseLibrary` - sets the [underlying driver's promise library](http://mongodb.github.io/node-mongodb-native/2.1/api/MongoClient.html)
* `poolSize` - The maximum number of sockets the MongoDB driver will keep open for this connection. By default, `poolSize` is 5. Keep in mind that, as of MongoDB 3.4, MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding.
* `bufferMaxEntries` - The MongoDB driver also has its own buffering mechanism that kicks in when the driver is disconnected. Set this option to 0 and set `bufferCommands` to `false` on your schemas if you want your database operations to fail immediately when the driver is not connected, as opposed to waiting for reconnection.

 Example:



```
var options = {
  useMongoClient: true,
  autoIndex: false, // Don't build indexes
  reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect
  reconnectInterval: 500, // Reconnect every 500ms
  poolSize: 10, // Maintain up to 10 socket connections
  // If not connected, return errors immediately rather than waiting for reconnect
  bufferMaxEntries: 0
};
mongoose.connect(uri, options);

```

Callback
--------


The `connect()` function also accepts a callback parameter and returns a [promise](promises).



```
mongoose.connect(uri, options, function(error) {
  // Check error in initial connection. There is no 2nd param to the callback.
});

// Or using promises
mongoose.connect(uri, options).then(
  () => { /\*\* ready to use. The `mongoose.connect()` promise resolves to undefined. \*/ },
  err => { /\*\* handle initial connection error \*/ }
);

```

#### Connection String Options


You can also specify options in your connection string as [parameters in the query string](https://en.wikipedia.org/wiki/Query_string) portion of the URI.



```
mongoose.connect('mongodb://localhost:27017/test?connectTimeoutMS=1000', { useMongoClient: true });
// The above is equivalent to:
mongoose.connect('mongodb://localhost:27017/test', {
  useMongoClient: true,
  connectTimeoutMS: 1000
});
```

The disadvantage of putting options in the query string is that query string options are harder to read. The advantage is that you only need a single configuration option, the URI, rather than separate options for `socketTimeoutMS`, `connectTimeoutMS`, etc. Best practice is to put options that likely differ between development and production, like `replicaSet` or `ssl`, in the connection string, and options that should remain constant, like `connectTimeoutMS` or `poolSize`, in the options object.

 The MongoDB docs have a full list of [supported connection string options](https://docs.mongodb.com/manual/reference/connection-string/)


#### A note about keepAlive


For long running applications, it is often prudent to enable `keepAlive` with a number of milliseconds. Without it, after some period of time you may start to see `"connection closed"` errors for what seems like no reason. If so, after [reading this](http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html), you may decide to enable `keepAlive`:



```
options.server.socketOptions = options.replset.socketOptions = { keepAlive: 120 };
mongoose.connect(uri, options);

```

Replica Set Connections
-----------------------


To connect to a replica set you pass a comma delimited list of hosts to connect to rather than a single host.



```
mongoose.connect('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]' [, options]);

```

To connect to a single node replica set, specify the `replicaSet` option.



```
mongoose.connect('mongodb://host1:port1/?replicaSet=rsName');

```

Multi-mongos support
--------------------


High availability over multiple `mongos` instances is also supported. Pass a connection string for your `mongos` instances. If you are not using the `useMongoClient` option, you must also set the `mongos` option:



```
mongoose.connect('mongodb://mongosA:27501,mongosB:27501', { mongos: true }, cb);
```

With `useMongoClient`, you do not need to set the `mongos` option. You also do **not** need to use `mongos` or `useMongoClient` in mongoose 5.x.



```
mongoose.connect('mongodb://mongosA:27501,mongosB:27501', { useMongoClient: true }, cb);

```

Multiple connections
--------------------


So far we've seen how to connect to MongoDB using Mongoose's default connection. At times we may need multiple connections open to Mongo, each with different read/write settings, or maybe just to different databases for example. In these cases we can utilize `mongoose.createConnection()` which accepts all the arguments already discussed and returns a fresh connection for you.



```
var conn = mongoose.createConnection('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]', options);

```

This [connection](api#connection_Connection) object is then used to create and retrieve [models](api#model_Model). Models are **always** scoped to a single connection.


Connection pools
----------------


Each `connection`, whether created with `mongoose.connect` or `mongoose.createConnection` are all backed by an internal configurable connection pool defaulting to a maximum size of 5. Adjust the pool size using your connection options:



```
// single server
var uri = 'mongodb://localhost/test';
mongoose.createConnection(uri, { server: { poolSize: 4 }});

// for a replica set
mongoose.createConnection(uri, { replset: { poolSize: 4 }});

// passing the option in the URI works with single or replica sets
var uri = 'mongodb://localhost/test?poolSize=4';
mongoose.createConnection(uri);

```

The `useMongoClient` Option
---------------------------


Mongoose's default connection logic is deprecated as of 4.11.0. Please opt in to the new connection logic using the `useMongoClient` option, but make sure you test your connections first if you're upgrading an existing codebase!



```
// Using `mongoose.connect`...
var promise = mongoose.connect('mongodb://localhost/myapp', {
  useMongoClient: true,
  /\* other options \*/
});
// Or `createConnection`
var promise = mongoose.createConnection('mongodb://localhost/myapp', {
  useMongoClient: true,
  /\* other options \*/
});
promise.then(function(db) {
  /\* Use `db`, for instance `db.model()`
});
// Or, if you already have a connection
connection.openUri('mongodb://localhost/myapp', { /\* options \*/ });
```

The parameters to `openUri()` are passed transparently to the [underlying MongoDB driver's `MongoClient.connect()` function](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html#connect). Please see the [driver documentation for this function](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html#connect) for options. The same is true for `connect()` and `createConnection()` if `useMongoClient` is `true`.


You may see the following deprecation warning with `useMongoClient`:

 `the server/replset/mongos options are deprecated, all their options are supported at the top level of the options object`

 In older version of the MongoDB driver you had to specify distinct options for server connections, replica set connections, and mongos connections:



```
mongoose.connect(myUri, {
  server: {
    socketOptions: {
      socketTimeoutMS: 0,
      keepAlive: true
    },
    reconnectTries: 30
  },
  replset: {
    socketOptions: {
      socketTimeoutMS: 0,
      keepAlive: true
    },
    reconnectTries: 30
  },
  mongos: {
    socketOptions: {
      socketTimeoutMS: 0,
      keepAlive: true
    },
    reconnectTries: 30
  }
});
```

With `useMongoClient` you can instead declare these options at the top level, without all that extra nesting. [Here's the list of all supported options](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html).



```
// Equivalent to the above code
mongoose.connect(myUri, {
  socketTimeoutMS: 0,
  keepAlive: true,
  reconnectTries: 30
});

```

This deprecation is because the [MongoDB driver](https://www.npmjs.com/package/mongodb) has deprecated an API that is critical to mongoose's connection logic to support MongoDB 3.6, see [this github issue](https://github.com/Automattic/mongoose/issues/5304) and [this blog post](http://thecodebarbarian.com/mongoose-4.11-use-mongo-client.html) for more details.


Next Up
-------


Now that we've covered `connections`, let's take a look at how we can break pieces of our functionality out into reusable and shareable [plugins](../../plugins).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/connections.html>

Schemas
=======


If you haven't yet done so, please take a minute to read the [quickstart](index) to get an idea of how Mongoose works. If you are migrating from 3.x to 4.x please take a moment to read the [migration guide](migration).


Defining your schema
--------------------


Everything in Mongoose starts with a Schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection.



```
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var blogSchema = new Schema({
  title:  String,
  author: String,
  body:   String,
  comments: [{ body: String, date: Date }],
  date: { type: Date, default: Date.now },
  hidden: Boolean,
  meta: {
    votes: Number,
    favs:  Number
  }
});
```

*If you want to add additional keys later, use the[Schema#add](api#schema_Schema-add) method.*


Each key in our`blogSchema` defines a property in our documents which will be cast to its associated[SchemaType](api#schematype_SchemaType). For example, we've defined a`title` which will be cast to the[String](api#schema-string-js) SchemaType and`date` which will be cast to a`Date` SchemaType. Keys may also be assigned nested objects containing further key/type definitions*(e.g. the `meta` property above).*


The permitted SchemaTypes are


* String
* Number
* Date
* Buffer
* Boolean
* Mixed
* ObjectId
* Array

Read more about them[here](schematypes).Schemas not only define the structure of your document and casting of properties, they also define document[instance methods](#methods), static[Model methods](#statics),[compound indexes](#indexes) and document lifecycle hooks called<middleware>.


Creating a model
----------------


To use our schema definition, we need to convert our `blogSchema` into a [Model](models) we can work with. To do so, we pass it into `mongoose.model(modelName, schema)`:



```
var Blog = mongoose.model('Blog', blogSchema);
// ready to go!

```

Instance methods
----------------


Instances of `Models` are <documents>. Documents have many of their own [built-in instance methods](api#document-js). We may also define our own custom document instance methods too.



```
// define a schema
var animalSchema = new Schema({ name: String, type: String });

// assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function(cb) {
  return this.model('Animal').find({ type: this.type }, cb);
};
```

Now all of our`animal` instances have a`findSimilarTypes` method available to it.



```
var Animal = mongoose.model('Animal', animalSchema);
var dog = new Animal({ type: 'dog' });

dog.findSimilarTypes(function(err, dogs) {
  console.log(dogs); // woof
});

```

Overwriting a default mongoose document method may lead to unpredictable results. See [this](api#schema_Schema.reserved) for more details.


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
-------


Adding static methods to a `Model` is simple as well. Continuing with our `animalSchema`:



```
// assign a function to the "statics" object of our animalSchema
animalSchema.statics.findByName = function(name, cb) {
  return this.find({ name: new RegExp(name, 'i') }, cb);
};

var Animal = mongoose.model('Animal', animalSchema);
Animal.findByName('fido', function(err, animals) {
  console.log(animals);
});

```

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
-------------


You can also add query helper functions, which are like instance methods but for mongoose queries. Query helper methods let you extend mongoose's [chainable query builder API](queries).



```
animalSchema.query.byName = function(name) {
  return this.find({ name: new RegExp(name, 'i') });
};

var Animal = mongoose.model('Animal', animalSchema);
Animal.find().byName('fido').exec(function(err, animals) {
  console.log(animals);
});

```

Indexes
-------


MongoDB supports [secondary indexes](http://docs.mongodb.org/manual/indexes/). With mongoose, we define these indexes within our `Schema` [at](api#schematype_SchemaType-index) [the](api#schematype_SchemaType-unique) [path](api#schematype_SchemaType-sparse) [level](api#schema_date_SchemaDate-expires) or the `schema` level. Defining indexes at the schema level is necessary when creating [compound indexes](http://www.mongodb.org/display/DOCS/Indexes#Indexes-CompoundKeys).



```
var animalSchema = new Schema({
  name: String,
  type: String,
  tags: { type: [String], index: true } // field level
});

animalSchema.index({ name: 1, type: -1 }); // schema level

```

When your application starts up, Mongoose automatically calls [`createIndex`](https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/#db.collection.createIndex) for each defined index in your schema. Mongoose will call `createIndex` for each index sequentially, and emit an 'index' event on the model when all the `createIndex` calls succeeded or when there was an error. While nice for development, it is recommended this behavior be disabled in production since index creation can cause a [significant performance impact](http://docs.mongodb.org/manual/core/indexes/#index-creation-operations). Disable the behavior by setting the `autoIndex` option of your schema to `false`, or globally on the connection by setting the option `autoIndex` to `false`.



```
mongoose.connect('mongodb://user:pass@localhost:port/database', { autoIndex: false });
// or
mongoose.createConnection('mongodb://user:pass@localhost:port/database', { autoIndex: false });
// or
animalSchema.set('autoIndex', false);
// or
new Schema({..}, { autoIndex: false });

```

Mongoose will emit an `index` event on the model when indexes are done building or an error occurred.



```
// Will cause an error because mongodb has an \_id index by default that
// is not sparse
animalSchema.index({ _id: 1 }, { sparse: true });
var Animal = mongoose.model('Animal', animalSchema);

Animal.on('index', function(error) {
  // "\_id index cannot be sparse"
  console.log(error.message);
});

```

See also the [Model#ensureIndexes](api#model_Model.ensureIndexes) method.


Virtuals
--------


[Virtuals](api#schema_Schema-virtual) are document properties that you can get and set but that do not get persisted to MongoDB. The getters are useful for formatting or combining fields, while setters are useful for de-composing a single value into multiple values for storage.



```
// define a schema
var personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
});

// compile our model
var Person = mongoose.model('Person', personSchema);

// create a document
var axl = new Person({
  name: { first: 'Axl', last: 'Rose' }
});

```

Suppose you want to print out the person's full name. You could do it yourself:



```
console.log(axl.name.first + ' ' + axl.name.last); // Axl Rose

```

But concatenating the first and last name every time can get cumbersome. And what if you want to do some extra processing on the name, like [removing diacritics?](https://www.npmjs.com/package/diacritics). A [virtual property getter](api#virtualtype_VirtualType-get) lets you define a `fullName` property that won't get persisted to MongoDB.



```
personSchema.virtual('fullName').get(function () {
  return this.name.first + ' ' + this.name.last;
});

```

Now, mongoose will call your getter function every time you access the `fullName` property:



```
console.log(axl.fullName); // Axl Rose

```

If you use `toJSON()` or `toObject()` (or use `JSON.stringify()` on a mongoose document) mongoose will *not* include virtuals by default. Pass `{ virtuals: true }` to either [toObject()](api#document_Document-toObject) or `toJSON()`.

 You can also add a custom setter to your virtual that will let you set both first name and last name via the `fullName` virtual.



```
personSchema.virtual('fullName').
  get(function() { return this.name.first + ' ' + this.name.last; }).
  set(function(v) {
    this.name.first = v.substr(0, v.indexOf(' '));
    this.name.last = v.substr(v.indexOf(' ') + 1);
  });
  
axl.fullName = 'William Rose'; // Now `axl.name.first` is "William"

```

Virtual property setters are applied before other validation. So the example above would still work even if the `first` and `last` name fields were required.

 Only non-virtual properties work as part of queries and for field selection. Since virtuals are not stored in MongoDB, you can't query with them.


##### 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 bandwidth, so you can convert a short property name stored in the database into a longer name for code readability.



```
var personSchema = new Schema({
  n: {
    type: String,
    // Now accessing `name` will get you the value of `n`, and setting `n` will set the value of `name`
    alias: 'name'
  }
});

// Setting `name` will propagate to `n`
var person = new Person({ name: 'Val' });
console.log(person); // { n: 'Val' }
console.log(person.toObject({ virtuals: true })); // { n: 'Val', name: 'Val' }
console.log(person.name); // "Val"

person.name = 'Not Val';
console.log(person); // { n: 'Not Val' }

```

Options
-------


`Schema`s have a few configurable options which can be passed to the constructor or `set` directly:



```
new Schema({..}, options);

// or

var schema = new Schema({..});
schema.set(option, value);

```

Valid options:

 * [autoIndex](#autoIndex)
* [bufferCommands](#bufferCommands)
* [capped](#capped)
* [collection](#collection)
* [emitIndexErrors](#emitIndexErrors)
* [id](#id)
* [*id](#*id)
* [minimize](#minimize)
* [read](#read)
* [safe](#safe)
* [shardKey](#shardKey)
* [strict](#strict)
* [toJSON](#toJSON)
* [toObject](#toObject)
* [typeKey](#typeKey)
* [validateBeforeSave](#validateBeforeSave)
* [versionKey](#versionKey)
* [collation](#collation)
* [skipVersioning](#skipVersioning)
* [timestamps](#timestamps)
* [retainKeyOrder](#retainKeyOrder)


#### option: autoIndex


At application startup, Mongoose sends a [`createIndex` command](https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/#db.collection.createIndex) for each index declared in your `Schema`. As of Mongoose v3, indexes are created in the `background` by default. If you wish to disable the auto-creation feature and manually handle when indexes are created, set your `Schema`s `autoIndex` option to `false` and use the [ensureIndexes](api#model_Model.ensureIndexes) method on your model.



```
var schema = new Schema({..}, { autoIndex: false });
var Clock = mongoose.model('Clock', schema);
Clock.ensureIndexes(callback);

```

#### option: bufferCommands


By default, mongoose buffers commands when the connection goes down until the driver manages to reconnect. To disable buffering, set `bufferCommands` to false.



```
var schema = new Schema({..}, { bufferCommands: false });

```

#### option: capped


Mongoose supports MongoDBs [capped](http://www.mongodb.org/display/DOCS/Capped+Collections) collections. To specify the underlying MongoDB collection be `capped`, set the `capped` option to the maximum size of the collection in [bytes](http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-size.).



```
new Schema({..}, { capped: 1024 });
```

The `capped` option may also be set to an object if you want to pass additional options like [max](http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-max) or [autoIndexId](http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-autoIndexId). In this case you must explicitly pass the `size` option which is required.



```
new Schema({..}, { capped: { size: 1024, max: 1000, autoIndexId: true } });

```

#### option: collection


Mongoose by default produces a collection name by passing the model name to the [utils.toCollectionName](api#utils_exports.toCollectionName) method. This method pluralizes the name. Set this option if you need a different name for your collection.



```
var dataSchema = new Schema({..}, { collection: 'data' });

```

#### option: emitIndexErrors


By default, mongoose will build any indexes you specify in your schema for you, and emit an 'index' event on the model when the index build either succeeds or errors out.



```
MyModel.on('index', function(error) {
  /\* If error is truthy, index build failed \*/
});
```

However, this makes it tricky to catch when your index build fails. The `emitIndexErrors` option makes seeing when your index build fails simpler. If this option is on, mongoose will additionally emit an 'error' event on the model when an index build fails.



```
MyModel.schema.options.emitIndexErrors; // true
MyModel.on('error', function(error) {
  // gets an error whenever index build fails
});
```

Node.js' built-in [event emitter throws an exception if an error event is emitted and there are no listeners](https://nodejs.org/api/events.html#events_class_events_eventemitter), so its easy to configure your application to fail fast when an index build fails.


#### option: id


Mongoose assigns each of your schemas an `id` virtual getter by default which returns the documents `_id` field cast to a string, or in the case of ObjectIds, its hexString. If you don't want an `id` getter added to your schema, you may disable it passing this option at schema construction time.



```
// default behavior
var schema = new Schema({ name: String });
var Page = mongoose.model('Page', schema);
var p = new Page({ name: 'mongodb.org' });
console.log(p.id); // '50341373e894ad16347efe01'

// disabled id
var schema = new Schema({ name: String }, { id: false });
var Page = mongoose.model('Page', schema);
var p = new Page({ name: 'mongodb.org' });
console.log(p.id); // undefined

```

#### option: \_id


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

 You can **only** use this option on sub-documents. Mongoose can't save a document without knowing its id, so you will get an error if you try to save a document without an `_id`.



```
// default behavior
var schema = new Schema({ name: String });
var Page = mongoose.model('Page', schema);
var p = new Page({ name: 'mongodb.org' });
console.log(p); // { \_id: '50341373e894ad16347efe01', name: 'mongodb.org' }

// disabled \_id
var childSchema = new Schema({ name: String }, { _id: false });
var parentSchema = new Schema({ children: [childSchema] });

var Model = mongoose.model('Model', parentSchema);

Model.create({ children: [{ name: 'Luke' }] }, function(error, doc) {
  // doc.children[0].\_id will be undefined
});

```

#### option: minimize


Mongoose will, by default, "minimize" schemas by removing empty objects.



```
var schema = new Schema({ name: String, inventory: {} });
var Character = mongoose.model('Character', schema);

// will store `inventory` field if it is not empty
var frodo = new Character({ name: 'Frodo', inventory: { ringOfPower: 1 }});
Character.findOne({ name: 'Frodo' }, function(err, character) {
  console.log(character); // { name: 'Frodo', inventory: { ringOfPower: 1 }}
});

// will not store `inventory` field if it is empty
var sam = new Character({ name: 'Sam', inventory: {}});
Character.findOne({ name: 'Sam' }, function(err, character) {
  console.log(character); // { name: 'Sam' }
});

```

This behavior can be overridden by setting `minimize` option to `false`. It will then store empty objects.



```
var schema = new Schema({ name: String, inventory: {} }, { minimize: false });
var Character = mongoose.model('Character', schema);

// will store `inventory` if empty
var sam = new Character({ name: 'Sam', inventory: {}});
Character.findOne({ name: 'Sam' }, function(err, character) {
  console.log(character); // { name: 'Sam', inventory: {}}
});

```

#### option: read


Allows setting [query#read](https://mongoosejs.com/docs/api.html#query_Query-read) options at the schema level, providing us a way to apply default [ReadPreferences](http://docs.mongodb.org/manual/applications/replication/#replica-set-read-preference) to all queries derived from a model.



```
var schema = new Schema({..}, { read: 'primary' });            // also aliased as 'p'
var schema = new Schema({..}, { read: 'primaryPreferred' });   // aliased as 'pp'
var schema = new Schema({..}, { read: 'secondary' });          // aliased as 's'
var schema = new Schema({..}, { read: 'secondaryPreferred' }); // aliased as 'sp'
var schema = new Schema({..}, { read: 'nearest' });            // aliased as 'n'

```

The alias of each pref is also permitted so instead of having to type out 'secondaryPreferred' and getting the spelling wrong, we can simply pass 'sp'.

 The read option also allows us to specify *tag sets*. These tell the [driver](https://github.com/mongodb/node-mongodb-native/) from which members of the replica-set it should attempt to read. Read more about tag sets [here](http://docs.mongodb.org/manual/applications/replication/#tag-sets) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences).

 *NOTE: you may also specify the driver read pref [strategy](http://mongodb.github.com/node-mongodb-native/api-generated/replset.html?highlight=strategy) option when connecting:*



```
// pings the replset members periodically to track network latency
var options = { replset: { strategy: 'ping' }};
mongoose.connect(uri, options);

var schema = new Schema({..}, { read: ['nearest', { disk: 'ssd' }] });
mongoose.model('JellyBean', schema);

```

#### option: safe


This option is passed to MongoDB with all operations and specifies if errors should be returned to our callbacks as well as tune write behavior.



```
var safe = true;
new Schema({ .. }, { safe: safe });

```

By default this is set to `true` for all schemas which guarentees that any occurring error gets passed back to our callback. By setting `safe` to something else like `{ j: 1, w: 2, wtimeout: 10000 }` we can guarantee the write was committed to the MongoDB journal (j: 1), at least 2 replicas (w: 2), and that the write will timeout if it takes longer than 10 seconds (wtimeout: 10000). Errors will still be passed to our callback.

 NOTE: In 3.6.x, you also need to turn [versioning](#versionKey) off. In 3.7.x and above, versioning will **automatically be disabled** when `safe` is set to `false`

 \*\*NOTE: this setting overrides any setting specified by passing db options while [creating a connection](https://mongoosejs.com/docs/api.html#index_Mongoose-createConnection).

 There are other write concerns like `{ w: "majority" }` too. See the MongoDB [docs](http://www.mongodb.org/display/DOCS/getLastError+Command) for more details.



```
var safe = { w: "majority", wtimeout: 10000 };
new Schema({ .. }, { safe: safe });

```

#### option: shardKey


The `shardKey` option is used when we have a [sharded MongoDB architecture](http://www.mongodb.org/display/DOCS/Sharding+Introduction). Each sharded collection is given a shard key which must be present in all insert/update operations. We just need to set this schema option to the same shard key and we’ll be all set.



```
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


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 the db.



```
var thingSchema = new Schema({..})
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing({ iAmNotInTheSchema: true });
thing.save(); // iAmNotInTheSchema is not saved to the db

// set to false..
var thingSchema = new Schema({..}, { strict: false });
var thing = new Thing({ iAmNotInTheSchema: true });
thing.save(); // iAmNotInTheSchema is now saved to the db!!

```

This also affects the use of `doc.set()` to set a property value.



```
var thingSchema = new Schema({..})
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing;
thing.set('iAmNotInTheSchema', true);
thing.save(); // iAmNotInTheSchema is not saved to the db

```

This value can be overridden at the model instance level by passing a second boolean argument:



```
var Thing = mongoose.model('Thing');
var thing = new Thing(doc, true);  // enables strict mode
var thing = new Thing(doc, false); // disables strict mode

```

The `strict` option may also be set to `"throw"` which will cause errors to be produced instead of dropping the bad data.


*NOTE: do not set to false unless you have good reason.*

 *NOTE: in mongoose v2 the default was false.*

 *NOTE: Any key/val set on the instance that does not exist in your schema is always ignored, regardless of schema option.*



```
var thingSchema = new Schema({..})
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing;
thing.iAmNotInTheSchema = true;
thing.save(); // iAmNotInTheSchema is never saved to the db

```

#### option: toJSON


Exactly the same as the [toObject](#toObject) option but only applies when the documents `toJSON` method is called.



```
var schema = new Schema({ name: String });
schema.path('name').get(function (v) {
  return v + ' is my name';
});
schema.set('toJSON', { getters: true, virtuals: false });
var M = mongoose.model('Person', schema);
var m = new M({ name: 'Max Headroom' });
console.log(m.toObject()); // { \_id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom' }
console.log(m.toJSON()); // { \_id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }
// since we know toJSON is called whenever a js object is stringified:
console.log(JSON.stringify(m)); // { "\_id": "504e0cd7dd992d9be2f20b6f", "name": "Max Headroom is my name" }

```

To see all available `toJSON/toObject` options, read [this](https://mongoosejs.com/docs/api.html#document_Document-toObject).


#### option: toObject


Documents have a [toObject](https://mongoosejs.com/docs/api.html#document_Document-toObject) method which converts the mongoose document into a plain javascript object. This method accepts a few options. Instead of applying these options on a per-document basis we may declare the options here and have it applied to all of this schemas documents by default.

 To have all virtuals show up in your `console.log` output, set the `toObject` option to `{ getters: true }`:



```
var schema = new Schema({ name: String });
schema.path('name').get(function (v) {
  return v + ' is my name';
});
schema.set('toObject', { getters: true });
var M = mongoose.model('Person', schema);
var m = new M({ name: 'Max Headroom' });
console.log(m); // { \_id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }

```

To see all available `toObject` options, read [this](https://mongoosejs.com/docs/api.html#document_Document-toObject).


#### option: typeKey


By default, if you have an object with key 'type' in your schema, mongoose will interpret it as a type declaration.



```
// Mongoose interprets this as 'loc is a String'
var schema = new Schema({ loc: { type: String, coordinates: [Number] } });

```

However, for applications like [geoJSON](http://docs.mongodb.org/manual/reference/geojson/), the 'type' property is important. If you want to control which key mongoose uses to find type declarations, set the 'typeKey' schema option.



```
var schema = new Schema({
  // Mongoose interpets this as 'loc is an object with 2 keys, type and coordinates'
  loc: { type: String, coordinates: [Number] },
  // Mongoose interprets this as 'name is a String'
  name: { $type: String }
}, { typeKey: '$type' }); // A '$type' key means this object is a type declaration

```

#### option: 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 handle validation manually, and be able to save objects which don't pass validation, you can set validateBeforeSave to false.



```
var schema = new Schema({ name: String });
schema.set('validateBeforeSave', false);
schema.path('name').validate(function (value) {
    return v != null;
});
var M = mongoose.model('Person', schema);
var m = new M({ name: null });
m.validate(function(err) {
    console.log(err); // Will tell you that null is not allowed.
});
m.save(); // Succeeds despite being invalid

```

#### option: versionKey


The `versionKey` is a property set on each document when first created by Mongoose. This keys value contains the internal [revision](http://aaronheckmann.tumblr.com/post/48943525537/mongoose-v3-part-1-versioning) of the document. The `versionKey` option is a string that represents the path to use for versioning. The default is `__v`. If this conflicts with your application you can configure as such:



```
var schema = new Schema({ name: 'string' });
var Thing = mongoose.model('Thing', schema);
var thing = new Thing({ name: 'mongoose v3' });
thing.save(); // { \_\_v: 0, name: 'mongoose v3' }

// customized versionKey
new Schema({..}, { versionKey: '\_somethingElse' })
var Thing = mongoose.model('Thing', schema);
var thing = new Thing({ name: 'mongoose v3' });
thing.save(); // { \_somethingElse: 0, name: 'mongoose v3' }

```

Document versioning can also be disabled by setting the `versionKey` to `false`. *DO NOT disable versioning unless you [know what you are doing](http://aaronheckmann.tumblr.com/post/48943525537/mongoose-v3-part-1-versioning).*



```
new Schema({..}, { versionKey: false });
var Thing = mongoose.model('Thing', schema);
var thing = new Thing({ name: 'no versioning please' });
thing.save(); // { name: 'no versioning please' }

```

#### option: collation


Sets a default [collation](https://docs.mongodb.com/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).



```
var schema = new Schema({
  name: String
}, { collation: { locale: 'en\_US', strength: 1 } });

var MyModel = db.model('MyModel', schema);

MyModel.create([{ name: 'val' }, { name: 'Val' }]).
  then(function() {
    return MyModel.find({ name: 'val' });
  }).
  then(function(docs) {
    // `docs` will contain both docs, because `strength: 1` means
    // MongoDB will ignore case when matching.
  });
  
```

#### option: skipVersioning


`skipVersioning` allows excluding paths from versioning (i.e., the internal revision will not be incremented even if these paths are updated). DO NOT do this unless you know what you're doing. For sub-documents, include this on the parent document using the fully qualified path.



```
new Schema({..}, { skipVersioning: { dontVersionMe: true } });
thing.dontVersionMe.push('hey');
thing.save(); // version is not incremented

```

#### option: timestamps


If set `timestamps`, mongoose assigns `createdAt` and `updatedAt` fields to your schema, the type assigned is [Date](api#schema-date-js).

 By default, the name of two fields are `createdAt` and `updatedAt`, customize the field name by setting `timestamps.createdAt` and `timestamps.updatedAt`.



```
var thingSchema = new Schema({..}, { timestamps: { createdAt: 'created\_at' } });
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing();
thing.save(); // `created\_at` & `updatedAt` will be included

```

#### option: useNestedStrict


In mongoose 4, `update()` and `findOneAndUpdate()` only check the top-level schema's strict mode setting.



```
var childSchema = new Schema({}, { strict: false });
var parentSchema = new Schema({ child: childSchema }, { strict: 'throw' });
var Parent = mongoose.model('Parent', parentSchema);
Parent.update({}, { 'child.name': 'Luke Skywalker' }, function(error) {
  // Error because parentSchema has `strict: throw`, even though
  // `childSchema` has `strict: false`
});

var update = { 'child.name': 'Luke Skywalker' };
var opts = { strict: false };
Parent.update({}, update, opts, function(error) {
  // This works because passing `strict: false` to `update()` overwrites
  // the parent schema.
});
```

If you set `useNestedStrict` to true, mongoose will use the child schema's `strict` option for casting updates.



```
var childSchema = new Schema({}, { strict: false });
var parentSchema = new Schema({ child: childSchema },
  { strict: 'throw', useNestedStrict: true });
var Parent = mongoose.model('Parent', parentSchema);
Parent.update({}, { 'child.name': 'Luke Skywalker' }, function(error) {
  // Works!
});

```

#### option: retainKeyOrder


By default, mongoose reverses key order in documents as a performance optimization. For example, `new Model({ first: 1, second: 2 });` would actually be stored in MongoDB as `{ second: 2, first: 1 }`. This behavior is [considered deprecated](https://github.com/Automattic/mongoose/wiki/5.0-Deprecation-Warnings) because it has numerous unintended side effects, including making it difficult to manipulate documents whose `_id` field is an object.

 Mongoose >= 4.6.4 has a `retainKeyOrder` option for schemas that ensures that mongoose will always keep the correct order for your object keys.



```
var testSchema = new Schema({ first: Number, second: Number }, { retainKeyOrder: true });
var Test = mongoose.model('Test', testSchema);
Test.create({ first: 1, second: 2 }); // Will be stored in mongodb as `{ first: 1, second: 2 }`

```

Pluggable
---------


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


Next Up
-------


Now that we've covered `Schemas`, let's take a look at [SchemaTypes](../../schematypes).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/guide.html>

Getting Started
===============


*First be sure you have [MongoDB](http://www.mongodb.org/downloads) and [Node.js](http://nodejs.org/) installed.*

 Next install Mongoose from the command line using `npm`:

 
```
$ npm install mongoose
```

Now say we like fuzzy kittens and want to record every kitten we ever meet in MongoDB. The first thing we need to do is include mongoose in our project and open a connection to the `test` database on our locally running instance of MongoDB.



```
// getting-started.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
```

We have a pending connection to the test database running on localhost. We now need to get notified if we connect successfully or if a connection error occurs:



```
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
  // we're connected!
});
```

Once our connection opens, our callback will be called. For brevity, let's assume that all following code is within this callback.


With Mongoose, everything is derived from a [Schema](../../guide). Let's get a reference to it and define our kittens.



```
var kittySchema = mongoose.Schema({
    name: String
});
```

So far so good. We've got a schema with one property, `name`, which will be a `String`. The next step is compiling our schema into a [Model](../../models).



```
var Kitten = mongoose.model('Kitten', kittySchema);
```

A model is a class with which we construct documents. In this case, each document will be a kitten with properties and behaviors as declared in our schema. Let's create a kitten document representing the little guy we just met on the sidewalk outside:



```
var silence = new Kitten({ name: 'Silence' });
console.log(silence.name); // 'Silence'
```

Kittens can meow, so let's take a look at how to add "speak" functionality to our documents:



```
// NOTE: methods must be added to the schema before compiling it with mongoose.model()
kittySchema.methods.speak = function () {
  var greeting = this.name
    ? "Meow name is " + this.name
    : "I don't have a name";
  console.log(greeting);
}

var Kitten = mongoose.model('Kitten', kittySchema);
```

Functions added to the `methods` property of a schema get compiled into the `Model` prototype and exposed on each document instance:



```
var fluffy = new Kitten({ name: 'fluffy' });
fluffy.speak(); // "Meow name is fluffy"
```

We have talking kittens! But we still haven't saved anything to MongoDB. Each document can be saved to the database by calling its [save](https://mongoosejs.com/docs/api.html#model_Model-save) method. The first argument to the callback will be an error if any occured.



```
fluffy.save(function (err, fluffy) {
  if (err) return console.error(err);
  fluffy.speak();
});
```

Say time goes by and we want to display all the kittens we've seen. We can access all of the kitten documents through our Kitten [model](../../models).



```
Kitten.find(function (err, kittens) {
  if (err) return console.error(err);
  console.log(kittens);
})
```

We just logged all of the kittens in our db to the console. If we want to filter our kittens by name, Mongoose supports MongoDBs rich [querying](../../queries) syntax.



```
Kitten.find({ name: /^fluff/ }, callback);
```

This performs a search for all documents with a name property that begins with "Fluff" and returns the result as an array of kittens to the callback.


Congratulations
---------------


That's the end of our quick start. We created a schema, added a custom document method, saved and queried kittens in MongoDB using Mongoose. Head over to the <guide>, or [API docs](api) for more.



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/index.html>

Migrating from 3.x to 4.x
=========================


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
--------------------------------------------------------


Mongoose's `findOneAndUpdate()`, `findOneAndRemove()`, `findByIdAndUpdate()`, and `findByIdAndRemove()` functions are just wrappers around MongoDB's [`findAndModify` command](http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/). Both the MongoDB server and the MongoDB NodeJS driver set the `new` option to false by default, but mongoose 3 overwrote this default. In order to be more consistent with the MongoDB server's documentation, mongoose will use false by default. That is, `findOneAndUpdate({}, { $set: { test: 1 } }, callback);` will return the document as it was *before* the `$set` operation was applied.

 To return the document with modifications made on the update, use the `new: true` option.



```
MyModel.findOneAndUpdate({}, { $set: { test: 1 } }, { new: true }, callback);

```

CastError and ValidationError now use `kind` instead of `type` to report error types
------------------------------------------------------------------------------------


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
----------------------------------


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 promises, so you can do `MyModel.find().then()` instead. Be careful if 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
---------


Related blog posts:

 * [Introducting Version 4.0 of the Mongoose NodeJS ODM](http://www.mongodb.com/blog/post/introducing-version-40-mongoose-nodejs-odm)



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/migration.html>

SchemaTypes
===========


SchemaTypes handle definition of path [defaults](api#schematype_SchemaType-default), [validation](api#schematype_SchemaType-validate), [getters](api#schematype_SchemaType-get), [setters](api#schematype_SchemaType-set), [field selection defaults](api#schematype_SchemaType-select) for [queries](api#query-js) and other general characteristics for [Strings](api#schema-string-js) and[Numbers](api#schema-number-js). Check out their respective API documentation for more detail.


Following are all valid [Schema Types](api#schema_Schema.Types).


* [String](api#schema-string-js)
* [Number](api#schema-number-js)
* [Date](api#schema-date-js)
* [Buffer](api#schema-buffer-js)
* Boolean
* Mixed
* [Objectid](api#schema-objectid-js)
* Array


#### Example



```
var schema = new Schema({
  name:    String,
  binary:  Buffer,
  living:  Boolean,
  updated: { type: Date, default: Date.now },
  age:     { type: Number, min: 18, max: 65 },
  mixed:   Schema.Types.Mixed,
  _someId: Schema.Types.ObjectId,
  array:      [],
  ofString:   [String],
  ofNumber:   [Number],
  ofDates:    [Date],
  ofBuffer:   [Buffer],
  ofBoolean:  [Boolean],
  ofMixed:    [Schema.Types.Mixed],
  ofObjectId: [Schema.Types.ObjectId],
  ofArrays:   [[]],
  ofArrayOfNumbers: [[Number]],
  nested: {
    stuff: { type: String, lowercase: true, trim: true }
  }
})

// example use

var Thing = mongoose.model('Thing', schema);

var m = new Thing;
m.name = 'Statue of Liberty';
m.age = 125;
m.updated = new Date;
m.binary = new Buffer(0);
m.living = false;
m.mixed = { any: { thing: 'i want' } };
m.markModified('mixed');
m._someId = new mongoose.Types.ObjectId;
m.array.push(1);
m.ofString.push("strings!");
m.ofNumber.unshift(1,2,3,4);
m.ofDates.addToSet(new Date);
m.ofBuffer.pop();
m.ofMixed = [1, [], 'three', { four: 5 }];
m.nested.stuff = 'good';
m.save(callback);

```

SchemaType Options
------------------


You can declare a schema type using the type directly, or an object with a `type` property.



```
var schema1 = new Schema({
  test: String // `test` is a path of type String
});

var schema2 = new Schema({
  test: { type: String } // `test` is a path of type string
});
```

In addition to the type property, you can specify additional properties for a path. For example, if you want to lowercase a string before saving:



```
var schema2 = new Schema({
  test: {
    type: String,
    lowercase: true // Always convert `test` to lowercase
  }
});
```

The `lowercase` property 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


* `required`: boolean or function, if true adds a [required validator](validation#built-in-validators) for this property
* `default`: Any or function, sets a default value for the path. If the value is a function, the return value of the function is used as the default.
* `select`: boolean, specifies default [projections](https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/) for queries
* `validate`: function, adds a [validator function](validation#built-in-validators) for this property
* `get`: function, defines a custom getter for this property using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
* `set`: function, defines a custom setter for this property using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
* `alias`: string, mongoose >= 4.10.0 only. Defines a [virtual](guide#virtuals) with the given name that gets/sets this path.



```
var numberSchema = new Schema({
  integerOnly: {
    type: Number,
    get: v => Math.round(v),
    set: v => Math.round(v),
    alias: 'i'
  }
});

var Number = mongoose.model('Number', numberSchema);

var doc = new Number();
doc.integerOnly = 2.001;
doc.integerOnly; // 2
doc.i; // 2
doc.i = 3.001;
doc.integerOnly; // 3
doc.i; // 3

```

##### Indexes


You can also define [MongoDB indexes](https://docs.mongodb.com/manual/indexes/) using schema type options.


* `index`: boolean, whether to define an [index](https://docs.mongodb.com/manual/indexes/) on this property.
* `unique`: boolean, whether to define a [unique index](https://docs.mongodb.com/manual/core/index-unique/) on this property.
* `sparse`: boolean, whether to define a [sparse index](https://docs.mongodb.com/manual/core/index-sparse/) on this property.



```
var schema2 = new Schema({
  test: {
    type: String,
    index: true,
    unique: true // Unique index. If you specify `unique: true`
    // specifying `index: true` is optional if you do `unique: true`
  }
});
```

##### String


* `lowercase`: boolean, whether to always call `.toLowerCase()` on the value
* `uppercase`: boolean, whether to always call `.toUpperCase()` on the value
* `trim`: boolean, whether to always call `.trim()` on the value
* `match`: RegExp, creates a [validator](validation) that checks if the value matches the given regular expression
* `enum`: Array, creates a [validator](validation) that checks if the value is in the given array.


##### Number


* `min`: Number, creates a [validator](validation) that checks if the value is greater than or equal to the given minimum.
* `max`: Number, creates a [validator](validation) that checks if the value is less than or equal to the given maximum.


##### Date


* `min`: Date
* `max`: Date


Usage notes:
------------


#### 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.



```
var Assignment = mongoose.model('Assignment', { dueDate: Date });
Assignment.findOne(function (err, doc) {
  doc.dueDate.setMonth(3);
  doc.save(callback); // THIS DOES NOT SAVE YOUR CHANGE
  
  doc.markModified('dueDate');
  doc.save(callback); // works
})

```

#### Mixed


An "anything goes" SchemaType, its flexibility comes at a trade-off of it being harder to maintain. Mixed is available either through Schema.Types.Mixed or by passing an empty object literal. The following are equivalent:



```
var Any = new Schema({ any: {} });
var Any = new Schema({ any: Object });
var Any = new Schema({ any: Schema.Types.Mixed });
```

Since it is a schema-less type, you can change the value to anything else you like, but Mongoose loses the ability to auto detect and save those changes. To "tell" Mongoose that the value of a Mixed type has changed, call the`.markModified(path)` method of the document passing the path to the Mixed type you just changed.



```
person.anything = { x: [3, 4, { y: "changed" }] };
person.markModified('anything');
person.save(); // anything will now get saved
```

#### ObjectIds


To specify a type of ObjectId, use`Schema.Types.ObjectId` in your declaration.



```
var mongoose = require('mongoose');
var ObjectId = mongoose.Schema.Types.ObjectId;
var Car = new Schema({ driver: ObjectId });
// or just Schema.ObjectId for backwards compatibility with v2
```

#### Arrays


Provide creation of arrays of[SchemaTypes](api#schema_Schema.Types) or[Sub-Documents](subdocs).



```
var ToySchema = new Schema({ name: String });
var ToyBox = new Schema({
  toys: [ToySchema],
  buffers: [Buffer],
  string:  [String],
  numbers: [Number]
  // ... etc
});
```

Note: specifying an empty array is equivalent to`Mixed`. The following all create arrays of`Mixed`:



```
var Empty1 = new Schema({ any: [] });
var Empty2 = new Schema({ any: Array });
var Empty3 = new Schema({ any: [Schema.Types.Mixed] });
var Empty4 = new Schema({ any: [{}] });
```

Arrays implicitly have a default value of `[]` (empty array).



```
var Toy = mongoose.model('Test', ToySchema);
console.log((new Toy()).toys); // []
```

To overwrite this default, you need to set the default value to `undefined`



```
var ToySchema = new Schema({
  toys: {
    type: [ToySchema],
    default: undefined
  }
});
```

If an array is marked as `required`, it must have at least one element.



```
var ToySchema = new Schema({
  toys: {
    type: [ToySchema],
    required: true
  }
});
var Toy = mongoose.model('Toy', ToySchema);
Toy.create({ toys: [] }, function(error) {
  console.log(error.errors['toys'].message); // Path "toys" is required.
});
```

Creating Custom Types
---------------------


Mongoose can also be extended with custom SchemaTypes. Search the[plugins](http://plugins.mongoosejs.com) site for compatible types like[mongoose-long](https://github.com/aheckmann/mongoose-long), [mongoose-int32](https://github.com/vkarpov15/mongoose-int32) and[other](https://github.com/aheckmann/mongoose-function)|[types](https://github.com/OpenifyIt/mongoose-types).


The `schema.path()` Function
----------------------------


The `schema.path()` function returns the instantiated schema type for a given path.



```
var sampleSchema = new Schema({ name: { type: String, required: true } });
console.log(sampleSchema.path('name'));
// Output looks like:
/\*\*
 \* SchemaString {
 \* enumValues: [],
 \* regExp: null,
 \* path: 'name',
 \* instance: 'String',
 \* validators: ...
 \*/
```

You can use this function to inspect the schema type for a given path, including what validators it has and what the type is.


Next Up
-------


Now that we've covered `SchemaTypes`, let's take a look at [Models](../../models).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/schematypes.html>

Middleware
==========


Middleware (also called pre and post *hooks*) are functions which are passed control during execution of asynchronous functions. Middleware is specified on the schema level and is useful for writing <plugins>. Mongoose 4.x has 4 types of middleware: document middleware, model middleware, aggregate middleware, and query middleware. Document middleware is supported for the following document functions. In document middleware functions, `this` refers to the document.

 * [init](api#document_Document-init)
* [validate](api#document_Document-validate)
* [save](api#model_Model-save)
* [remove](api#model_Model-remove)

 Query middleware is supported for the following Model and Query functions. In query middleware functions, `this` refers to the query.

 * [count](api#query_Query-count)
* [find](api#query_Query-find)
* [findOne](api#query_Query-findOne)
* [findOneAndRemove](api#query_Query-findOneAndRemove)
* [findOneAndUpdate](api#query_Query-findOneAndUpdate)
* [update](api#query_Query-update)

 Aggregate middleware is for `MyModel.aggregate()`. Aggregate middleware executes when you call `exec()` on an aggregate object. In aggregate middleware, `this` refers to the [aggregation object](api#model_Model.aggregate).

 * [aggregate](api#model_Model.aggregate)

 Model middleware is supported for the following model functions. In model middleware functions, `this` refers to the model.

 * [insertMany](api#model_Model.insertMany)

 All middleware types support pre and post hooks. How pre and post hooks work is described in more detail below.

 **Note:** There is no query hook for `remove()`, only for documents. If you set a 'remove' hook, it will be fired when you call `myDoc.remove()`, not when you call `MyModel.remove()`. **Note:** The `create()` function fires `save()` hooks.


Pre
---


There are two types of `pre` hooks, serial and parallel.


#### Serial


Serial middleware functions are executed one after another, when each middleware calls `next`.



```
var schema = new Schema(..);
schema.pre('save', function(next) {
  // do stuff
  next();
});
```

The `next()` call does **not** stop the rest of the code in your middleware function from executing. Use [the early `return` pattern](https://www.bennadel.com/blog/2323-use-a-return-statement-when-invoking-callbacks-especially-in-a-guard-statement.htm) to prevent the rest of your middleware function from running when you call `next()`.



```
var schema = new Schema(..);
schema.pre('save', function(next) {
  if (foo()) {
    console.log('calling next!');
    // `return next();` will make sure the rest of this function doesn't run
    /\*return\*/ next();
  }
  // Unless you comment out the `return` above, 'after next' will print
  console.log('after next');
});
```

#### Parallel


Parallel middleware offer more fine-grained flow control.



```
var schema = new Schema(..);

// `true` means this is a parallel middleware. You \*\*must\*\* specify `true`
// as the second parameter if you want to use parallel middleware.
schema.pre('save', true, function(next, done) {
  // calling next kicks off the next middleware in parallel
  next();
  setTimeout(done, 100);
});
```

The hooked method, in this case `save`, will not be executed until `done` is called by each middleware.


#### Use Cases


Middleware are useful for atomizing model logic and avoiding nested blocks of async code. Here are some other ideas:


* complex validation
* removing dependent documents
	+ (removing a user removes all his blogposts)
* asynchronous defaults
* asynchronous tasks that a certain action triggers
	+ triggering custom events
	+ notifications


#### Error handling


If any middleware calls `next` or `done` with a parameter of type `Error`, the flow is interrupted, and the error is passed to the callback.



```
schema.pre('save', function(next) {
  // You \*\*must\*\* do `new Error()`. `next('something went wrong')` will
  // \*\*not\*\* work
  var err = new Error('something went wrong');
  next(err);
});

// later...

myDoc.save(function(err) {
  console.log(err.message) // something went wrong
});

```

Post middleware
---------------


[post](https://mongoosejs.com/docs/api.html#schema_Schema-post) middleware are executed *after* the hooked method and all of its `pre` middleware have completed. `post` middleware do not directly receive flow control, e.g. no `next` or `done` callbacks are passed to it. `post` hooks are a way to register traditional event listeners for these methods.



```
schema.post('init', function(doc) {
  console.log('%s has been initialized from the db', doc._id);
});
schema.post('validate', function(doc) {
  console.log('%s has been validated (but not saved yet)', doc._id);
});
schema.post('save', function(doc) {
  console.log('%s has been saved', doc._id);
});
schema.post('remove', function(doc) {
  console.log('%s has been removed', doc._id);
});

```

Asynchronous Post Hooks
-----------------------


While post middleware doesn't receive flow control, you can still make sure that asynchronous post hooks are executed in a pre-defined order. 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.



```
// Takes 2 parameters: this is an asynchronous post hook
schema.post('save', function(doc, next) {
  setTimeout(function() {
    console.log('post1');
    // Kick off the second post hook
    next();
  }, 10);
});

// Will not execute until the first middleware calls `next()`
schema.post('save', function(doc, next) {
  console.log('post2');
  next();
});

```

Save/Validate Hooks
-------------------


The `save()` function triggers `validate()` hooks, because mongoose has a built-in `pre('save')` hook that calls `validate()`. This means that all `pre('validate')` and `post('validate')` hooks get called **before** any `pre('save')` hooks.



```
schema.pre('validate', function() {
  console.log('this gets printed first');
});
schema.post('validate', function() {
  console.log('this gets printed second');
});
schema.pre('save', function() {
  console.log('this gets printed third');
});
schema.post('save', function() {
  console.log('this gets printed fourth');
});

```

Notes on findAndUpdate() and Query Middleware
---------------------------------------------


Pre and post `save()` hooks are **not** executed on `update()`, `findOneAndUpdate()`, etc. You can see a more detailed discussion why in [this GitHub issue](http://github.com/Automattic/mongoose/issues/964). Mongoose 4.0 has distinct hooks for these functions.



```
schema.pre('find', function() {
  console.log(this instanceof mongoose.Query); // true
  this.start = Date.now();
});

schema.post('find', function(result) {
  console.log(this instanceof mongoose.Query); // true
  // prints returned documents
  console.log('find() returned ' + JSON.stringify(result));
  // prints number of milliseconds the query took
  console.log('find() took ' + (Date.now() - this.start) + ' millis');
});

```

Query middleware differs from document middleware in a subtle but important way: in document middleware, `this` refers to the document being updated. In query middleware, mongoose doesn't necessarily have a reference to the document being updated, so `this` refers to the **query** object rather than the document being updated.

 For instance, if you wanted to add an `updatedAt` timestamp to every `update()` call, you would use the following pre hook.



```
schema.pre('update', function() {
  this.update({},{ $set: { updatedAt: new Date() } });
});

```

Error Handling Middleware
-------------------------


*New in 4.5.0*

 Middleware execution normally stops the first time a piece of middleware calls `next()` with an error. However, there is a special kind of post middleware called "error handling middleware" that executes specifically when an error occurs.

 Error handling middleware is defined as middleware that takes one extra parameter: the 'error' that occurred as the first parameter to the function. Error handling middleware can then transform the error however you want.



```
var schema = new Schema({
  name: {
    type: String,
    // Will trigger a MongoError with code 11000 when
    // you save a duplicate
    unique: true
  }
});

// Handler \*\*must\*\* take 3 parameters: the error that occurred, the document
// in question, and the `next()` function
schema.post('save', function(error, doc, next) {
  if (error.name === 'MongoError' && error.code === 11000) {
    next(new Error('There was a duplicate key error'));
  } else {
    next(error);
  }
});

// Will trigger the `post('save')` error handler
Person.create([{ name: 'Axl Rose' }, { name: 'Axl Rose' }]);

```

Error handling middleware also works with query middleware. You can also define a post `update()` hook that will catch MongoDB duplicate key errors.



```
// The same E11000 error can occur when you call `update()`
// This function \*\*must\*\* take 3 parameters. If you use the
// `passRawResult` function, this function \*\*must\*\* take 4
// parameters
schema.post('update', function(error, res, next) {
  if (error.name === 'MongoError' && error.code === 11000) {
    next(new Error('There was a duplicate key error'));
  } else {
    next(error);
  }
});

var people = [{ name: 'Axl Rose' }, { name: 'Slash' }];
Person.create(people, function(error) {
  Person.update({ name: 'Slash' }, { $set: { name: 'Axl Rose' } }, function(error) {
    // `error.message` will be "There was a duplicate key error"
  });
});

```

Next Up
-------


Now that we've covered middleware, let's take a look at Mongoose's approach to faking JOINs with its query [population](../../populate) helper.



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/middleware.html>

Models
======


[Models](api#model-js) are fancy constructors compiled from our `Schema` definitions. Instances of these models represent <documents> which can be saved and retrieved from our database. All document creation and retrieval from the database is handled by these models.


Compiling your first model
--------------------------



```
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
var Tank = mongoose.model('Tank', schema);

```

The first argument is the *singular* name of the collection your model is for.  **Mongoose automatically looks for the *plural* version of your model name.**  Thus, for the example above, the model Tank is for the **tanks** collection in the database. The `.model()` function makes a copy of `schema`. Make sure that you've added everything you want to `schema` before calling `.model()`!


Constructing documents
----------------------


[Documents](documents) are instances of our model. Creating them and saving to the database is easy:



```
var Tank = mongoose.model('Tank', yourSchema);

var small = new Tank({ size: 'small' });
small.save(function (err) {
  if (err) return handleError(err);
  // saved!
})

// or

Tank.create({ size: 'small' }, function (err, small) {
  if (err) return handleError(err);
  // saved!
})
```

Note that no tanks will be created/removed until the connection your model uses is open. Every model has an associated connection. When you use `mongoose.model()`, your model will use the default mongoose connection.



```
mongoose.connect('localhost', 'gettingstarted');
```

If you create a custom connection, use that connection's `model()` function instead.



```
var connection = mongoose.createConnection('mongodb://localhost:27017/test');
var Tank = connection.model('Tank', yourSchema);

```

Querying
--------


Finding documents is easy with Mongoose, which supports the [rich](http://www.mongodb.org/display/DOCS/Advanced+Queries) query syntax of MongoDB. Documents can be retreived using each `models` [find](api#model_Model.find), [findById](api#model_Model.findById), [findOne](api#model_Model.findOne), or [where](api#model_Model.where) static methods.



```
Tank.find({ size: 'small' }).where('createdDate').gt(oneYearAgo).exec(callback);
```

See the chapter on [querying](queries) for more details on how to use the [Query](api#query-js) api.


Removing
--------


Models have a static `remove` method available for removing all documents matching `conditions`.



```
Tank.remove({ size: 'large' }, function (err) {
  if (err) return handleError(err);
  // removed!
});
```

Updating
--------


Each `model` has its own `update` method for modifying documents in the database without returning them to your application. See the [API](api#model_Model.update) docs for more detail.

 *If you want to update a single document in the db and return it to your application, use [findOneAndUpdate](api#model_Model.findOneAndUpdate) instead.*


Yet more
--------


The [API docs](api#model_Model) cover many additional methods available like [count](api#model_Model.count), [mapReduce](api#model_Model.mapReduce), [aggregate](api#model_Model.aggregate), and [more](api#model_Model.findOneAndRemove).


Next Up
-------


Now that we've covered `Models`, let's take a look at [Documents](../../documents).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/models.html>

Documents
=========


Mongoose [documents](api#document-js) represent a one-to-one mapping to documents as stored in MongoDB. Each document is an instance of its [Model](models).


Retrieving
----------


There are many ways to retrieve documents from MongoDB. We won't cover that in this section. See the chapter on [querying](queries) for detail.


Updating
--------


There are a number of ways to update documents. We'll first look at a traditional approach using [findById](api#model_Model.findById):



```
Tank.findById(id, function (err, tank) {
  if (err) return handleError(err);
  
  tank.size = 'large';
  tank.save(function (err, updatedTank) {
    if (err) return handleError(err);
    res.send(updatedTank);
  });
});
```

You can also use [`.set()`](api#document_Document-set) to modify documents. Under the hood, `tank.size = 'large';` becomes `tank.set({ size: 'large' })`.



```
Tank.findById(id, function (err, tank) {
  if (err) return handleError(err);
  
  tank.set({ size: 'large' });
  tank.save(function (err, updatedTank) {
    if (err) return handleError(err);
    res.send(updatedTank);
  });
});
```

This approach involves first retrieving the document from Mongo, then issuing an update command (triggered by calling `save`). However, if we don't need the document returned in our application and merely want to update a property in the database directly, [Model#update](api#model_Model.update) is right for us:



```
Tank.update({ _id: id }, { $set: { size: 'large' }}, callback);
```

If we do need the document returned in our application there is another, often [better](api#model_Model.findByIdAndUpdate), option:



```
Tank.findByIdAndUpdate(id, { $set: { size: 'large' }}, { new: true }, function (err, tank) {
  if (err) return handleError(err);
  res.send(tank);
});
```

The `findAndUpdate/Remove` static methods all make a change to at most one document, and return it with just one call to the database. There [are](api#model_Model.findByIdAndRemove) [several](api#model_Model.findOneAndUpdate) [variations](api#model_Model.findOneAndRemove) on the [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) theme. Read the [API](api) docs for more detail.

 \_Note that `findAndUpdate/Remove` do *not* execute any hooks or validation before making the change in the database. You can use the [`runValidators` option](../../validation#update-validators) to access a limited subset of document validation. However, if you need hooks and full document validation, first query for the document and then `save()` it.\_


Validating
----------


Documents are validated before they are saved. Read the [api](api#document_Document-validate) docs or the <validation> chapter for detail.


Overwriting
-----------


You can overwrite an entire document using `.set()`. This is handy if you want to change what document is being saved in [middleware](docs/middleware).



```
Tank.findById(id, function (err, tank) {
  if (err) return handleError(err);
  // Now `otherTank` is a copy of `tank`
  otherTank.set(tank);
});

```

Next Up
-------


Now that we've covered `Documents`, let's take a look at [Sub-documents](../../subdocs).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/documents.html>

Queries
=======


Documents can be retrieved through several static helper methods of <models>.


Any [model](api#model_Model) method which [involves](api#model_Model.find) [specifying](api#model_Model.findById) [query](api#model_Model.count) [conditions](api#model_Model.update) can be executed two ways:

 When a `callback` function:

 * is passed, the operation will be executed immediately with the results passed to the callback.
* is not passed, an instance of [Query](api#query-js) is returned, which provides a special query builder interface.


In mongoose 4, a [Query](api#query-js) has a `.then()` function, and thus can be used as a promise.


When executing a query with a `callback` function, you specify your query as a JSON document. The JSON document's syntax is the same as the [MongoDB shell](http://docs.mongodb.org/manual/tutorial/query-documents/).



```
var Person = mongoose.model('Person', yourSchema);

// find each person with a last name matching 'Ghost', selecting the `name` and `occupation` fields
Person.findOne({ 'name.last': 'Ghost' }, 'name occupation', function (err, person) {
  if (err) return handleError(err);
  console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation) // Space Ghost is a talk show host.
})
```

Here we see that the query was executed immediately and the results passed to our callback. All callbacks in Mongoose use the pattern: `callback(error, result)`. If an error occurs executing the query, the `error` parameter will contain an error document, and `result` will be null. If the query is successful, the `error` parameter will be null, and the `result` will be populated with the results of the query.


Anywhere a callback is passed to a query in Mongoose, the callback follows the pattern `callback(error, results)`. What `results` is depends on the operation: For `findOne()` it is a [potentially-null single document](api#model_Model.findOne), `find()` a [list of documents](api#model_Model.find), `count()` [the number of documents](api#model_Model.count), `update()` the [number of documents affected](api#model_Model.update), etc. The [API docs for Models](api#model-js) provide more detail on what is passed to the callbacks.


Now let's look at what happens when no `callback` is passed:



```
// find each person with a last name matching 'Ghost'
var query = Person.findOne({ 'name.last': 'Ghost' });

// selecting the `name` and `occupation` fields
query.select('name occupation');

// execute the query at a later time
query.exec(function (err, person) {
  if (err) return handleError(err);
  console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation) // Space Ghost is a talk show host.
})
```

In the above code, the `query` variable is of type [Query](api#query-js). A `Query` enables you to build up a query using chaining syntax, rather than specifying a JSON object. The below 2 examples are equivalent.



```
// With a JSON doc
Person.
  find({
    occupation: /host/,
    'name.last': 'Ghost',
    age: { $gt: 17, $lt: 66 },
    likes: { $in: ['vaporizing', 'talking'] }
  }).
  limit(10).
  sort({ occupation: -1 }).
  select({ name: 1, occupation: 1 }).
  exec(callback);
  
// Using query builder
Person.
  find({ occupation: /host/ }).
  where('name.last').equals('Ghost').
  where('age').gt(17).lt(66).
  where('likes').in(['vaporizing', 'talking']).
  limit(10).
  sort('-occupation').
  select('name occupation').
  exec(callback);
  
```

A full list of [Query helper functions can be found in the API docs](api#query-js).


Setters are not executed by default in 4.x. For example, if you lowercase emails in your schema:



```
var personSchema = new Schema({
  email: {
    type: String,
    lowercase: true
  }
});

```

Mongoose will **not** automatically lowercase the email in your queries, so `Person.find({ email: 'Val@karpov.io' })` would return no results. Use the `runSettersOnQuery` option to turn on this behavior:



```
var personSchema = new Schema({
  email: {
    type: String,
    lowercase: true
  }
}, { runSettersOnQuery: true });

```

References to other documents
-----------------------------


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


Streaming
---------


You can [stream](http://nodejs.org/api/stream.html) query results from MongoDB. You need to call the [Query#cursor()](api#query_Query-cursor) function instead of [Query#exec](api#query_Query-exec) to return an instance of [QueryCursor](api#querycursor-js).



```
var cursor = Person.find({ occupation: /host/ }).cursor();
cursor.on('data', function(doc) {
  // Called once for every document
});
cursor.on('close', function() {
  // Called when done
});

```

Next Up
-------


Now that we've covered `Queries`, let's take a look at [validation](../../validation).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/queries.html>

Plugins
=======


Schemas are pluggable, that is, they allow for applying pre-packaged capabilities to extend their functionality. This is a very powerful feature.

 Suppose that we have several collections in our database and want to add last-modified functionality to each one. With plugins this is easy. Just create a plugin once and apply it to each `Schema`:



```
// lastMod.js
module.exports = exports = function lastModifiedPlugin (schema, options) {
  schema.add({ lastMod: Date })
  
  schema.pre('save', function (next) {
    this.lastMod = new Date
    next()
  })
  
  if (options && options.index) {
    schema.path('lastMod').index(options.index)
  }
}

// game-schema.js
var lastMod = require('./lastMod');
var Game = new Schema({ ... });
Game.plugin(lastMod, { index: true });

// player-schema.js
var lastMod = require('./lastMod');
var Player = new Schema({ ... });
Player.plugin(lastMod);
```

We just added last-modified behavior to both our `Game` and `Player` schemas and declared an index on the `lastMod` path of our Games to boot. Not bad for a few lines of code.


Global Plugins
--------------


Want to register a plugin for all schemas? The mongoose singleton has a `.plugin()` function that registers a plugin for every schema. For example:



```
var mongoose = require('mongoose');
mongoose.plugin(require('./lastMod'));

var gameSchema = new Schema({ ... });
var playerSchema = new Schema({ ... });
// `lastModifiedPlugin` gets attached to both schemas
var Game = mongoose.model('Game', gameSchema);
var Player = mongoose.model('Player', playerSchema);
```

Community!
----------


Not only can you re-use schema functionality in your own projects but you also reap the benefits of the Mongoose community as well. Any plugin published to [npm](https://npmjs.org/) and [tagged](https://npmjs.org/doc/tag.html) with `mongoose` will show up on our [search results](http://plugins.mongoosejs.io) page.


Next Up
-------


Now that we've covered plugins and how to get involved in the great community growing around them, let's take a look how you can help [contribute](https://github.com/Automattic/mongoose/blob/master/CONTRIBUTING.md) to the continuing development of Mongoose itself.



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/plugins.html>

Sub Docs
========


Subdocuments are documents embedded in other documents. In Mongoose, this means you can nest schemas in other schemas. Mongoose has two distinct notions of subdocuments: arrays of subdocuments and single nested subdocuments.



```
var childSchema = new Schema({ name: 'string' });

var parentSchema = new Schema({
  // Array of subdocuments
  children: [childSchema],
  // Single nested subdocuments. Caveat: single nested subdocs only work
  // in mongoose >= 4.2.0
  child: childSchema
});

```

Subdocuments are similar to normal documents. Nested schemas can have <middleware>, [custom validation logic](validation), virtuals, and any other feature top-level schemas can use. The major difference is that subdocuments are not saved individually, they are saved whenever their top-level parent document is saved.



```
var Parent = mongoose.model('Parent', parentSchema);
var parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] })
parent.children[0].name = 'Matthew';

// `parent.children[0].save()` is a no-op, it triggers middleware but
// does \*\*not\*\* actually save the subdocument. You need to save the parent
// doc.
parent.save(callback);

```

Subdocuments have `save` and `validate` <middleware> just like top-level documents. Calling `save()` on the parent document triggers the `save()` middleware for all its subdocuments, and the same for `validate()` middleware.



```
childSchema.pre('save', function (next) {
  if ('invalid' == this.name) {
    return next(new Error('#sadpanda'));
  }
  next();
});

var parent = new Parent({ children: [{ name: 'invalid' }] });
parent.save(function (err) {
  console.log(err.message) // #sadpanda
});

```

Subdocuments' `pre('save')` and `pre('validate')` middleware execute **before** the top-level document's `pre('save')` but **after** the top-level document's `pre('validate')` middleware. This is because validating before `save()` is actually a piece of built-in middleware.



```
// Below code will print out 1-4 in order
var childSchema = new mongoose.Schema({ name: 'string' });

childSchema.pre('validate', function(next) {
  console.log('2');
  next();
});

childSchema.pre('save', function(next) {
  console.log('3');
  next();
});

var parentSchema = new mongoose.Schema({
  child: childSchema,
    });
    
parentSchema.pre('validate', function(next) {
  console.log('1');
  next();
});

parentSchema.pre('save', function(next) {
  console.log('4');
  next();
});


```

Finding a sub-document
----------------------


Each subdocument has an `_id` by default. Mongoose document arrays have a special [id](api#types_documentarray_MongooseDocumentArray-id) method for searching a document array to find a document with a given `_id`.



```
var doc = parent.children.id(_id);

```

Adding sub-docs to arrays
-------------------------


MongooseArray methods such as [push](api#types_array_MongooseArray.push), [unshift](api#types_array_MongooseArray.unshift), [addToSet](api#types_array_MongooseArray.addToSet), and others cast arguments to their proper types transparently:



```
var Parent = mongoose.model('Parent');
var parent = new Parent;

// create a comment
parent.children.push({ name: 'Liesl' });
var subdoc = parent.children[0];
console.log(subdoc) // { \_id: '501d86090d371bab2c0341c5', name: 'Liesl' }
subdoc.isNew; // true

parent.save(function (err) {
  if (err) return handleError(err)
  console.log('Success!');
});
```

Sub-docs may also be created without adding them to the array by using the [create](api#types_documentarray_MongooseDocumentArray.create) method of MongooseArrays.



```
var newdoc = parent.children.create({ name: 'Aaron' });

```

Removing subdocs
----------------


Each subdocument has it's own [remove](api#types_embedded_EmbeddedDocument-remove) method. For an array subdocument, this is equivalent to calling `.pull()` on the subdocument. For a single nested subdocument, `remove()` is equivalent to setting the subdocument to `null`.



```
// Equivalent to `parent.children.pull(\_id)`
parent.children.id(_id).remove();
// Equivalent to `parent.child = null`
parent.child.remove();
parent.save(function (err) {
  if (err) return handleError(err);
  console.log('the subdocs were removed');
});

```

#### Alternate declaration syntax for arrays


If you create a schema with an array of objects, mongoose will automatically convert the object to a schema for you:



```
var parentSchema = new Schema({
  children: [{ name: 'string' }]
});
// Equivalent
var parentSchema = new Schema({
  children: [new Schema({ name: 'string' })]
});

```

Next Up
-------


Now that we've covered `Sub-documents`, let's take a look at [querying](queries).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/subdocs.html>

Population
==========


MongoDB has the join-like [$lookup](https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/) aggregation operator in versions >= 3.2. Mongoose has a more powerful alternative called `populate()`, which lets you reference documents in other collections.

 Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). We may populate a single document, multiple documents, plain object, multiple plain objects, or all objects returned from a query. Let's look at some examples.



```
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var personSchema = Schema({
  _id: Schema.Types.ObjectId,
  name: String,
  age: Number,
  stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
  author: { type: Schema.Types.ObjectId, ref: 'Person' },
  title: String,
  fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});

var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
```

So far we've created two [Models](models). Our `Person` model has its `stories` field set to an array of `ObjectId`s. The `ref` option is what tells Mongoose which model to use during population, in our case the `Story` model. All `_id`s we store here must be document `_id`s from the `Story` model.


**Note**: `ObjectId`, `Number`, `String`, and `Buffer` are valid for use as refs. However, you should use `ObjectId` unless you are an advanced user and have a good reason for doing so.


Saving refs
-----------


Saving refs to other documents works the same way you normally save properties, just assign the `_id` value:



```
var author = new Person({
  _id: new mongoose.Types.ObjectId(),
  name: 'Ian Fleming',
  age: 50
});

author.save(function (err) {
  if (err) return handleError(err);
  
  var story1 = new Story({
    title: 'Casino Royale',
    author: author._id    // assign the \_id from the person
  });
  
  story1.save(function (err) {
    if (err) return handleError(err);
    // thats it!
  });
});
```

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 `author` using the query builder:



```
Story.
  findOne({ title: 'Casino Royale' }).
  populate('author').
  exec(function (err, story) {
    if (err) return handleError(err);
    console.log('The author is %s', story.author.name);
    // prints "The author is Ian Fleming"
  });
```

Populated paths are no longer set to their original `_id` , their value is replaced with the mongoose document returned from the database by performing a separate query before returning the results.

 Arrays of refs work the same way. Just call the [populate](api#query_Query-populate) method on the query and an array of documents will be returned *in place* of the original `_id`s.


**Note**: mongoose >= 3.6 exposes the original `_ids` used during population through the [document#populated()](api#document_Document-populated) method.


Setting Populated Fields
------------------------


In Mongoose >= 4.0, you can manually populate a field as well.



```
Story.findOne({ title: 'Casino Royale' }, function(error, story) {
  if (error) {
    return handleError(error);
  }
  story.author = author;
  console.log(story.author.name); // prints "Ian Fleming"
});
```

Note that this only works for single refs. You currently **can't** manually populate an array of refs.


Field selection
---------------


What if we only want a few specific fields returned for the populated documents? This can be accomplished by passing the usual [field name syntax](api#query_Query-select) as the second argument to the populate method:



```
Story.
  findOne({ title: /casino royale/i }).
  populate('author', 'name'). // only return the Persons name
  exec(function (err, story) {
    if (err) return handleError(err);
    
    console.log('The author is %s', story.author.name);
    // prints "The author is Ian Fleming"
    
    console.log('The authors age is %s', story.author.age);
    // prints "The authors age is null'
  })
```

Populating multiple paths
-------------------------


What if we wanted to populate multiple paths at the same time?



```
Story.
  find(...).
  populate('fans').
  populate('author').
  exec()
```

If you call `populate()` multiple times with the same path, only the last one will take effect.



```
// The 2nd `populate()` call below overwrites the first because they
// both populate 'fans'.
Story.
  find().
  populate({ path: 'fans', select: 'name' }).
  populate({ path: 'fans', select: 'email' });
// The above is equivalent to:
Story.find().populate({ path: 'fans', select: 'email' });
```

Query conditions and other options
----------------------------------


What if we wanted to populate our fans array based on their age, select just their names, and return at most, any 5 of them?



```
Story.
  find(...).
  populate({
    path: 'fans',
    match: { age: { $gte: 21 }},
    // Explicitly exclude `\_id`, see http://bit.ly/2aEfTdB
    select: 'name -\_id',
    options: { limit: 5 }
  }).
  exec()
```

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' onto `author.stories`.

 There are two perspectives here. First, you may want the `author` know which stories are theirs. Usually, your schema should resolve one-to-many relationships by having a parent pointer in the 'many' side. But, if you have a good reason to want an array of child pointers, you can `push()` documents onto the array as shown below.



```
author.stories.push(story1);
author.save(callback);
```

This allows us to perform a `find` and `populate` combo:



```
Person.
  findOne({ name: 'Ian Fleming' }).
  populate('stories'). // only works if we pushed refs to children
  exec(function (err, person) {
    if (err) return handleError(err);
    console.log(person);
  });
```

It is debatable that we really want two sets of pointers as they may get out of sync. Instead we could skip populating and directly `find()` the stories we are interested in.



```
Story.
  find({ author: author._id }).
  exec(function (err, stories) {
    if (err) return handleError(err);
    console.log('The stories are an array: ', stories);
  });
  
```

The documents returned from [query population](api#query_Query-populate) become fully functional, `remove`able, `save`able documents unless the [lean](api#query_Query-lean) option is specified. Do not confuse them with [sub docs](subdocs). Take caution when calling its remove method because you'll be removing it from the database, not just the array.


Populating an existing document
-------------------------------


If we have an existing mongoose document and want to populate some of its paths, **mongoose >= 3.6** supports the [document#populate()](api#document_Document-populate) method.


Populating multiple existing documents
--------------------------------------


If we have one or many mongoose documents or even plain objects (*like [mapReduce](api#model_Model.mapReduce) output*), we may populate them using the [Model.populate()](api#model_Model.populate) method available in **mongoose >= 3.6**. This is what `document#populate()` and `query#populate()` use to populate documents.


Populating across multiple levels
---------------------------------


Say you have a user schema which keeps track of the user's friends.



```
var userSchema = new Schema({
  name: String,
  friends: [{ type: ObjectId, ref: 'User' }]
});
```

Populate lets you get a list of a user's friends, but what if you also wanted a user's friends of friends? Specify the `populate` option to tell mongoose to populate the `friends` array of all the user's friends:



```
User.
  findOne({ name: 'Val' }).
  populate({
    path: 'friends',
    // Get friends of friends - populate the 'friends' array for every friend
    populate: { path: 'friends' }
  });
  
```

Populating across Databases
---------------------------


Let's say you have a schema representing events, and a schema representing conversations. Each event has a corresponding conversation thread.



```
var eventSchema = new Schema({
  name: String,
  // The id of the corresponding conversation
  // Notice there's no ref here!
  conversation: ObjectId
});
var conversationSchema = new Schema({
  numMessages: Number
});
```

Also, suppose that events and conversations are stored in separate MongoDB instances.



```
var db1 = mongoose.createConnection('localhost:27000/db1');
var db2 = mongoose.createConnection('localhost:27001/db2');

var Event = db1.model('Event', eventSchema);
var Conversation = db2.model('Conversation', conversationSchema);
```

In this situation, you will **not** be able to `populate()` normally. The `conversation` field will always be null, because `populate()` doesn't know which model to use. However, [you can specify the model explicitly](api#model_Model.populate).



```
Event.
  find().
  populate({ path: 'conversation', model: Conversation }).
  exec(function(error, docs) { /\* ... \*/ });
```

This is known as a "cross-database populate," because it enables you to populate across MongoDB databases and even across MongoDB instances.


Dynamic References
------------------


Mongoose can also populate from multiple collections at the same time. Let's say you have a user schema that has an array of "connections" - a user can be connected to either other users or an organization.



```
var userSchema = new Schema({
  name: String,
  connections: [{
    kind: String,
    item: { type: ObjectId, refPath: 'connections.kind' }
  }]
});

var organizationSchema = new Schema({ name: String, kind: String });

var User = mongoose.model('User', userSchema);
var Organization = mongoose.model('Organization', organizationSchema);
```

The `refPath` property above means that mongoose will look at the `connections.kind` path to determine which model to use for `populate()`. In other words, the `refPath` property enables you to make the `ref` property dynamic.



```
// Say we have one organization:
// `{ \_id: ObjectId('000000000000000000000001'), name: "Guns N' Roses", kind: 'Band' }`
// And two users:
// {
// \_id: ObjectId('000000000000000000000002')
// name: 'Axl Rose',
// connections: [
// { kind: 'User', item: ObjectId('000000000000000000000003') },
// { kind: 'Organization', item: ObjectId('000000000000000000000001') }
// ]
// },
// {
// \_id: ObjectId('000000000000000000000003')
// name: 'Slash',
// connections: []
// }
User.
  findOne({ name: 'Axl Rose' }).
  populate('connections.item').
  exec(function(error, doc) {
    // doc.connections[0].item is a User doc
    // doc.connections[1].item is an Organization doc
  });
  
```

Populate Virtuals
-----------------


*New in 4.5.0*

 So far you've only populated based on the `_id` field. However, that's sometimes not the right choice. In particular, [arrays that grow without bound are a MongoDB anti-pattern](https://docs.mongodb.com/manual/tutorial/model-referenced-one-to-many-relationships-between-documents/). Using mongoose virtuals, you can define more sophisticated relationships between documents.



```
var PersonSchema = new Schema({
  name: String,
  band: String
});

var BandSchema = new Schema({
  name: String
});
BandSchema.virtual('members', {
  ref: 'Person', // The model to use
  localField: 'name', // Find people where `localField`
  foreignField: 'band', // is equal to `foreignField`
  // If `justOne` is true, 'members' will be a single doc as opposed to
  // an array. `justOne` is false by default.
  justOne: false
});

var Person = mongoose.model('Person', PersonSchema);
var Band = mongoose.model('Band', BandSchema);

/\*\*
 \* Suppose you have 2 bands: "Guns N' Roses" and "Motley Crue"
 \* And 4 people: "Axl Rose" and "Slash" with "Guns N' Roses", and
 \* "Vince Neil" and "Nikki Sixx" with "Motley Crue"
 \*/
Band.find({}).populate('members').exec(function(error, bands) {
  /\* `bands.members` is now an array of instances of `Person` \*/
});

```

Keep in mind that virtuals are *not* included in `toJSON()` output by default. If you want populate virtuals to show up when using functions that rely on `JSON.stringify()`, like Express' [`res.json()` function](http://expressjs.com/en/4x/api.html#res.json), set the `virtuals: true` option on your schema's `toJSON` options.



```
// Set `virtuals: true` so `res.json()` works
var BandSchema = new Schema({
  name: String
}, { toJSON: { virtuals: true } });

```

If you're using populate projections, make sure `foreignField` is included in the projection.



```
Band.
  find({}).
  populate({ path: 'members', select: 'name' }).
  exec(function(error, bands) {
    // Won't work, foreign field `band` is not selected in the projection
  });
  
Band.
  find({}).
  populate({ path: 'members', select: 'name band' }).
  exec(function(error, bands) {
    // Works, foreign field `band` is selected
  });
  
```

Next Up
-------


Now that we've covered query population, let's take a look at [connections](../../connections).



 © 2010 LearnBoost  
Licensed under the MIT License.  

<https://mongoosejs.com/docs/4.x/docs/populate.html>

mongoose