Learn how to connect and run script on mongosh

Recently, I needed to write some scripts to run on mongosh and since there will be common code among the scripts. I was wondering if it is possible to write just like any JavaScript file (with import/export) to run on mongosh.

I also explored a little further to see what are supported as well, read below to know more!

Assumption

You have a local instance of MongoDB installed, with a username as root and password as password

MongoDB Shell (mongosh)

mongosh allows you to connect and work with MongoDB via CLI. According to its website, mongosh is a

fully functional JavaScript and Node.js 16.x REPL environment for interacting with MongoDB deployments

Given that, it would have meant I can write a JavaScript file, and expects it to run perfectly on mongosh. And I should be able to import and export statement and expect it to run as well.

Installation

Grab a copy of mongosh at its official website. For my case, I'm using Windows, and I will download the zip binary.

image.png

Once downloaded, extract it to any path of your choice, and add it to your environment variable.

Using mongosh

Let's see how we can use mongosh via command line first, before looking into running via scripts.

Connecting

Launch your command prompt, and run

mongosh "mongodb://localhost:27017/sample" --username root --password password --authenticationDatabase admin

You should see the following after connected

> mongosh "mongodb://localhost:27017/sample" --username root --password password --authenticationDatabase admin

Current Mongosh Log ID: 634138e49092fab94899061f
Connecting to:          mongodb://<credentials>@localhost:27017/sample?directConnection=true&serverSelectionTimeoutMS=2000&authSource=admin&appName=mongosh+1.6.0
Using MongoDB:          6.0.1
Using Mongosh:          1.6.0

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

------
   The server generated these startup warnings when booting
   2022-09-24T06:48:19.570+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
   2022-09-24T06:48:21.727+00:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
   2022-09-24T06:48:21.727+00:00: vm.max_map_count is too low
------

------
   Enable MongoDB's free cloud-based monitoring service, which will then receive and display
   metrics about your deployment (disk utilization, CPU, operation statistics, etc).

   The monitoring data will be available on a MongoDB website with a unique URL accessible to you
   and anyone you share the URL with. MongoDB may use this information to make product
   improvements and to suggest MongoDB products and deployment options to you.

   To enable free monitoring, run the following command: db.enableFreeMonitoring()
   To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
------

sample>

If you get error such as

MongoServerError: Authentication failed.

Ensure to double-check your credentials / authenticationDatabase value.

Inserting Documents

To create a document in sample database, simply run the following command after connected, and you will see the acknowledgement immediately

sample> db.sample.insertOne({"name":"sample-1"})
{
  acknowledged: true,
  insertedId: ObjectId("634139d14c429a502d43ee3b")
}

Finding Documents

To search for all document, run the following command

sample> db.sample.find();
[
    {
        _id: ObjectId("634139d14c429a502d43ee3b"),
        name: 'sample-1'
    }
]

Execute with JavaScript file

So far, we are interacting with mongosh via the shell and that's fine for demo, or simple use-case. But what if we have complex scripts that we want to run, or that we want to run it automatically via a cron job?

mongosh does accept a --file parameter to take in a javascript based file. Imagine our index.js looks like this

printjson(db.sample.insertOne({"name":"sample-2"}));
printjson(db.sample.find());

printjson is a mongosh specific function that returns formatted JSON

In order to run the script on connect, we run the following command

mongosh "mongodb://localhost:27017/sample" --username root --password password --authenticationDatabase admin --file index.js

Notice the new parameter --file index.js I have passed in

The output would look like

Loading file: index.js
{
  acknowledged: true,
  insertedId: ObjectId("63413cae8d616c98fd852c7d")
}
[
  { _id: ObjectId("634139d14c429a502d43ee3b"), name: 'sample-1' },
  { _id: ObjectId("63413cae8d616c98fd852c7d"), name: 'sample-2' }
]

Execute with JavaScript file (with imports)

