Es6 static call non static hướng dẫn

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

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 method.

Each key in our code


// 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']];

6 defines a property in our documents which will be cast to its associated . For example, we've defined a property


// 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']];

7 which will be cast to the SchemaType and property


// 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']];

8 which will be cast to a


// 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']];

9 SchemaType.

Notice above that if a property only requires a type, it can be specified using a shorthand notation [contrast the


// 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']];

7 property above with the


// 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']];

8 property].

Keys may also be assigned nested objects containing further key/type definitions like the


// 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];
}];

2 property above. This will happen whenever a key's value is a POJO that doesn't have a


// 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];
}];

3 property.

In these cases, Mongoose only creates actual schema paths for leaves in the tree. [like


// 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];
}];

4 and


// 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];
}];

5 above], and the branches do not have actual paths. A side-effect of this is that


// 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];
}];

2 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 section for more information on how to do this. Also read the Mixed subsection of the SchemaTypes guide for some gotchas.

The permitted SchemaTypes are:

Read more about SchemaTypes here.

Schemas not only define the structure of your document and casting of properties, they also define document , , , and document lifecycle hooks called middleware.

To use our schema definition, we need to convert our


// 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']];

6 into a Model we can work with. To do so, we pass it into


// 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];
}];

8:

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

By default, Mongoose adds an


// 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];
}];

9 property to your schemas.

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

When you create a new document with the automatically added


// 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];
}];

9 property, Mongoose creates a new


// 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];
}];

9 of type 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


// 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];
}];

9 with your own


// 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];
}];

9. Just be careful: Mongoose will refuse to save a document that doesn't have an


// 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];
}];

9, so you're responsible for setting


// 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];
}];

9 if you define your own


// 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];
}];

9 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

Instances of

const animalSchema = new Schema[{
  name: String,
  type: String,
  tags: { type: [String], index: true } // path level
}];
animalSchema.index[{ name: 1, type: -1 }]; // schema level

7 are documents. Documents have many of their own built-in instance methods. 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

const animalSchema = new Schema[{
  name: String,
  type: String,
  tags: { type: [String], index: true } // path level
}];
animalSchema.index[{ name: 1, type: -1 }]; // schema level

8 instances have a

const animalSchema = new Schema[{
  name: String,
  type: String,
  tags: { type: [String], index: true } // path level
}];
animalSchema.index[{ name: 1, type: -1 }]; // schema level

9 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 for more details.
  • The example above uses the

    const Blog = mongoose.model['Blog', blogSchema]; // ready to go!

    00 object directly to save an instance method. You can also use the

    const Blog = mongoose.model['Blog', blogSchema]; // ready to go!

    01 helper as described .
  • Do not declare methods using ES6 arrow functions [

    const Blog = mongoose.model['Blog', blogSchema]; // ready to go!

    02]. Arrow functions , so your method will not have access to the document and the above examples will not work.

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 [

    const Blog = mongoose.model['Blog', blogSchema]; // ready to go!

    04]
  • Add a function property to

    const Blog = mongoose.model['Blog', blogSchema]; // ready to go!

    05
  • Call the


// 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 [

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

02]. Arrow functions , so the above examples will not work because of the value of

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

03.

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.


// 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];
}];

MongoDB supports secondary indexes. With mongoose, we define these indexes within our

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

10 or the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

11 level. Defining indexes at the schema level is necessary when creating compound indexes.

const animalSchema = new Schema[{
  name: String,
  type: String,
  tags: { type: [String], index: true } // path level
}];
animalSchema.index[{ name: 1, type: -1 }]; // schema level

See for other index options.

When your application starts up, Mongoose automatically calls for each defined index in your schema. Mongoose will call

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

12 for each index sequentially, and emit an 'index' event on the model when all the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

12 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 . Disable the behavior by setting the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

15 option of your schema to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

16, or globally on the connection by setting the option

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

15 to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

16.

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

0

Mongoose will emit an

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

19 event on the model when indexes are done building or an error occurred.

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

1

See also the method.

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.

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

2

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

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

3

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? A lets you define a

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

20 property that won't get persisted to MongoDB.

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

4

Now, mongoose will call your getter function every time you access the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

20 property:

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

5

If you use

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

22 or

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

23 Mongoose will not include virtuals by default. Pass

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

24 to or

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

23 to include virtuals.

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

6

The above caveat for

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

22 also includes the output of calling

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

28 on a Mongoose document, because . To include virtuals in

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

28 output, you can either call

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

32 on the document before calling

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

28, or set the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

34 option on your schema.

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

7

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

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

20 virtual.

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

8

Virtual property setters are applied before other validation. So the example above would still work even if the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

