How to execute mongo commands through shell scripts?

MongodbBashShellSh

Mongodb Problem Overview


I want to execute mongo commands in shell script, e.g. in a script test.sh:

#!/bin/sh
mongo myDbName
db.mycollection.findOne()
show collections

When I execute this script via ./test.sh, then the connection to MongoDB is established, but the following commands are not executed.

How to execute other commands through shell script test.sh?

Mongodb Solutions


Solution 1 - Mongodb

You can also evaluate a command using the --eval flag, if it is just a single command.

mongo --eval "printjson(db.serverStatus())"

Please note: if you are using Mongo operators, starting with a $ sign, you'll want to surround the eval argument in single quotes to keep the shell from evaluating the operator as an environment variable:

mongo --eval 'db.mycollection.update({"name":"foo"},{$set:{"this":"that"}});' myDbName

Otherwise you may see something like this:

mongo --eval "db.test.update({\"name\":\"foo\"},{$set:{\"this\":\"that\"}});"
> E QUERY    SyntaxError: Unexpected token :

Solution 2 - Mongodb

Put your mongo script into a .js file.

Then execute mongo < yourFile.js

Ex:

demo.js //file has your script

use sample  //db name
show collections

keep this file in "c:\db-scripts"

Then in cmd prompt go to "c:\db-scripts"

C:\db-scripts>mongo < demo.js

This will execute the code in mongo and shows the output

C:\db-scripts>mongo < demo.js
Mongo shell version: 3.0.4
Connecting to: test
switched to db sample
users   //collection name
tasks   //collection name
bye
C:\db-scripts>

Solution 3 - Mongodb

This works for me under Linux:

mongo < script.js

For newer version of mongodb

mongosh < script.js

Solution 4 - Mongodb

Put this in a file called test.js:

db.mycollection.findOne()
db.getCollectionNames().forEach(function(collection) {
  print(collection);
});

then run it with mongo myDbName test.js.

Solution 5 - Mongodb

There is an official documentation page about this as well.

Examples from that page include:

mongo server:27017/dbname --quiet my_commands.js
mongo test --eval "printjson(db.getCollectionNames())"

Solution 6 - Mongodb

The shell script below also worked nicely for me... definite had to use the redirect that Antonin mentioned at first... that gave me the idea to test the here document.

function testMongoScript {
    mongo <<EOF
    use mydb
    db.leads.findOne()
    db.leads.find().count()
EOF
}

Solution 7 - Mongodb

In case you have authentication enabled:

mongo -u username -p password --authenticationDatabase auth_db_name < your_script.js

For newer version

mongosh -u username -p password --authenticationDatabase auth_db_name < your_script.js

Solution 8 - Mongodb

I use the "heredoc" syntax, which David Young mentions. But there is a catch:

#!/usr/bin/sh

mongo <db> <<EOF
db.<collection>.find({
  fieldName: { $exists: true }
})
.forEach( printjson );
EOF

The above will NOT work, because the phrase "$exists" will be seen by the shell and substituted with the value of the environment variable named "exists." Which, likely, doesn't exist, so after shell expansion, it becomes:

#!/usr/bin/sh

mongo <db> <<EOF
db.<collection>.find({
  fieldName: { : true }
})
.forEach( printjson );
EOF

In order to have it pass through you have two options. One is ugly, one is quite nice. First, the ugly one: escape the $ signs:

#!/usr/bin/sh

mongo <db> <<EOF
db.<collection>.find({
  fieldName: { \$exists: true }
})
.forEach( printjson );
EOF

I do NOT recommend this, because it is easy to forget to escape.

The other option is to escape the EOF, like this:

#!/usr/bin/sh

mongo <db> <<\EOF
db.<collection>.find({
  fieldName: { $exists: true }
})
.forEach( printjson );
EOF

Now, you can put all the dollar signs you want in your heredoc, and the dollar signs are ignored. The down side: That doesn't work if you need to put shell parameters/variables in your mongo script.

Another option you can play with is to mess with your shebang. For example,

#!/bin/env mongo
<some mongo stuff>

There are several problems with this solution:

  1. It only works if you are trying to make a mongo shell script executable from the command line. You can't mix regular shell commands with mongo shell commands. And all you save by doing so is not having to type "mongo" on the command line... (reason enough, of course)

  2. It functions exactly like "mongo <some-js-file>" which means it does not let you use the "use <db>" command.

I have tried adding the database name to the shebang, which you would think would work. Unfortunately, the way the system processes the shebang line, everything after the first space is passed as a single parameter (as if quoted) to the env command, and env fails to find and run it.

Instead, you have to embed the database change within the script itself, like so:

#!/bin/env mongo
db = db.getSiblingDB('<db>');
<your script>

As with anything in life, "there is more than one way to do it!"

Solution 9 - Mongodb

In my setup I have to use:

mongo --host="the.server.ip:port" databaseName theScript.js 

For newer version of mongodb

