six demon bag

Wind, fire, all that kind of thing!


Non-interactive MongoDB Commandline

MongoDB provides an interactive command shell for working with the database. Which is all nice and dandy, but from an admin and automation perspective it's desirable to also be able to run commands non-interactively. The mongo commandline tool does have a parameter --eval that kind of allows you to do that:

--eval <javascript>
Evaluates a JavaScript expression that is specified as an argument. mongo does not load its own environment when evaluating code. As a result many options of the shell environment are not available.

except that it doesn't play nice when you also want to automatically authenticate via the config file .mongorc.js.

root@server:~# mongo --ssl --sslAllowInvalidHostnames --eval 'rs.status()'
MongoDB shell version v3.4.10
connecting to: mongodb://
2018-04-11T08:39:28.250+0000 W NETWORK  [thread1] The server certificate does not match the host name. Hostname: does not match SAN(s): *
MongoDB server version: 3.4.10
  "ok" : 0,
  "errmsg" : "not authorized on admin to execute command { replSetGetStatus: 1.0 }",
  "code" : 13,
  "codeName" : "Unauthorized"

Essentially, non-interactive invocation ignores .mongorc.js and requires explicit credentials:

mongo --username alice --password abc123 --authenticationDatabase admin ...

However, if you echo the statement into the mongo command it authenticates and executes just fine:

root@server:~# echo 'rs.status()' | mongo --ssl --sslAllowInvalidHostnames
MongoDB shell version v3.4.23
connecting to: mongodb://
2020-02-26T19:33:07.603+0000 W NETWORK  [thread1] The server certificate does not match the host name. Hostname: does not match SAN(s): ...

To work around this issue create a script (e.g. mongocmd) with the following content:


declare -a mongo_args=(

if [ "$#" -eq 0 ]; then
  mongo "${mongo_args[@]}" < /dev/stdin
  for cmd in "$@"; do
    echo "$cmd" | mongo "${mongo_args[@]}"

The script will take commands either as arguments:

mongocmd 'rs.status()' 'db.hostInfo()'

or (if no arguments were provided) read them from STDIN:

echo 'rs.status()' | mongocmd
mongocmd <<EOF

The parameter --sslAllowInvalidHostnames is used because the host certificate didn't include a Subject Alternative Name for

The .mongorc.js for automatic login should look like this:

function authRequired() {
  try {
    return (db.serverCmdLineOpts().code == 13);
  } catch (err) {
    return false;

if (authRequired()) {
  try {
    var prev_db = db
    db = db.getSiblingDB('admin')
    db.auth('admin', 'PASSWORD')
    db = db.getSiblingDB(prev_db)
  } catch (err) {
    abort('Unknown error')

Posted 01:29 [permalink]