52

I want to consume the raw output of some MongoDB commands in other programs that speak JSON. When I run commands in the mongo shell, they represent Extended JSON, fields in "shell mode", with special fields like NumberLong , Date, and Timestamp. I see references in the documentation to "strict mode", but I see no way to turn it on for the shell, or a way to run commands like db.serverStatus() in things that do output strict JSON, like mongodump. How can I force Mongo to output standards-compliant JSON?

There are several other questions on this topic, but I don't find any of their answers particularly satisfactory.

Community
  • 1
  • 1
whereswalden
  • 4,819
  • 3
  • 27
  • 41
  • You have this the wrong way around. The shell uses "strict" syntax which is `{ "a": NumberLong(1) }` etc.And "Extended JSON" which is not supported by the shell at all, is used by tools like `mongoexport` which does `"a":{"$numberLong":"1"}}` which is parsable JSON form. `mongodump` just dumps BSON datafiles. – Blakes Seven Aug 19 '15 at 14:19
  • You are incorrect. The [documentation](http://docs.mongodb.org/manual/reference/mongodb-extended-json/#numberlong) clearly shows that the "strict mode" representation of the NumberLong type is `{ "$numberLong": "" }`, while the "shell mode" representation is `NumberLong( "" )`. I can edit the question to clarify the difference between "extended JSON" and "shell mode". – whereswalden Aug 19 '15 at 14:31
  • Like I said. You have this completely in reverse. Extened JSON is what you are calling "strict". – Blakes Seven Aug 19 '15 at 15:04
  • The semantics don't really change the question or the answer, but FWIW, the previously linked documentation specifies that both "shell mode" and "strict mode" are extensions on JSON, so "Extended JSON" includes both. If there's other documentation that indicates otherwise, I'd be interested to see it. – whereswalden Aug 19 '15 at 15:46
  • Blakes Seven please read http://docs.mongoing.com/manual/reference/mongodb-extended-json.html strict mode -> { "$oid": "" } shell mode -> ObjectId( "" ) strict = standard Json – Jean-Marie Oct 16 '15 at 05:41

5 Answers5

45

The MongoDB shell speaks Javascript, so the answer is simple: use JSON.stringify(). If your command is db.serverStatus(), then you can simply do this:

JSON.stringify(db.serverStatus())

This won't output the proper "strict mode" representation of each of the fields ({ "floatApprox": <number> } instead of { "$numberLong": "<number>" }), but if what you care about is getting standards-compliant JSON out, this'll do the trick.

whereswalden
  • 4,819
  • 3
  • 27
  • 41
  • 4
    And this is false as well. as `JSON.stringify({ "a": NumberLong(1) })` comes out as `{"a":{"floatApprox":1}}` which is totally not the [Extended JSON](http://docs.mongodb.org/manual/reference/mongodb-extended-json/) format. I think before you go for any more self answers you should research the material a bit more. – Blakes Seven Aug 19 '15 at 14:22
  • 2
    The crux of the question is how to get the shell to spit out something that can be parsed by a standards-compliant JSON parser. This accomplishes that goal. I will edit the answer to clarify that though. – whereswalden Aug 19 '15 at 14:34
  • 2
    Can you suggest an improvement? – whereswalden Aug 19 '15 at 15:46
  • 1
    Would be great if we also got an answer to "Force mongodb to output Extended JSON"... but that is not what you are asking – KCD Feb 29 '16 at 04:16
  • You rock. You made my day! Thank you!! – danilodeveloper Jun 04 '16 at 06:42
  • Thanks for this, php cannot decode printjsononeline output. JSON.stringify works very nicely and is actual valid JSON. Cheers – stackoverflowsucks Feb 20 '17 at 00:51
7

I have not found a way to do this in the mongo shell, but as a workaround, mongoexport can run queries and its output uses strict mode and can be piped into other commands that expect JSON input (such as json_pp or jq). For example, suppose you have the following mongo shell command to run a query, and you want to create a pipeline using that data:

db.myItemsCollection.find({creationDate: {$gte: ISODate("2016-09-29")}}).pretty()

Convert that mongo shell command into this shell command, piping for the sake of example to `json_pp:

mongoexport --jsonArray -d myDbName -c myItemsCollection -q '{"creationDate": {"$gte": {"$date": "2016-09-29T00:00Z"}}}' | json_pp

You will need to convert the query into strict mode format, and pass the database name and collection name as arguments, as well as quote properly for your shell, as shown here.

jbyler
  • 7,200
  • 3
  • 34
  • 42
3

In case of findOne

JSON.stringify(db.Bill.findOne({'a': '123'}))

In case of a cursor

db.Bill.find({'a': '123'}).forEach(r=>print(JSON.stringify(r)))

or

print('[') + db.Bill.find().limit(2).forEach(r=>print(JSON.stringify(r) + ',')) + print(']')

will output

[{a:123},{a:234},]

the last one will have a ',' after the last item...remove it

agelbess
  • 4,249
  • 3
  • 20
  • 21
1

To build on the answer from @jbyler, you can strip out the numberLongs using sed after you get your data - that is if you're using linux.

mongoexport --jsonArray -d dbName -c collection -q '{fieldName: {$regex: ".*turkey.*"}}' | sed -r 's/\{ "[$]numberLong" : "([0-9]+)" }/"\1"/g' | json_pp
Kieveli
  • 10,944
  • 6
  • 56
  • 81
-1

EDIT: This will transform a given document, but will not work on a list of documents. Changed find to findOne.

Adding

.forEach(function(results){results._id=results._id.toString();printjson(results)})`

to a findOne() will output valid JSON.

Example:

db
  .users
  .findOne()
  .forEach(function (results) {
    results._id = results._id.toString();
    printjson(results)
  })

Source: https://www.mydbaworld.com/mongodb-shell-output-valid-json/

DeBraid
  • 8,751
  • 5
  • 32
  • 43
  • not general enough. I have a large doc, it's difficult to process each field on my own. – Yin Apr 28 '21 at 11:29