Home > Back-end >  Is there a way to standardize mongosh JSON output?
Is there a way to standardize mongosh JSON output?

Time:03-27

MongoDB upgraded their command-line interface (formerly mongo, now mongosh). Before, the mongo command output was in proper JSON, the kind jq could ingest.

For example:

{ "abc" : "hello" }

The new mongosh command now outputs stuff like:

{ abc: 'hello' }

...which can't be parsed by jq.

Is there a way to standardize mongosh to output standard JSON?

If not, is there any shell command that filters "incorrect but coherent" JSON (from stdin) and normalizes it into a standard form (to stdout)?

CodePudding user response:

A MongoDB employee recommends using the EJSON.stringify wrapper, e.g.:

$ mongosh [...] --eval "EJSON.stringify(db.adminCommand('listDatabases'))"

Except for extensions such as Long(_) and Date(_), it looks like hjson could also be used.

CodePudding user response:

In principle you can use JSON.stringify(). However it has some limitations, see this example:

x = {
  a: 1,
  b: ISODate("2022-03-26T11:15:53.750Z"),
  c: Int32(1),
  d: Long("1"),
  e: Long("2"),
  f: Decimal128("-7.6E 11"),
  g: 1.345,
  h: 2,
  t: 'foo'
}

JSON.stringify(x, null, " ")
{
 "a": 1,
 "b": "2022-03-26T11:15:53.750Z",
 "c": 1,
 "d": {
  "low": 1,
  "high": 0,
  "unsigned": false
 },
 "e": {
  "low": 2,
  "high": 0,
  "unsigned": false
 },
 "f": {
  "$numberDecimal": "-7.6E 11"
 },
 "g": 1.345,
 "h": 2,
 "t": "foo"
}

Date objects are converted into strings.

An alternative could be EJSON.stringify(), which recognizes data types like Date. It is also mentioned in documentation:

EJSON has built in formatting options which may eliminate the need for a parser like jq.

However, the values are printed as {"$date": "2022-03-26T11:15:53.750Z"}

EJSON.stringify(x, null, " ")
{
 "a": 1,
 "b": {
  "$date": "2022-03-26T11:15:53.750Z"
 },
 "c": 1,
 "d": 1,
 "e": 2,
 "f": {
  "$numberDecimal": "-7.6E 11"
 },
 "g": 1.345,
 "h": 2,
 "t": "foo"
}

My solution is a customized function. tojson and tojsononeline do not exist anymore in mongosh, so I created my own:

if (typeof tojsononeline == 'undefined') {
   function tojsononeline(x) {
      return EJSON.stringify(x)
         .replace(/\{"\$date":"(.{19,23}Z)"\}/g, "ISODate(\"$1\")")
         .replace(/\{"\$oid":"(\w{24})"\}/g, "ObjectId(\"$1\")")
         .replace(/\{"\$numberDecimal":"(. ?)"\}/g, "Decimal128(\"$1\")");
   }
}

tojsononeline(x)
{"a":1,"b":ISODate("2022-03-26T11:22:08.029Z"),"c":1,"d":1,"e":2,"f":Decimal128("-7.6E 11"),"g":1.345,"h":2,"t":"foo"}

There are a few more data types used in MongoDB, however I think they are hardly relevant. Otherwise add a few more replace() operations.

Anther solution is to install "mongosh snippet", either with snippet install mongocompat, or download scripts from https://github.com/mongodb-labs/mongosh-snippets/tree/main/snippets/mongocompat and run

load('mongonative.js');
load('mongoassert.js');
load('mongotypes.js');

Preferable put these 3 lines in your .mongoshrc.js file.

These 3 scripts define (almost?) all function from legacy mongo shell which are not (yet) available in new mongosh

Be aware, when you move to new mongosh, then your application may face some more differences, see for example mongosh Data Types

  • Related