An Introduction to Mongoose SchemaTypes

May 20, 2020

In Mongoose, a SchemaType is a configuration object for a single path within a schema. A SchemaType says what type the path should be, how to validate that path, what the default value for the path is, and other Mongoose-specific config options.

const schema = Schema({ name: String, age: Number });

schema.path('name') instanceof mongoose.SchemaType; // true
schema.path('age') instanceof mongoose.SchemaType; // true

The SchemaType class is just a base class. There are several classes that inherit from SchemaType that represent different core Mongoose Types:

For example:

const schema = Schema({ name: String, age: Number });

schema.path('name') instanceof mongoose.SchemaType; // true
schema.path('name') instanceof mongoose.Schema.Types.String; // true

schema.path('age') instanceof mongoose.SchemaType; // true
schema.path('age') instanceof mongoose.Schema.Types.Number; // true

Working With SchemaTypes

You normally don't have to work with SchemaType instances directly. You can declare validators and defaults in your schema definition. For example, the below example sets the default age to 25 and adds a validator that ensures age is at least 21.

const schema = Schema({
  age: {
    type: Number,
    default: 25,
    validate: v => v >= 21
  }
});

The above is how you normally declare defaults and validators in Mongoose. But there's nothing stopping you from adding them on the age SchemaType after creating your schema.

// Equivalent:
const schema = Schema({ age: Number });

schema.path('age').default(25);
schema.path('age').validate(v => v >= 21);

The latter syntax is equivalent to the former, but isn't commonly used. The most common case for working with SchemaType instances directly is with embedded discriminators.

For example, suppose you have an Order schema, and an Order has an embedded list of products. Each product may be a book, computer, or something else, and each type of product can have different properties. Embedded discriminators let an array store subdocuments that conform to different schemas based on each subdocument's __t property.

const productSchema = new Schema({
  imageURL: String,
  name: String
}, { discriminatorKey: '__t' });

const bookSchema = new Schema({
  author: String
});

const computerSchema = new Schema({
  ramGB: Number
});

const orderSchema = new Schema({
  createdAt: Date,
  product: [productSchema]
});

// Add discriminators to the `products` SchemaType.
orderSchema.path('products').discriminator('Book', bookSchema);
orderSchema.path('products').discriminator('Computer', computerSchema);

const Order = mongoose.model('Order', orderSchema);

Want to become your team's MongoDB expert? "Mastering Mongoose" distills 8 years of hard-earned lessons building Mongoose apps at scale into 153 pages. That means you can learn what you need to know to build production-ready full-stack apps with Node.js and MongoDB in a few days. Get your copy!

Did you find this tutorial useful? Say thanks by starring our repo on GitHub!

More Mongoose Tutorials