36 and

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

37 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.

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 Blog = mongoose.model['Blog', blogSchema];
// ready to go!

9

You can also declare aliases on nested paths. It is easier to use nested schemas and subdocuments, but you can also declare nested path aliases inline as long as you use the full nested path

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

38 as the alias.

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

0

Schemas have a few configurable options which can be passed to the constructor or to the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

39 method:

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

1

Valid options:

By default, Mongoose's creates all the indexes defined in your model's schema by calling 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

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

15 to false.

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

2

The

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

15 option is set to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

44 by default. You can change this default by setting

Before Mongoose builds indexes, it calls

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

46 to create the underlying collection in MongoDB by default. Calling

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

47 sets the collection's default collation based on the and establishes the collection as a capped collection if you set the .

You can disable this behavior by setting

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

49 to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

16 using . Like

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

15,

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

49 is helpful for development and test environments, but you may want to disable it for production to avoid unnecessary database calls.

Unfortunately,

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

47 cannot change an existing collection. For example, if you add

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

55 to your schema and the existing collection is not capped,

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

47 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[];
schema.path['_id']; // ObjectId { ... }

3

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

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

57 to false.

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

4

The schema

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

57 option overrides the global

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

57 option.

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

5

If

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

57 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].

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

6

Mongoose supports MongoDBs capped collections. To specify the underlying MongoDB collection be

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

48, set the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

48 option to the maximum size of the collection in .

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

7

The

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

48 option may also be set to an object if you want to pass additional options like . In this case you must explicitly pass the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

64 option, which is required.

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

8

Mongoose by default produces a collection name by passing the model name to the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

65 method. This method pluralizes the name. Set this option if you need a different name for your collection.

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

9

When you define a discriminator, Mongoose adds a path to your schema that stores which discriminator a document is an instance of. By default, Mongoose adds an

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

66 path, but you can set

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

67 to overwrite this default.

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

0

When

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

68 is

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

44, 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

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

16.

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

1

Mongoose assigns each of your schemas an

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

71 virtual getter by default which returns the document's


// 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];
}];

9 field cast to a string, or in the case of ObjectIds, its hexString. If you don't want an

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

71 getter added to your schema, you may disable it by passing this option at schema construction time.

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

2

Mongoose assigns each of your schemas an


// 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];
}];

9 field by default if one is not passed into the constructor. The type assigned is an to coincide with MongoDB's default behavior. If you don't want an


// 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];
}];

9 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


// 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];
}];

9.

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

3

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

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

4

This behavior can be overridden by setting

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

77 option to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

16. It will then store empty objects.

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

5

To check whether an object is empty, you can use the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

79 helper:

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

6

Allows setting options at the schema level, providing us a way to apply default to all queries derived from a model.

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

7

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 from which members of the replica-set it should attempt to read. Read more about tag sets and here.

NOTE: you may also specify the driver read preference option when connecting:

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

8

Allows setting write concern at the schema level.

const Model = mongoose.model['Test', schema];
const doc = new Model[];
doc._id instanceof mongoose.Types.ObjectId; // true

9

The

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

80 option is used when we have a sharded MongoDB architecture. 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.

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

0

Note that Mongoose does not send the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

81 command for you. You must configure your shards yourself.

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

1

This also affects the use of

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

82 to set a property value.

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

2

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

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

3

The

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

83 option may also be set to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

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

4

Mongoose supports a separate

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

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

5

The

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

83 option does apply to updates. The

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

85 option is just for query filters.

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

6

Mongoose has a separate

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

85 option to toggle strict mode for the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

89 parameter to queries.

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

7

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

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

8

In Mongoose 7,

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

85 is

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

16 by default. However, you can override this behavior globally:

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

9

Exactly the same as the option but only applies when the document's

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

92 method is called.

// 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];
};

0

To see all available

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

93 options, read .

Documents have a 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

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

94 output, set the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

95 option to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

96:

// 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];
};

1

To see all available

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

95 options, read .

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

// 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];
};

2

However, for applications like geoJSON, the 'type' property is important. If you want to control which key mongoose uses to find type declarations, set the 'typeKey' schema option.

// 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];
};

3

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

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

98 to false.

// 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];
};

4

The

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

99 is a property set on each document when first created by Mongoose. This keys value contains the internal revision of the document. The

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

99 option is a string that represents the path to use for versioning. The default is

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

01. If this conflicts with your application you can configure as such:

// 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];
};

5

Note that Mongoose's default versioning is not a full optimistic concurrency solution. Mongoose's default versioning only operates on arrays as shown below.

// 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];
};

6

If you need optimistic concurrency support for

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

02, you can set the

