Printing Mongo query output to a file while in the mongo shell
Asked Answered
T

8

107

2 days old with Mongo and I have a SQL background so bear with me. As with mysql, it is very convenient to be in the MySQL command line and output the results of a query to a file on the machine. I am trying to understand how I can do the same with Mongo, while being in the shell

I can easily get the output of a query I want by being outside of the shell and executing the following command:

mongo localhost:27017/dbname --eval "printjson(db.collectionName.findOne())" > sample.json

The above way is fine, but it requires me to exit the mongo shell or open a new terminal tab to execute this command. It would be very convenient if I could simply do this while still being inside the shell.

P.S: the Question is an offshoot of a question I posted on SO

Taitaichung answered 21/3, 2014 at 17:12 Comment(0)
B
114

AFAIK, there is no a interactive option for output to file, there is a previous SO question related with this: Printing mongodb shell output to File

However, you can log all the shell session if you invoked the shell with tee command:

$ mongo | tee file.txt
MongoDB shell version: 2.4.2
connecting to: test
> printjson({this: 'is a test'})
{ "this" : "is a test" }
> printjson({this: 'is another test'})
{ "this" : "is another test" }
> exit
bye

Then you'll get a file with this content:

MongoDB shell version: 2.4.2
connecting to: test
> printjson({this: 'is a test'})
{ "this" : "is a test" }
> printjson({this: 'is another test'})
{ "this" : "is another test" }
> exit
bye

To remove all the commands and keep only the json output, you can use a command similar to:

tail -n +3 file.txt | egrep -v "^>|^bye" > output.json

Then you'll get:

{ "this" : "is a test" }
{ "this" : "is another test" }
Bihari answered 21/3, 2014 at 17:28 Comment(3)
sigh, I wish this was possible, oh well, thanks for your answer :)Taitaichung
Good answer, but using the cursor keys distorts the output in tmux, to the point where it's pretty much "paste a command, CTRL+C "Zampardi
I wish there was workaround like this when using mongosh from within compassUpholstery
E
60

We can do it this way -

mongo db_name --quiet --eval 'DBQuery.shellBatchSize = 2000; db.users.find({}).limit(2000).toArray()' > users.json

The shellBatchSize argument is used to determine how many rows is the mongo client allowed to print. Its default value is 20.

Environs answered 4/4, 2018 at 14:55 Comment(3)
Unfortunately this is not safe, other useless junk is captured too with some ssl setups: jira.mongodb.org/browse/SERVER-23810Soldierly
New versions of mongo shell deprecated shellbatchSize. The new syntax is: mongo db_name --quiet --eval 'config.set("displayBatchSize", 2000); db.users.find({}).limit(2000).toArray()' > users.jsonSumer
If using a query operator that starts with $ keep the single quotes in mind so that bash (or whatever shell you're using) doesn't try to interpret the operator as a variable. mongo --eval 'db.coll.find().sort({$natural: -1})' works but using a double quote wouldn't work here.Wigwam
M
37

If you invoke the shell with script-file, db address, and --quiet arguments, you can redirect the output (made with print() for example) to a file:

mongo localhost/mydatabase --quiet myScriptFile.js > output 
Mistymisunderstand answered 23/12, 2014 at 2:4 Comment(2)
I came here looking for --quiet specifically, thanksSteward
Works with mongosh tooRheta
S
18

In the new mongodb shell 5.0+ mongosh, it integrate the Node.js fs module, so you can simply do below in the new mongosh shell:

fs.writeFileSync('output.json', JSON.stringify(db.collectionName.findOne()))

This also avoid problems such as the ObjectId(...) being included in the tojson result, which is not valid JSON string.

The above code works according to the docs describes:

The MongoDB Shell, mongosh, is a fully functional JavaScript and Node.js 14.x REPL environment for interacting with MongoDB deployments. You can use the MongoDB Shell to test queries and operations directly with your database.

The old mongo shell already marked as Legacy, so use the mongosh if possible.

Smallclothes answered 29/12, 2021 at 2:4 Comment(2)
I needed to convert the iterated response via .toArray(), without it there was an error "Converting circular structure to JSON"Cornice
When tried from mongosh within compass this gives "fs is not defined"Upholstery
N
15

There are ways to do this without having to quit the CLI and pipe mongo output to a non-tty.

To save the output from a query with result x we can do the following to directly store the json output to /tmp/x.json:

> EDITOR="cat > /tmp/x.json"
> x = db.MyCollection.find(...).toArray()
> edit x
>

Note that the output isn't strictly Json but rather the dialect that Mongo uses.

Natural answered 8/7, 2020 at 20:55 Comment(6)
why not just EDITOR="cat > x.json"Belvabelvedere
I didn't test if redirection worked. It seems that works just as well. Nice catch!Natural
For Windows, replace cat with type. (writeFile function also works)Nocturne
is there something similar for mongosh? when I do edit x it complains about a missing semicolon before x.Burnedout
FYI if you use let x you'll get SyntaxError: redeclaration of let x when you use the edit command... still works thoughZeppelin
@JosephSummerhays For mongosh, use config.set('editor', '...') instead of setting the EDITOR variableEjecta
N
7

It may be useful to you to simply increase the number of results that get displayed

In the mongo shell > DBQuery.shellBatchSize = 3000

and then you can select all the results out of the terminal in one go and paste into a text file.

It is what I am going to do :)

(from : https://mcmap.net/q/98837/-how-to-print-out-more-than-20-items-documents-in-mongodb-39-s-shell)

Neotropical answered 2/6, 2017 at 2:31 Comment(0)
C
6

Combining several conditions:

  • write mongo query in JS file and send it from terminal
  • switch/define a database programmatically
  • output all found records
  • cut initial output lines
  • save the output into JSON file

myScriptFile.js

// Switch current database to "mydatabase"
db = db.getSiblingDB('mydatabase');

// The mark for cutting initial output off
print("CUT_TO_HERE");

// Main output
// "toArray()" method allows to get all records
printjson( db.getCollection('jobs').find().toArray() );

Sending the query from terminal

-z key of sed allows treat output as a single multi-line string

$> mongo localhost --quiet myScriptFile.js | sed -z 's/^.*CUT_TO_HERE\n//' > output.json

Casebound answered 19/3, 2018 at 12:41 Comment(0)
C
0

Better late than never: you could use mongoexport like so:

mongoexport --uri mongodb://localhost/mydb \
  --collection "my_collection" \
  --quiet \
  --limit 1 \
  --out my_file.json
Clardy answered 25/5, 2023 at 6:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.