As I mentioned previously that given a complex script, there would probably have some functions or objects shared across scripts, and it would be helpful to use those in my main (index.js) file

Now, let's assume we have two files now, index.js and collection.js

// index.js
const profile = require('./collections');

printjson(db.sample.insertOne(profile));
printjson(db.sample.find());

// collections.js
const profile = {
    name: 'name',
    remarks: 'remarks'
};

module.exports = { profile };

Notice that I've exported the profile object from collection.js and then import (require) it on index.js. However, when I run the script, you need to just specify the entry file which in this case would be index.js

mongosh "mongodb://localhost:27017/sample" --username root --password password --authenticationDatabase admin --file index.js

And the output will be

Loading file: index.js
{
  acknowledged: true,
  insertedId: ObjectId("6346d4b40ce71b9819a17d61")
}
[
  {
    _id: ObjectId("6346d4b40ce71b9819a17d61"),
    profile: { name: 'name', remarks: 'remarks' }
  }
]

Execute with load function

If you wish to load and run the script within the mongosh console, you can do so via the load function. Connect to the shell as usual without specifying the --file parameter

mongosh "mongodb://localhost:27017/sample" --username root --password password --authenticationDatabase admin

Once entered to the console mode, run load('index.js')

sample> load('index.js')
{
  acknowledged: true,
  insertedId: ObjectId("6346d54fd955e733e1cad13e")
}
[
  {
    _id: ObjectId("6346d54fd955e733e1cad13e"),
    profile: { name: 'name', remarks: 'remarks' }
  }
]
true

Support for native NodeJS module

If you ever need to rely on nodejs modules, then you will be glad to know that it is supported as well!

// index.js
const os = require('node:os');

print(os);
sample> load('index.js')
{
  arch: [Function: arch] {
    [Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
  },
  cpus: [Function: cpus],
  endianness: [Function: endianness] {
    [Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
  },
  // omitted
  },
  EOL: '\r\n',
  devNull: '\\\\.\\nul'
}
sample>

Support for 3rd party modules

You can rely on 3rd party modules too, but the condition is that the module you want to use, must be installed globally or locally.

Global

Let's install lodash module globally

npm i -g lodash

Which, in my case, will be installed to %APPDATA%\npm\node_modules

// index.js
const path = require('node:path');
// this might be slightly different for linux machine
const lodashPath = path.join(process.env.APPDATA, 'npm', 'node_modules', 'lodash');
const lodash = require(lodashPath);

print(lodash);
  1. Import path module to make use of join method
  2. Join the path segment using the platform-specific separator as a delimiter
  3. Import lodash
sample> load('index.js')
<ref *1> [Function: lodash] {
  templateSettings: {
    escape: /<%-([\s\S]+?)%>/g,
    evaluate: /<%([\s\S]+?)%>/g,
    interpolate: /<%=([\s\S]+?)%>/g,
    variable: '',
    imports: { _: [Circular *1] }
  },
  after: [Function: after],
  ary: [Function: ary],
  // omitted

If you encounter error such as

sample> load('index.js')
Uncaught:
Error: Cannot find module 'lodash'
Require stack:
- <repl>
sample>

This means that it can't reference to the global lodash module that was installed, so it is likely that the path is wrong. So make sure you double-check on that.

Local

The directory where you run the script must have a node_modules directory containing the library/module you want to use.

For this, we do not need to point to the global npm path, but just need to import as usual

// index.js
const lodash = require('lodash');

print(lodash);

And everything should run normally as before

Conclusion

We looked at how mongosh can be used to

  • run commands via the console directly
  • run script using --file parameter
  • run script usingload function within the console
  • run script that imports other files, native NodeJS module, or even 3rd party modules

Personally, I like the option of using --file to run because I can write the script using JavaScript, and more importantly, I can also choose to run using node index.js if I want to.

I hoped that this gives you an insight of what mongosh can do and help you to improve your experience using the console.

References