Document versioning can also be disabled by setting the

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

99 to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

16. DO NOT disable versioning unless you know what you are doing.

// 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];
};

7

Mongoose only updates the version key when you use . If you use

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

07,

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

08, etc. Mongoose will not update the version key. As a workaround, you can use the below middleware.

// 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];
};

8

Optimistic concurrency is a strategy to ensure the document you're updating didn't change between when you loaded it using

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

09 or

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

10, and when you update it using

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

02.

For example, suppose you have a

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

12 model that contains a list of

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

13, and a

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

14 that represents whether this house shows up in searches. Suppose that a house that has status

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

15 must have at least two

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

13. You might implement the logic of approving a house document as shown below:

// 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];
};

9

The

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

17 function looks right in isolation, but there might be a potential issue: what if another function removes the house's photos between the

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

10 call and the

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

02 call? For example, the below code will succeed:

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

0

If you set the

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

03 option on the

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

12 model's schema, the above script will throw an error.

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

1

Sets a default collation for every query and aggregation. Here's a beginner-friendly overview of collations.

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

2

If you set the

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

22 option on a schema, Mongoose will create a timeseries collection for any model that you create from that schema.

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

3

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

23 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.

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

4

The

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

24 option tells Mongoose to assign

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

25 and

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

26 fields to your schema. The type assigned is .

By default, the names of the fields are

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

25 and

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

26. Customize the field names by setting

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

29 and

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

30.

The way

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

24 works under the hood is:

  • If you create a new document, mongoose simply sets

    const schema = new Schema[]; schema.path['_id']; // ObjectId { ... }

    25, and

    const schema = new Schema[]; schema.path['_id']; // ObjectId { ... }

    26 to the time of creation.
  • If you update a document, mongoose will add

    const schema = new Schema[]; schema.path['_id']; // ObjectId { ... }

    26 to the

    const schema = new Schema[]; schema.path['_id']; // ObjectId { ... }

    35 object.
  • If you set

    const schema = new Schema[]; schema.path['_id']; // ObjectId { ... }

    36 on an update operation, mongoose will use

    const schema = new Schema[]; schema.path['_id']; // ObjectId { ... }

    37 operator to add

    const schema = new Schema[]; schema.path['_id']; // ObjectId { ... }

    25 to the document in case the

    const schema = new Schema[]; schema.path['_id']; // ObjectId { ... }

    39 operation resulted into a new inserted document.

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

5

By default, Mongoose uses

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

40 to get the current time. If you want to overwrite the function Mongoose uses to get the current time, you can set the

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

41 option. Mongoose will call the

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

41 function whenever it needs to get the current time.

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

6

Mongoose supports defining global plugins, plugins that apply to all schemas.

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

7

Sometimes, you may only want to apply a given plugin to some schemas. In that case, you can add

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

43 to a schema:

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

8

If you call

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

44 with a

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

45 option, Mongoose will only apply that plugin to schemas that have a matching entry in

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

43.

const Animal = mongoose.model['Animal', animalSchema];
const dog = new Animal[{ type: 'dog' }];
dog.findSimilarTypes[[err, dogs] => {
  console.log[dogs]; // woof
}];

9

By default, Mongoose will automatically

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

47 any populated paths for you, unless you explicitly exclude them.


// 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']];

0

To opt out of selecting populated fields by default, set

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

48 to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

16 in your schema.


// 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']];

1

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:


// 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']];

2

Set the

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

50 to

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

16 on the child schema to make Mongoose only reports the parent error.


// 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']];

3

Options like and affect the options Mongoose passes to MongoDB when creating a new collection. Mongoose schemas support most MongoDB

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

47 options, but not all. You can use the

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

55 option to set any

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

47 options; Mongoose will use

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

55 as the default values when calling

const Blog = mongoose.model['Blog', blogSchema];
// ready to go!

47 for your schema.


// 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']];

4

Schemas have a that you can use to create a Mongoose schema from an ES6 class:

  • become
  • become
  • become Mongoose virtuals

Here's an example of using

const schema = new Schema[];
schema.path['_id']; // ObjectId { ... }

59 to create a schema from an ES6 class:


// 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']];

5

Schemas are also pluggable which allows us to package up reusable features into plugins that can be shared with the community or just between your projects.

Here's an alternative introduction to Mongoose schemas.

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, whereas MongoDB schema design is about making common queries as fast as possible. The 6 Rules of Thumb for MongoDB Schema Design blog series 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 by Christian Kvalheim, the original author of the MongoDB Node.js driver. This book shows you how to implement performant schemas for a laundry list of use cases, including e-commerce, wikis, and appointment bookings.

Chủ Đề