Updated 9/21/15: This blog post is now outdated. We recommend upgrading your driver to the latest version of Mongoose. If you have any questions or difficulties, email us at email@example.com.
Many of the support requests we get at MongoLab are questions about how to properly configure and use particular MongoDB drivers and client libraries.
This blog post is the 2nd of a series where we are covering the popular MongoDB drivers in depth (we covered Mongoid last time). The driver we're covering today is Mongoose, which is maintained by Aaron Heckmann (@aaronheckmann) and officially supported by MongoDB, Inc.
In this post:
- A simple Mongoose example
- Production-ready connection settings
- Mongoose tips & tricks
- You're all set!
Mongoose is a Node.js Object Document Mapper (ODM). For relational folks, ODMs are the MongoDB equivalent of Object Relational Mappers (ORMs). One major reason developers use ODMs like Mongoose is that it gives them the ability to define a schema for their documents which can then be used to map documents to objects in their programming language. With Mongoose, this feature serves as an easy transition for former Ruby on Rails developers used to working with ActiveRecord.
Mongoose is written on top of the native Node.js MongoDB driver which is also officially supported by MongoDB, Inc. While Mongoose defines models and uses them to query, the native Node.js MongoDB provides a more traditional querying interface. We will cover this native driver in a future installment of this blog series.
This post aims to help you understand how to configure and use Mongoose effectively in your MongoDB application.
A simple Mongoose example
Production-ready connection settings
We often see that users have problems connecting to MongoLab using the Mongoose driver. The root cause is almost always incorrect configuration of the driver, particularly around timeouts. The following is a connection example using the MongoLab-recommended driver options:
Additional connection options that are supported by the underlying native Node.js driver can be found here.
Mongoose tips & tricks
Mongoose requires a different connection string format
Update 10/6/14: Depending on your Mongoose version, Mongoose accepts Standard URIs per https://github.com/LearnBoost/mongoose/issues/2246#issuecomment-58039780. It's unclear what version of the driver first implemented this change.
The Mongoose URI format follows the convention:
Notice that the database name is included with the first node. Also notice that every node requires the "mongodb://" prefix.
This format differs from MongoDB's standard connection string format which looks like:
Increase connection timeouts to mitigate errors
A common error that we see with the Mongoose driver is Mongo Connection error. For example:
Mongo Connection error: Error: No primary found in set
This error is thrown whenever Mongoose has difficulty making a connection. Depending on the type of connection being created by the driver (server or replica set), the default timeout value varies from 1 to 5 seconds. We often see that users who are running their app with a Platform-as-a-Service (PaaS), such as Heroku, will find that their driver needs longer to establish a connection to the database, particularly when dynos are just starting up. For this reason we recommend allowing up to 30 seconds for connections to become established.
New connections require the write lock; be careful with index builds
Update (5/21/14 10:34 AM): The MongoDB Node Native driver has pushed a fix for this issue in v1.4.5. We're unclear when this will be incorporated into the Mongoose driver, but will update accordingly.
In order to establish a connection to your MongoDB, the driver must first connect to and authenticate on all the replica set nodes. The authentication step requires the write lock to complete.
As of MongoDB 2.4.x, index builds on secondaries run in the foreground and hold the write lock. As a result, any connection attempting to authenticate (which requires the write lock) must wait until the index build is complete. To avoid unexpected errors, we recommend building indexes during off-peak times when the application can reuse existing connections that have already authenticated.
This behavior is slightly different from other drivers which can usually handle not being able to authenticate to the secondaries in the replica set cluster.
Properly configure application error handling
Node.js error handling can often be tricky. For newer developers, it's important to remember that most errors are returned through callbacks. You can handle errors in the callback, or you can consider passing them to a centralized framework by using the Node.js "next" callback convention offered to every Express route.
However, some errors happen outside of the context of an individual database operation. These errors e.g. connection errors, require handlers registered at a broader scope (the connection itself).
Aaron Heckmann, the core maintainer of the Mongoose project, provides some good advice on Mongoose and Express error handling in this StackOverflow thread.
You're all set!
We hope this post helps shed light on some things that are unique to Mongoose. If you have any tips and tricks that you'd like to share please post in comments or write to us at firstname.lastname@example.org so we can pass on the knowledge. Happy hacking!