mongosh --host="the.server.ip:port" databaseName theScript.js 

Solution 10 - Mongodb

Create a script file; write commands:

#!/bin/sh
mongo < file.js

For newer versions mongosh < file.js

In file.js write your mongo query:

db.collection.find({"myValue":null}).count();

Solution 11 - Mongodb

How about this:

echo "db.mycollection.findOne()" | mongo myDbName
echo "show collections" | mongo myDbName

Solution 12 - Mongodb

As suggested by theTuxRacer, you can use the eval command, for those who are missing it like I was, you can also add in your db name if you are not trying to preform operation on the default db.

mongo <dbname> --eval "printjson(db.something.find())"

Newer version of mongodb

mongosh <dbname> --eval "printjson(db.something.find())"

Solution 13 - Mongodb

Thank you printf! In a Linux environment, here's a better way to have only one file run the show. Say you have two files, mongoCmds.js with multiple commands:

use someDb
db.someColl.find()

and then the driver shell file, runMongoCmds.sh

mongo < mongoCmds.js

Newer version of mongodb

mongosh < mongoCmds.js

Instead, have just one file, runMongoCmds.sh containing

printf "use someDb\ndb.someColl.find()" | mongo

Bash's printf is much more robust than echo and allows for the \n between commands to force them on multiple lines.

Solution 14 - Mongodb

In my case, I can conveniently use \n as separator for the next mongo command I want to execute then pipe them to mongo

echo $'use your_db\ndb.yourCollection.find()' | mongo

Newer version of mongodb

echo $'use your_db\ndb.yourCollection.find()' | mongosh

Solution 15 - Mongodb

mongo <<EOF
use <db_name>
db.getCollection("<collection_name>").find({})
EOF

Solution 16 - Mongodb

--shell flag can also be used for javascript files

 mongo --shell /path/to/jsfile/test.js 

Solution 17 - Mongodb

mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"

Solution 18 - Mongodb

Recently migrated from mongodb to Postgres. This is how I used the scripts.

mongo < scripts.js > inserts.sql

Read the scripts.js and output redirect to inserts.sql.

scripts.js looks like this

use myDb;
var string = "INSERT INTO table(a, b) VALUES";
db.getCollection('collectionName').find({}).forEach(function (object) {
    string += "('" + String(object.description) + "','" + object.name + "'),";
});
print(string.substring(0, string.length - 1), ";");

inserts.sql looks like this

INSERT INTO table(a, b) VALUES('abc', 'Alice'), ('def', 'Bob'), ('ghi', 'Claire');

Solution 19 - Mongodb

If you want to handle it with one line it's an easy way.

file.sh --> db.EXPECTED_COLLECTION.remove("_id":1234)

cat file.sh | mongo <EXPECTED_COLLECTION>

Solution 20 - Mongodb

Single shell script solution with ability to pass mongo arguments (--quiet, dbname, etc):

#!/usr/bin/env -S mongo --quiet localhost:27017/test

cur = db.myCollection.find({});
while(cur.hasNext()) {
  printjson(cur.next());
}

The -S flag might not work on all platforms.

Solution 21 - Mongodb

When using a replicaset, writes must be done on the PRIMARY, so I usually use syntax like this which avoids having to figure out which host is the master:

mongo -host myReplicaset/anyKnownReplica

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStackOverFlowView Question on Stackoverflow
Solution 1 - MongodbtheTuxRacerView Answer on Stackoverflow
Solution 2 - MongodbMattView Answer on Stackoverflow
Solution 3 - MongodbAntonin BrettsnajdrView Answer on Stackoverflow
Solution 4 - MongodbTheoView Answer on Stackoverflow
Solution 5 - MongodbthaddeusmtView Answer on Stackoverflow
Solution 6 - MongodbDavid H. YoungView Answer on Stackoverflow
Solution 7 - MongodbMoses XuView Answer on Stackoverflow
Solution 8 - MongodbJohn ArrowwoodView Answer on Stackoverflow
Solution 9 - MongodbEd WilliamsView Answer on Stackoverflow
Solution 10 - MongodbGSKView Answer on Stackoverflow
Solution 11 - MongodbMark ButlerView Answer on Stackoverflow
Solution 12 - MongodbMatt ClarkView Answer on Stackoverflow
Solution 13 - MongodbtgoneilView Answer on Stackoverflow
Solution 14 - MongodbArdhiView Answer on Stackoverflow
Solution 15 - MongodbErdem ÖZDEMİRView Answer on Stackoverflow
Solution 16 - MongodbJackson HarryView Answer on Stackoverflow
Solution 17 - MongodbTalespin_KitView Answer on Stackoverflow
Solution 18 - MongodbmythicalcoderView Answer on Stackoverflow
Solution 19 - MongodbErçin AkçayView Answer on Stackoverflow
Solution 20 - MongodbyǝsʞǝlaView Answer on Stackoverflow
Solution 21 - MongodbRichard SaltView Answer on Stackoverflow