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