# Mongoose

# Schema Types

`SchemaType`s take care of validation, casting, defaults, and other general options in our models. We can specify our types one of two ways:

    // directly without options
    var Person = new Schema({
        title   : String
    });

    // or with options
    var Person = new Schema({
        title   : { type: String, lowercase: true }
    });

In the example above we specified the `lowercase` option for strings which will lowercase the string whenever it is set. Options are functions that are called on each SchemaType. Each `SchemaType` has its own set of custom options.

## Available Schema Types

### String

- `lowercase`: {Boolean}

  Creates a setter which calls `.toLowerCase()` on the value

- `uppercase`: {Boolean}

  Creates a setter which calls `.toUpperCase()` on the value

- `trim`: {Boolean}

  Creates a setter which calls `.trim()` on the value

- `match`: {RegExp}

  Creates a RegExp based validator. The value being set is `.test()`ed against the RegExp. If it does not pass, validation will fail.

- `enum`: {Array}

  Creates an enum validator. If the value being set is not in this array, validation will fail.

### Number

- `min`: {Number}

  Creates a validator which checks that the value being set is not less than the value specified.

- `max`: {Number}

  Creates a validator which checks that the value being set is not greater than the value specified.

### Date

- no custom options

### Boolean

- no custom options

### Buffer (v2.x only)

- no custom options

### ObjectId

To specify a type of `ObjectId`, use `Schema.ObjectId` in your declaration.

    var mongoose = require('mongoose');
    var Schema = mongoose.Schema;
    var Car = new Schema({ driver: Schema.ObjectId })

- no custom options

### 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: 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/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

- no custom options

### Array

Creates an array of `SchemaTypes` or Embedded Documents.

    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: [{}] });

- no custom options

## Additional options

Besides the options listed above, all SchemaTypes share the following additional options.

- `default`: {Function|value} - Determines the default value for the path. All values are casted. If using a function, the value it returns will be casted as the default value.

- `required`: {Boolean} - If true, creates a validation rule requiring this path be set before saving occurs.

- `select`: {Boolean} - Specifies default path selection behavior. In other words, you can specify if this path should be included or excluded from query results by default.

      // Excluding `bio` from query results by default

      var Person = new Schema({ bio: { type: String, select: false }})
      var P = db.model('Person', Person);
      P.findOne(function (err, p) {
        console.log(p.bio) // undefined
      });

      // Including `name` in query results by default

      var Person = new Schema({
          name: { type: String, select: true }
        , age: Number
      })

      var P = db.model('Person', Person);
      P.findOne().select('age').exec(function (err, p) {
        console.log(p.isSelected('age'))  // true
        console.log(p.isSelected('name')) // true
      });

      // can also be overridden on a query by query basis

      var Person = new Schema({ bio: { type: String, select: false }})
      var P = db.model('Person', Person);
      P.findOne().select('bio').exec(callback); // bio will be selected

- `get`: {Function} - Adds a getter for this path. See the getters / setters docs for more detail.

- `set`: {Function} - Adds a setter for this path. See the getters / setters docs for more detail.

- `index`: {Boolean|Object} - Tells Mongoose to ensure an index is created for this path. An object can be passed as well.

      var Person = new Schema({ name: { type: String, index: true }})

      var name = { type: String, index: { unique: true }}
      var Person = new Schema({ name: name })

  Note: if the index already exists on the db, it will not be replaced.

- `unique`: {Boolean} - Tells Mongoose to ensure a unique index is created for this path. The following are equivalent:

      var Person = new Schema({ name: { type: String, unique: true }})

      var name = { type: String, index: { unique: true }}
      var Person = new Schema({ name: name })

  Note: if the index already exists on the db, it will not be replaced.

- `sparse`: {Boolean} - Tells Mongoose to ensure a sparse index is created for this path. The following are equivalent:

      var Person = new Schema({ name: { type: String, sparse: true }})

      var name = { type: String, index: { sparse: true }}
      var Person = new Schema({ name: name })

  Note: if the index already exists on the db, it will not be replaced.

- `validate`: {Function|RegExp|Array} - Creates a validator for this path.

      // passing a function
      function hasNumber (v) {
        return v.length && /\d/.test(v);
      }
      var street = { type: String, validate: hasNumber }
      var Person = new Schema({ street: street });

      // passing a RegExp
      var street = { type: String, validate: /\d/ }
      var Person = new Schema({ street: street });

      // passing an array
      var street = {
          type: String
        , validate: [hasNumber, 'street number required']
      }
      var Person = new Schema({ street: street })

      // or
      var street = {
          type: String
        , validate: [/\d/, 'street number required']
      }
      var Person = new Schema({ street: street });

  For more detail about validation including async validation, see the validation page.

## Alternate options definition

Instead of defining options when instanciating your `Schema` we can also access keys through the `path` function and add options there:

    Person.path('age').max(400);

    Person.path('meta.birth').set(function (v) {
      // this is a setter
    });

    Person.path('title').validate(function (v) {
      return v.length > 50;
    });