Bash script to create a replica set - mongodb

I am working on a replicaSet mongo in aws, my goal is to set the replica in run time with a bash script command.
my bash look like this:
mongo mongodb://10.0.1.100 --eval "rs.initiate( { _id : 'rs0', members: [{ _id: 0, host: '10.0.1.100:27017' }]})"
mongo mongodb://10.0.1.100 --eval "rs.add( '10.0.2.100:27017' )"
mongo mongodb://10.0.1.100 --eval "rs.add( '10.0.3.100:27017' )"
mongo mongodb://10.0.1.100 --eval "db.isMaster().primary"
mongo mongodb://10.0.1.100 --eval "rs.slaveOk()"
but when i log in my instance and run rs.status(), i get the error that no config could be found.
So i tried in a different way. I accessed my fresh mongo instance, and through themongo command line i inserted the var config such as:
var config={_id:"rs0",members:[{_id:0,host:"10.0.1.100:27017"}, {_id:1,host:"10.0.2.100:27017"}, {_id:2,host:"10.0.3.100:27017"}]};
> rs.initiate(config);
if i run rs.status, it works.
i would like to run the same command through a linux bash command script to initiate the config, but i cant find a solution. any help please?

Related

Mongo is pending on password despit the --password option

Context
Mongod version v3.2.11
MongoDB shell version: 3.2.11
Debian stretch
ppc64 architecture
Ansible 2.7.6
Issue
I am executing a mongo command through ansible using mongo shell.
Here is the lines i use in my task :
- name: Add the shard to the mongos
shell: /usr/bin/mongo localhost:{{ mongos_port }}/admin -u admin -p {{ mongo_admin_password }} /tmp/shard_init.js
delegate_to: '{{ item }}'
with_items: "{{ groups['mongos_servers'] }}"
But the command is pending at :
TASK [Add the shard to the mongos] ************************************************
When i execute the command line on the remote machine, despite the -p option set, it still asks me to enter the password ...
$ /usr/bin/mongo localhost:2700/admin -u admin -p "XXXX" /tmp/shard_init.js
MongoDB shell version: 3.2.11
Enter password:
It there a way to execute a mongo command through ansible on a database that reaquires authentication ?
Try with the mysql CLI method :
/usr/bin/mongo localhost:2700/admin -u admin -pXXXX /tmp/shard_init.js
Where the password is just near the -p option.
Like the usage option show this isn't the right way to do but in this case the command seems to work.

How to set up Mongo replica set in dockerfile mode

I created a dockerfile file to build the Mongo replica set.It is not a problem to start creating a copy set, but when configuring a copy of Mongo, I don't want to manually go into the Mongo shell default configuration, which is too troublesome, so I automatically execute a script to complete automatic configuration when creating docker, and try a lot of methods, the following my specific way is not running. Work
And run a script The following is my detailed document
dockerfile
FROM mongo:3.4
ENV AUTO_RUN_DIR /docker-entrypoint-initdb.d
COPY ./setup.js /docker-entrypoint-initdb.d/
RUN chmod +x /docker-entrypoint-initdb.d/setup.js
ENTRYPOINT ["/docker-entrypoint-initdb.d/setup.js"]
setup.js
#!/bin/bash
echo "Started.."
mongod --replSet replset0
mongo 127.0.0.1/admin -u test -p test --authenticationDatabase "admin"<<EOF
var cfg = {
"_id": "replset0",
"members": [
{
"_id": 0,
"host": "192.168.1.233:27018"
}
]
};
rs.initiate(cfg, { force: true });
rs.reconfig(cfg, { force: true });
EOF
exec "$#"
After executing the mongod --replSet replset0, mongo Unable to execute.I want to know what you can do. Thank you very much.

How can I disable connection messages in mongo shell [duplicate]

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?
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 :
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>
This works for me under Linux:
mongo < script.js
For newer version of mongodb
mongosh < script.js
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.
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())"
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
}
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
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:
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)
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!"
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
How about this:
echo "db.mycollection.findOne()" | mongo myDbName
echo "show collections" | mongo myDbName
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();
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())"
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
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.
mongo <<EOF
use <db_name>
db.getCollection("<collection_name>").find({})
EOF
--shell flag can also be used for javascript files
mongo --shell /path/to/jsfile/test.js
mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"
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');
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>
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.
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
The legacy mongo shell has been removed from MongoDB with the version 6 release in 2022
There is a new way to execute shell scripts using the new shell, mongosh
From the shell documentation on writing scripts:
You can use mongosh to execute a script from the command line without entering the mongosh console
To specify the filename, use the --file or -f parameter to specify the filename
You may also need to specify connection information

mongo command line vs shell: different results

I'm puzzled by a problem I'm having with the Mongo Shell producing different variations on the output.
When I log into the mongo shell and run the simplest of queries, such as:
db.database.findOne();
I get a document returned.
When I invoke the same command through the --eval option on the command line, I get a different result: (xx's redact sensitive info)
mongo -u xxx -p xxx xxxx --eval 'db.database.findOne();'
MongoDB shell version: 3.0.6
connecting to: xxxx
[object Object]
And when I put this command in a file and try it, I get no output at all.
mongo -u xxx-p xxx xxxx example.js
MongoDB shell version: 3.0.6
connecting to: xxxx
(I just get returned to a command line here)
Example.js contains:
db.database.findOne();
What part of the Mongo shell manual did I miss that explains this behavior?
My goal is to be able to feed the output of my mongo query into a shell script.
When a findOne() is run within the shell it will print the result in JSON as a convenience. To print the same via shell script or eval you need to print the return value via a printjson() call:
mongo -u xxx -p xxx xxxx --eval 'printjson(db.database.findOne());'
For more on scripting with the mongo shell see the official MongoDB Shell docs.

How to execute mongo commands through shell scripts?

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?
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 :
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>
This works for me under Linux:
mongo < script.js
For newer version of mongodb
mongosh < script.js
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.
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())"
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
}
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
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:
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)
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!"
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
How about this:
echo "db.mycollection.findOne()" | mongo myDbName
echo "show collections" | mongo myDbName
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();
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())"
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
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.
mongo <<EOF
use <db_name>
db.getCollection("<collection_name>").find({})
EOF
--shell flag can also be used for javascript files
mongo --shell /path/to/jsfile/test.js
mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"
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');
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>
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.
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
The legacy mongo shell has been removed from MongoDB with the version 6 release in 2022
There is a new way to execute shell scripts using the new shell, mongosh
From the shell documentation on writing scripts:
You can use mongosh to execute a script from the command line without entering the mongosh console
To specify the filename, use the --file or -f parameter to specify the filename
You may also need to specify connection information