DEV Community

loading...
Cover image for Connect to MongoDB with monk in Node.js

Connect to MongoDB with monk in Node.js

christianfei profile image Christian Originally published at cri.dev ・3 min read

Originally posted on cri.dev

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')
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

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
        }
      }
    ]
  )
Enter fullscreen mode Exit fullscreen mode

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
)
Enter fullscreen mode Exit fullscreen mode

The result will look something like this:

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

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


Let me know how you are using monk in production!

Discussion (0)

pic
Editor guide