PS1++

Since MongoDB was first created, the Mongo shell prompt has just been:

>

A couple of months ago, my prompt suddenly changed to:

myReplSetName:SECONDARY> 

It’s nice to have more information the prompt, but 1) I don’t care about the replica set name and 2) a programmer’s prompt is very personal. Having it change out from under you is like coming home and finding that someone replaced all of your underwear. It’s just disconcerting.

Anyway, I recently got an intern (well, I’m mentoring him, it’s not like I bought him), Matt Dannenberg, who’s interested in working on shell stuff. He committed some code last week that lets you customize the shell’s prompt (it will be in 1.9.1+).

Basically, you define a prompt() function, and then it’ll be executed every time the shell is displayed. Immediately, I did:

myReplSetName:SECONDARY> prompt = "> "
> 
> // ah, bliss
>
> // some sysadmins think > is a weird prompt, as it's also 
> // used for redirections, so they might prefer $
> prompt = "$ "
$ 
$ // there we go

Okay, that’s much better. But there is some information I’d like to add to my prompt.

I often forget which database db is referring to, and then I have to type db to check (which is especially annoying when I’m in the middle of a multi-line script). So, let’s just add the current database name to the prompt.

> prompt = function() { return db+"> "; }
test> use foo
foo> use bar
bar>

The prompt no longer shows whether I’m connected to a PRIMARY or a SECONDARY (or something else), which is useful information to have. I hate that long string, though, so let’s neaten it up. I want it to be:

foo>
I’m connected to the primary
(foo)>
I’m connected to a secondary
STATE:foo>
I’m connected to a server with state STATE.

This might look something like:

> states = ["STARTUP", "PRIMARY", "SECONDARY", "RECOVERING", "FATAL", 
... "STARTUP2", "UNKNOWN", "ARBITER", "DOWN", "ROLLBACK"]
>
> prompt = function() { 
... result = db.isMaster();
... if (result.ismaster) {
...     return db+"> "; 
... }
... else if (result.secondary) {
...    return "("+db+")> ";
... }
... result = db.adminCommand({replSetGetStatus : 1})
... return states[result.myState]+":"+db+"> ";
... }
(test)>

Also, the default prompt displays if you’re connected to a mongos (with mongos>), which is good for keeping track when you’re running a cluster:

> prompt = function() {
... result = db.adminCommand({isdbgrid : 1});
... if (result.ok == 1) {
...     return "mongos> ";
... }
... return "> ";
... }

Another nice thing would be to have the time each time it displays the prompt: then you can kick off a long-running job, go to lunch, and know what time it finished when you get back.

> prompt = function() { 
... var now = new Date(); 
... return now.getHours()+":"+now.getMinutes()+":"+now.getSeconds()+"> ";
... }
10:30:45> db.foo.count()
60000
10:30:46>

Defining prompt() as shown above is nice for playing around, but it’s a pain to define your prompt every time you start up the shell. So, you can add it to a function and then either load it on startup (a command line argument) or from the shell itself:

$ # load from command line arg:
$ mongo shellConfig.js
MongoDB shell version 1.9.1-
connecting to: test
> 
> // load from the shell itself
> load("/path/to/my/shellConfig.js")

Or, you can use another feature my intern has implemented: mongo will automatically look for (and, if it finds, load) a .mongorc.js file from your home directory on startup.

// my startup file

prompt = /* ... */

// getting "not master and slaveok=false" errors drives me nuts,
// so I'm overriding the getDB() code to ALWAYS set slaveok=true
Mongo.prototype.getDB = function(name) {
    this.setSlaveOk();
    return new DB(this, name);
}

/* and so on... */
Actually, 10gen employees would never have an intern make coffee, as they might mess it up: we have at least five different brewers, two grinders, two pages of close-typed instructions on how to grind/brew, and an RFC on coffee-making protocol.

Keep in mind that the is a “proper” JS file, you can’t use magic Mongo shell helpers, like use <dbname> (instead, use db.getSisterDB("<dbname>")). If you don’t want .mongorc.js loaded on startup, start the shell with –norc.

Hopefully these things will make life a little easier for people.

Both of these changes are in master and will be in 1.9.1+. They will not be backported to the 1.8 branch. You can use the 1.9 shell with the 1.8 database server, though, if you want to use these features with a production database.

Leave a comment