MongoDB & Mongoose in Node.js— a quick start guide

Ciaran Morinan
5 min readNov 13, 2018

I recently got to grips with interacting with MongoDB via the Mongoose library in Node.JS. That sentence is more of an ordeal than the actual process, which is straightforward enough — if you follow this handy guide!

My point of reference was Ruby and ActiveRecord, and I will point our parallels where I see them. First, the basics:

  • Node.JS allows you to execute JavaScript outside of a web browser and take advantage of its asynchronous functions, e.g. to run a server.
  • MongoDB is a NoSQL database, in which records (known as documents) are JSON-like objects rather than rows in a table, and which doesn’t enforce any particular structure for each document by default.
  • Mongoose is an ODM (Object Data Modelling) library, designed to make it easier to translate between your code and your database, as ActiveRecord does for relational databases.

Terminology / vocabulary

MongoDB doesn’t have the tables, columns and rows of a relational database, and comes with new vocabulary. This isn’t standard across different types of NoSQL databases, but for MongoDB specifically the key terms are:

  • collection: equivalent of a table — a store of information on different items representing a particular kind of entity or concept (e.g. user, book, song).
  • document: equivalent of a row one record in a collection, containing information about a specific item.
  • field: equivalent of a column — a key-value pair in a document, containing information about one particular attribute of an item.

Document basics

Documents are represented as BSON objects (binary JSON). The value of fields can be any valid data type, including other documents.

A document in the user collection might look like this:

{
name: { first: 'Bob', second: 'the Builder' },
age: 35,
_id: ObjectID('507f191e810c19729de860ea')
}

The _id field is reserved for use as the primary, unique key identifying a document. MongoDB will automatically assign one when the document is created if you don’t assign one yourself. They are always a 12-byte value, commonly represented by 24 hexadecimal characters (as above).

The first four bytes represent a timestamp of when the document was created, which you can grab by calling ObjectID('the_id').getTimeStamp().

Installing MongoDB

To develop you’ll need to install and run MongoDB locally. Instructions here:

You’ll need the Mongo daemon — the mongod file mentioned in the above instructions— running whenever you want to interact with your database. It’s a pain to type the whole path to it each time, so you may want to add it to your .bash_profile file to allow you to call it by just typing mongod anywhere, by inserting something like the following line to ~/.bash_profile

export PATH=/Users/$USER/mongo/bin:$PATH

With mongod successfully running (don’t forget to create data folder it will look for— read the instructions!), you can now connect to your database, by default on port 27017. At this point you might want to also pick up Robo3T, which will allow you to connect to your database and view and manipulate documents without writing code.

Now we can finally start writing JavaScript! We’ll be interfacing with the database via Mongoose, so npm install mongoose or yarn add mongoose depending on your package manager of choice.

Connecting Mongoose to your MongoDB database

You’ll need some boilerplate code to connect to your database:

A few notes on this:

  • mongoose supports Promises, and you can specify what Promise library you want it to use. Line 3 tells it to use native ES6 Promises.
  • Line 5 takes care of connecting to a MongoDB URI specified in an environment variable if one is set (e.g. if your app is deployed to Heroku), and otherwise will look for a database server running locally.
  • You will get an annoying warning on start-up if useNewUrlParser is not set.
  • I like to catch failed connections and exit for immediate feedback when I inevitably forget to run mongod before booting up the server.

Save that in a file and require('./path/to/file') it near the top of your code, and you will have a database connection to work with following it.

Schema and model design and validation

MongoDB doesn’t require structure for documents in the way that you have to specify the columns in an SQL database. There is no prior database creation or migration required — if you tell MongoDB to insert a document in a collection, it will happily do so without any set-up beforehand.

We can, however, impose a structure on our documents at the application layer (i.e. in Node.JS), and Mongoose makes this easy. We can declare schema with the fields we require or permit in documents in a collection, as we would in an SQL database migration, and specify validation.

We now have a User model we can call Mongoose operations and queries on. We can also build our own custom methods for models, in the same way that you’d specify class and instance methods in a Ruby model. After you’ve defined a schema but before you pass it to mongoose.model and export it, declare a class and methods:

Or you can directly attach new methods to a Schema if you prefer:

The full documentation for schema creation is here and is worth a read:

MongoDB also has more flexibility in how you define relationships between objects than a SQL database — a good primer on the options is here:

Mongoose operations and queries

Now we have a model to work with, we can start creating and manipulating them. Here are the basic CRUD operations:

The above operations are mostly confined to finding one document and updating it, but they have bulk equivalents like Model.update() and Model.remove() — the full documentation is here:

For detailed queries, it’s worth diving into the potential of Model.where and especiallyModel.aggregate, where you specify an ‘aggregation pipeline’ which can include matching records, grouping, sorting, and choosing how the final output is displayed (using $match, $group, $sort, and $project) … but that is straying well beyond the scope of a ‘quick start’ guide, so I will leave it here — I hope it was helpful!

--

--