skip to Main Content

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)?

3

Answers


  1. 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.

    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
  3. You can wrap your queries inside EJSON.stringify from inside mongosh console.
    Eg: if you want to run the query db.books.find({"book-id":"123456789"}) execute the following.

    EJSON.stringify(db.books.find({"book-id":"123456789"}).toArray(), null, 2, { relaxed: false })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search