An example of connecting to mongodb with the Monk NPM module.

monk’s github repo description says it all

The wise MongoDB API

A tiny layer that provides simple yet substantial usability improvements for MongoDB usage within Node.JS.

I love the super simple api

const db = require('monk')('localhost/db')
const users = db.get('users')

Use it in production 💯

Below you can see a real-world snippet of the db connection for pomodoro.cc (source code here).

The file lib/db.js

const monk = require('monk')
const logger = require('pino')()

logger.info('process.env.NODE_ENV', process.env.NODE_ENV)
logger.info('MONGO_URL set?', !!process.env.MONGO_URL)
module.exports = monk(process.env.MONGO_URL)

Nothing more, nothing less.

You could use it then to create your models and repositories around it:

For example lib/models/users.js:

const db = require('../db')
const users = db.get('users')

users.createIndex({ _id: 1 })
users.createIndex({ createdAt: 1 })

module.exports = users

use cases

stream a collection

In pomodoro.cc I use this feature to stream documents from the users collection, to update a users twitter avatar.

Here you can find the full code snippet:

await users.find({
twitterAvatarNotFound: { $exists: false },
$or: [{
twitterAvatarUpdatedAt: { $lt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 7) }
}, {
twitterAvatarUpdatedAt: { $exists: false }
}]
})
.each(async (user, { pause, resume }) => {
// ... process user twitter avatar
})
.catch(err => console.error(err))

Aggregations

Again, as a real-world production use-case, I take pomodoro.cc’s daily analytics aggregation for Pro users.

In this example I want to showcase how a daily aggregate of documents can be done with MongoDB, monk and Node.js.

About aggregations from the official docs:

Aggregation operations process data records and return computed results. Aggregation operations group values from multiple documents together, and can perform a variety of operations on the grouped data to return a single result. MongoDB provides three ways to perform aggregation: the aggregation pipeline, the map-reduce function, and single purpose aggregation methods.

An example from pomodoro.cc source code

  return pomodoros.aggregate(
[
{
$match: {
userId: monk.id(userId)
}
}, {
$project: {
doc: '$$ROOT',
year: { $substr: [`$${field}`, 0, 4] },
month: { $substr: [`$${field}`, 5, 2] },
day: { $substr: [`$${field}`, 8, 2] }
}
}, {
$group: {
_id: {
year: '$year',
month: '$month',
day: '$day'
},
docs: {
$push: '$doc'
}
}
}, {
$project: {
_id: 0,
day: {
$concat: ['$_id.year', '-', '$_id.month', '-', '$_id.day']
},
docs: '$docs'
}
}, {
$sort: {
day: -1
}
}
]
)

Here I aggregated documents of a collection by date, matched by a single userId.

upsertion - update or insert

what an upsert operation is in a few words:

Insert a New Document if No Match Exists

from the official docs you can see that

Optional. If set to true, creates a new document when no document matches the query criteria. The default value is false, which does not insert a new document when no match is found.

It as simple as providing the upsert: true option to the update function:

const result = await books.update(
{ item: "ZZZ135" }, // Query parameter
{ // Replacement document
item: "ZZZ135",
stock: 5,
tags: [ "database" ]
},
{ upsert: true } // Options
)

The result will look something like this:

{
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("5da78973835b2f1c75347a83")
}

this gives us more information on what the update operation actually did.


Let me know how you are using monk in production!