Mongoose 4.0 brings some exciting new functionality: schema validation in the browser, query middleware, validation on update, and promises for async operations. In addition to these improvements, there are a few backwards breaking changes to be aware of when you choose to upgrade. The 3.8 branch will continue to be maintained until September 2015.

First, a note on versioning. As of 4.0, Mongoose will return to using semantic versioning rather than the even/odd versioning system that NodeJS and MongoDB use. The even/odd versioning caused a lot of confusion and made releases much larger than they had to be. Releases will be smaller and more focused going forward. Each Mongoose release after 4.0 will be considered production-ready, and there will be no more backwards-breaking changes until 5.0.

Backwards-Breaking Changes

  • #1323: CastError and ValidationError’s ‘type’ field has been renamed ‘kind’ to avoid interfering with V8’s usage of error.type.
  • #1349: setProfiling() was removed.
  • #1351: Document no longer inherits from EventEmitter. Documents still fulfill the NodeJS EventEmitter API through function wrappers, but Document instanceof EventEmitter is no longer true. This is to prevent users from accidentally clobbering EventEmitter internals by creating schema paths named “domain”, “_events”, etc.
  • #1530: If you set a field with the ‘ref’ property to a document whose model name is equal to the ‘ref’, mongoose will treat the field as if it were .populate()-ed.
  • #1594: If you set a field to undefined after you already set it, validators will no longer be run (except, of course, the required validator, if specified).
  • #1746: Model.create() will return a spread of documents if you pass it a spread, and an array if you pass it an array. In 3.8.x Model.create() always returned a spread.
  • #1892: Setters are now called even when the value is set to undefined
  • #2243: When you specify multiple validators on a field, they will now be run in the order specified, as opposed to reverse order.
  • #2262: The findOneAndUpdate(), findByIdAndUpdate(), etc. new option is now false by default. The MongoDB server assumes false by default, this change is so mongoose is more consistent with the server’s API.
  • #2306: If options.cursor is specified, aggregate.exec() will return a cursor and ignore any callback.
  • #2380: “save” and “validate” may no longer be schema path names.
  • #2552: Upgraded mongodb driver to 2.0.x. Mongoose is a wrapper layer on top of the MongoDB node driver. The mongodb driver recently released version 2.0, which includes numerous performance and usability improvements. The new driver, however, introduces a few changes that affect the way you use Mongoose:
  • #2589: validate() now collects all subdocument errors rather than stopping after the first subdocument errors out.
  • #2592: setting a nested path to a non-object value now triggers a CastError
  • #2611: validate() now checks for cast errors.
  • #2628: 3.x reversed the order for distinct() parameters in lib/query.js. For instance, you called distinct() on a model like so: Model.distinct(field, criteria, callback). But, if you were using a query instance, you had to reverse the field and criteria, for instance, Model.find().distinct(criteria, field, callback). 4.0 makes this order consistent, so you can use Model.find().distinct(field, criteria, callback).
  • #2698: Setters are now applied on paths with ref set
  • #2709: increment is now a reserved path
  • #2775: CastErrors are tracked on a per-path basis. If you set a path to a valid value, this will clear all CastErrors and any other calls to invalidate().
  • Array and DocumentArray are now functions that return an array, rather than constructors. For instance, new MongooseArray([]) instanceof MongooseArray is false in 4.0. To check whether an array is a MongooseArray, use the isMongooseArray and isMongooseDocumentArray properties. This is in order for Mongoose’s isomorphic component (see #2254) to support non-ES5 compatible browsers (such as IE8) without a shim.
  • #3763: limit() and skip() now require their input to be numbers. Mongoose 3.8 was already documented to require numbers here, but previously strings were accepted and cast to numbers. Passing numbers as strings will now throw a parse error.

New Features

  • #661: Can now specify validators for array elements
  • #860: You can optionally run validators and set defaults if a new document is created on update() and findOneAndUpdate() calls. In order to access these features, you must explicitly set the runValidators and setDefaultsOnInsert options when you call update() or findOneAndUpdate(). Note that the setDefaultsOnInsert option is not compatible with MongoDB <= 2.2. Further note update() and findOneAndUpdate() explicitly run validators with a null context (that is, this === null in the validator function).
  • #1401: You can add fields to text indexes in the field declaration itself.
  • #1416: You can now use properties named options in your schemas
  • #1967: findOneAndUpdate() now supports the strict option
  • #2138: Query middleware. You can now specify hooks like schema.pre('find') and schema.post('findOne').
  • #2177: Async operations return promises that are compatible with the yield keyword in ES6.
  • #2441: hooks no longer hangs when you return an error that isn’t of type Error.
  • #2494: You can pass a write concern to save().
  • #2531: You can now specify min and max validators for type: Date.
  • #2640: Ability to populate using different models
  • #2675: toObject() now has a versionKey option (true by default) that you can use to remove the version key from toObject() output
  • #2719: Populate() now can populate with discriminator child schema
  • Mongoose is now partially isomorphic. You can require('mongoose') in your Browserify-built applications or include a browser-friendly JS file with a script tag. The browser-side code is limited to Mongoose schema validation. Mongoose’s browser component is tested using SauceLabs on the browsers specified in karma.sauce.conf.js. In particular, Mongoose supports IE >= 9, Safari >= 6, mobile browsers, Chrome, and Firefox. Mongoose 4.0 is not expected to work on IE8.